реклама на сайте
подробности

 
 
3 страниц V   1 2 3 >  
Reply to this topicStart new topic
> STM32F10x, не перестаёт удивлять
pr0m
сообщение Feb 6 2011, 20:02
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 183
Регистрация: 22-06-05
Из: Таганрог
Пользователь №: 6 233



Полдня чесал репу и разлохматил бубен на казалоь бы ровном месте... А именно: имеем некий код в основном цикле, с временем исполнения, определяемым периодом таймера. Таймер запускается перед контролируемым кодом, тот в цикле делает свои дела, а выходит по флагу, к-й устанавливается в обработчике прерывания (Update Event) этого таймера. Таймер запускается перед этим блоком. По так и невыясненным причинам, всё работало после ресета до того момента, пока не происходило некое внешнее прерывание (с приоритетом ниже таймера), делающее быстро другие примитивные дела, не относящиеся к интересующему участку кода. После этого начинались чудеса - на очередном внешнем цикле после запуска таймера код лихо проскакивал проверку while(!bStopDSS), даже не заглянув внутрь, и происходило 2! прерывания от таймера, одно из которых видимо и устанавливало bStopDSS=1 до входа во внутренний цикл. Вылечил проверкой флага прерывания перед включением таймера. Перекорячивается конвейер команд? При включении таймера (строка TIM3->CR1 |= TIM_CR1_CEN) ещё не сброшен бит прерывания?
Код
volatile uint8_t bStopDSS;
while(1) // внешний цикл
{
bStopDSS = 0;
TIM3->CNT = 0;
TIM3->SR = ~TIM_IT_Update;
while(TIM3->SR & TIM_IT_Update); // без этой проверки - чудеса
TIM3->CR1 |= TIM_CR1_CEN;

while(bStopDSS == 0)
{
// Внутренний цикл, выходим по таймеру.    
}
//
...готовимся к следующему циклу
//
}

void TIM3_IRQHandler (void)
{
    // Сбрасываем флаг прерывания
    TIM3->SR = ~TIM_IT_Update;
    // Останавливаем таймер
       TIM3->CR1 &= ~TIM_CR1_CEN;
    // Флаг окончания внутреннего цикла
    bStopDSS = 1;
}


Такие дела. В голове смятение.

Сообщение отредактировал pr0m - Feb 6 2011, 20:05


--------------------
Правильно поставленный вопрос - половина ответа...
Go to the top of the page
 
+Quote Post
akimych
сообщение Feb 6 2011, 21:29
Сообщение #2


Участник
*

Группа: Участник
Сообщений: 72
Регистрация: 7-01-11
Пользователь №: 62 073



Интересно то, что после while(TIM3->SR & TIM_IT_Update); bStopDSS все равно не обнуляется и TIM_IT_Update тоже не сбрасывается.
А таймер как сконфигурирован?

В данном случае наверно имело бы смысл использовать One-pulse mode. Если по прерыванию только выставляется флаг bStopDSS, то можно будет вообще без него обойтись.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Feb 7 2011, 06:06
Сообщение #3


фанат дивана
******

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



Цитата(pr0m @ Feb 7 2011, 01:02) *
Такие дела. В голове смятение.

Попробуйте проверять источник прерывания перед сбросом:
Код
void TIM2_IRQHandler(void)
{
    if (TIM2->SR & TIM_SR_UIF)
    {
        TIM2->SR = ~TIM_SR_UIF;
        ...
    }
}


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
pr0m
сообщение Feb 7 2011, 08:42
Сообщение #4


Частый гость
**

Группа: Участник
Сообщений: 183
Регистрация: 22-06-05
Из: Таганрог
Пользователь №: 6 233



Цитата(AHTOXA @ Feb 7 2011, 09:06) *
Попробуйте проверять источник прерывания перед сбросом:
Код
void TIM2_IRQHandler(void)
{
    if (TIM2->SR & TIM_SR_UIF)
    {
        TIM2->SR = ~TIM_SR_UIF;
        ...
    }
}

Флаг UEV установлен в обоих случаях, смотрел в железе. А как может быть иначе, если прерывание только по нему сконфигурено, поэтому даже не проверяю. Даташиты и примеры молчат по этому поводу.


Цитата(akimych @ Feb 7 2011, 00:29) *
Интересно то, что после while(TIM3->SR & TIM_IT_Update); bStopDSS все равно не обнуляется и TIM_IT_Update тоже не сбрасывается.

В смысле, Вы это сами проверяли? Если так, то значит мне это не приглючилось.. Именно так и происходило.
Цитата(akimych @ Feb 7 2011, 00:29) *
А таймер как сконфигурирован?

Просто Upcounting (инициализирую прескалер, ARR, обнуляю CNT, разрешаю прерывания по UEV и вперёд).

Цитата(akimych @ Feb 7 2011, 00:29) *
В данном случае наверно имело бы смысл использовать One-pulse mode. Если по прерыванию только выставляется флаг bStopDSS, то можно будет вообще без него обойтись.

Да, вчера название режима привлекло, но ещё не пробовал. Попробую.
По поводу использования bStopDSS отдельная песня - внутренний блок очень критичен по времени (чем быстрее, тем лучше), причём это время должно быть детерминировано. После выяснений-экспериментов сделал следующие выводы:
1) Для детерминированности времени исполнения код должен исполняться из ОЗУ, что и сделал. Хотя исполняется медленнее, чем из флэш - что подтверждает высказывания по поводу отсутствия преимуществ исполнения кода из ОЗУ в сравнении с флэш для STM32F10...
2) Проверка флага UEV как признака окончания внутреннего цикла (while(!(TIMx->CR1 & UEV))увеличивает общее время исполнения блока на 2 такта, в сравнении c флагом в ОЗУ (bStopDSS), что в принципе понятно - чтение регистра+наложение маски бита UEV-сравнение, вместо чтение-сравнение). Поэтому bStopDSS.

Сообщение отредактировал pr0m - Feb 7 2011, 08:44


--------------------
Правильно поставленный вопрос - половина ответа...
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Feb 7 2011, 09:16
Сообщение #5


фанат дивана
******

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



Цитата(pr0m @ Feb 7 2011, 13:42) *
Флаг UEV установлен в обоих случаях, смотрел в железе. А как может быть иначе, если прерывание только по нему сконфигурено, поэтому даже не проверяю.

Однако же может :-)


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
pr0m
сообщение Feb 7 2011, 12:20
Сообщение #6


Частый гость
**

Группа: Участник
Сообщений: 183
Регистрация: 22-06-05
Из: Таганрог
Пользователь №: 6 233



Цитата(AHTOXA @ Feb 7 2011, 12:16) *
Однако же может :-)

Мдя, спасибо за ссылку. Понял, как нужно, но не понял, зачем. Многовато туману. Где ещё ожидают грабли? А то у меня ещё один необъяснимый и сильно напрягающий случай имеется - тоже таймер, тоже прерывание (с частотой 100кГц), в котором данные с группы из 6 каналов АЦП (АЦП в непрерывном режиме, с использованием ДМА в CircularMode, собирает данные в фиксированное место 6*2 байт) аккуратненько складывает эти 6 отсчётов в большой накопительный буфер, с инкрементом указателя ессно. Если перевести в требуемую скорость по каналу передачи 100кГц*6каналов*16бит = 9600кБит/c. Как только заполнен буфер, нужно его отправлять. Отправляю по Ethernet-у при помощи lwIP udp_send(). Пробовал 2 варианта:
1) В основном цикле программы (от чего очень хотелось бы избавиться, т.к. там коду есть чем другим заняться). Помечаем буфер как готовый для отправки, в основном цикле флажок готовности проверяется, буфер через lwIP udp_send() отправляется. Скорость наблюдаю на приёмном конце - на компе - соответсвует расчётной.
п.с. Процесс отправки чуть сложнее описанного, но сути не меняет - используются очереди, процедуры push в обработчике и "пока pop != 0" в основном цикле.
2) Поручаем отправку программному прерыванию:
Код
void SamplesMain(void) // Вариант1 - процедура отправки в основном цикле
{
#ifndef INT_TXR
    QUEUE_ELEMENT* pbuf;
    while( (pbuf = QueuePopSafe(&readyBufsQueue)) != NULL )
    {
        p->payload = pbuf->pSamples;
        udp_send(upcb, p);
        QueuePushSafe(&freeBufsQueue,pbuf);
    }
#endif        
}

void TIM2_IRQHandler (void)
{
    TIM2->SR = ~TIM_IT_Update;

    *(((u32*)pNextSamplesSet)+0) = *(((u32*)&samples_acc)+0);
    *(((u32*)pNextSamplesSet)+1) = *(((u32*)&samples_acc)+1);
    *(((u32*)pNextSamplesSet)+2) = *(((u32*)&samples_acc)+2);
    if(++pNextSamplesSet == (pSamplesAccumulator->pSamples + SAMPLES_SETS_PER_BUF))
       {
        QueuePushUnsafe(&readyBufsQueue,pSamplesAccumulator);
#ifdef INT_TXR
        EXTI->SWIER |= 0x0001;
#endif
        pSamplesAccumulator = QueuePopUnsafe(&freeBufsQueue);
        if( pSamplesAccumulator == NULL )
        {
            while(1);// Отладка. Сюда вваливаемся навсегда, если буферы уходят медленнее, чем заполняются.
        }
        pNextSamplesSet = pSamplesAccumulator->pSamples;    
       }
}

void EXTI0_IRQHandler(void)// Вариант2 - процедура отправки в программном прерывании
{
    QUEUE_ELEMENT* pbuf;
    EXTI->PR = EXTI_Line0;

    while( (pbuf = QueuePopSafe(&readyBufsQueue)) != NULL )
    {
        p->payload = pbuf->pSamples;
        udp_send(upcb, p);
        QueuePushSafe(&freeBufsQueue,pbuf);
    }
    time_elapsed = LocalTime - time; //отладка
    ++bufs;//отладка
//    bufs_per_ms = bufs/LocalTime;
//    kBs = bufs_per_ms * 1200UL * 1000UL;
}


Так вот при отправке через программное прерывание скорость передачи падает! примерно до 9200кБит. Как такое может быть? Ведь скорость однозначно определяется периодом работы таймера. При этом переполнения/опустошения очередей буферов не происходит. Ощущение, что замедляется бег таймера, как ни идиотски это звучит. Если закомментировать строчку udp_send(upcb, p);, всё приходит в норму (ориентируюсь по кол-ву отправленных буферов bufs за период времени time_elapsed). Ещё не до конца расковырял udp_send, но в конечном итоге она через memcpy копирует данные в буфер для Ethernet-а и отмечает к отправке. Чем может отличаться исполнение кода в конексте прерывания от кода в контексте главного цикла, что может приводить к такому эфф(де)фекту?

Сообщение отредактировал pr0m - Feb 7 2011, 12:24


--------------------
Правильно поставленный вопрос - половина ответа...
Go to the top of the page
 
+Quote Post
pr0m
сообщение Feb 7 2011, 14:18
Сообщение #7


Частый гость
**

Группа: Участник
Сообщений: 183
Регистрация: 22-06-05
Из: Таганрог
Пользователь №: 6 233



Победил. Не была задана группировка с вытеснением в NVIC, т.е. 0 preemption групп, 16 приоритетов. Задал приоритет 0 для таймера (типа выше всех остальных в системе), и думал ни одна собака его не прервёт, зато он у всех будет проц вырывать, как приспичит, и гарантированно не пропустит ни одного сэмпла. Ан нет - почитал про preemption, прозрел, разделил на группы, таймер определил в гордом одиночестве в 0-ю группу, 0-й приоритет - и теперь всё в норме.
Что взять с начинающего?


--------------------
Правильно поставленный вопрос - половина ответа...
Go to the top of the page
 
+Quote Post
sonycman
сообщение Feb 7 2011, 15:21
Сообщение #8


Любитель
*****

Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695



Цитата(pr0m @ Feb 7 2011, 17:18) *
Задал приоритет 0 для таймера (типа выше всех остальных в системе), и думал ни одна собака его не прервёт, зато он у всех будет проц вырывать, как приспичит, и гарантированно не пропустит ни одного сэмпла.

Так и есть. Без групп, нулевой приоритет - высший.
Разве нет?
Go to the top of the page
 
+Quote Post
pr0m
сообщение Feb 7 2011, 15:39
Сообщение #9


Частый гость
**

Группа: Участник
Сообщений: 183
Регистрация: 22-06-05
Из: Таганрог
Пользователь №: 6 233



Цитата(sonycman @ Feb 7 2011, 18:21) *
Так и есть. Без групп, нулевой приоритет - высший.
Разве нет?

Высший-то высший, но тут речь о возможности вытеснения текущего прерывания, и предаче управления другому. Например, если сейчас исполняется прерывание 0-й группы и, скажем, приоритет 2, то пришедший запрос на прерывание из той-же 0-й группы с более высоким приоритетом=1 НЕ прервёт исполнение текущего обработчика, т.к. они оба относятся к одной (0-й) группе, а станет в очередь (pending). А вот если мы разделим приоритеты по группам, подгруппам, обработчик прерывания 1-й группы, любой приоритет будет вытеснен запросом на прерывание из 0-й группы, любой приоритет. Такая вот иерархия. Описание NVIC контроллера и регистра SCB_AIRCR к прочтению.
В одной группе приоритетом определяется только очерёдность передачи управления тому или иному вектора, а если они ещё и с одинаковым приоритетом, то аппаратным порядковым номером вектора.

Сообщение отредактировал pr0m - Feb 7 2011, 15:43


--------------------
Правильно поставленный вопрос - половина ответа...
Go to the top of the page
 
+Quote Post
sonycman
сообщение Feb 7 2011, 16:04
Сообщение #10


Любитель
*****

Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695



Цитата(pr0m @ Feb 7 2011, 18:39) *
Высший-то высший, но тут речь о возможности вытеснения текущего прерывания, и предаче управления другому.

По умолчанию, после аппаратного сброса, NVIC в STM32 работает в режиме одной единственной группы, без подгрупп.
То есть любому прерыванию можно присвоить лишь простой приоритет 0, 1, 2 и т.д.

Ноль будет высшим и будет прерывать выполнение любого другого прерывания (кроме системных).
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Feb 7 2011, 16:17
Сообщение #11


фанат дивана
******

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



Цитата(sonycman @ Feb 7 2011, 21:04) *
По умолчанию, после аппаратного сброса, NVIC в STM32 работает в режиме одной единственной группы, без подгрупп.
То есть любому прерыванию можно присвоить лишь простой приоритет 0, 1, 2 и т.д.

Ноль будет высшим и будет прерывать выполнение любого другого прерывания (кроме системных).

Ненене! Внутри одной группы прерывания друг друга не вытесняют:-)


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
sonycman
сообщение Feb 7 2011, 16:25
Сообщение #12


Любитель
*****

Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695



Цитата(AHTOXA @ Feb 7 2011, 19:17) *
Ненене! Внутри одной группы прерывания друг друга не вытесняют:-)

Так ведь группы-то разные!
Приоритет 0 - нулевая группа.
Приоритет 1 - первая группа и т.д.

Это если PRIGROUP = 0.

Или нет?
Go to the top of the page
 
+Quote Post
pr0m
сообщение Feb 7 2011, 16:57
Сообщение #13


Частый гость
**

Группа: Участник
Сообщений: 183
Регистрация: 22-06-05
Из: Таганрог
Пользователь №: 6 233



Цитата(sonycman @ Feb 7 2011, 19:25) *
Так ведь группы-то разные!
Приоритет 0 - нулевая группа.
Приоритет 1 - первая группа и т.д.

Это если PRIGROUP = 0.

Или нет?


Нет, одна группа - 0-я, и в ней 15 ПОДприоритетов, к-е друг друга не вытесняют.
Прикрепленное изображение

Кстати, не совсем понял один момент: после сброса поле групп = 000, если верить описанию регистра SCB_AIRCR:
Прикрепленное изображение

Такого сочетания этих конфигурационных бит нет. И какая схема приоритетов имеет место после ресета?


--------------------
Правильно поставленный вопрос - половина ответа...
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Feb 7 2011, 17:06
Сообщение #14


фанат дивана
******

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



Цитата(sonycman @ Feb 7 2011, 21:04) *
По умолчанию, после аппаратного сброса, NVIC в STM32 работает в режиме одной единственной группы, без подгрупп.

Цитата(sonycman @ Feb 7 2011, 21:25) *
Так ведь группы-то разные!

Так одна-единственная, или разная для каждого приоритета? sm.gif
Я так понимаю, что при старте (PRIGROUP == 0) получается, что все биты приоритета определяют Preempt Priority (если нет нулевого бита у Priority Level). То есть, разные приоритеты находятся в разных группах, и могут вытеснять друг друга.
Но ведь они по умолчанию одинаковые, приоритеты-то?


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
sonycman
сообщение Feb 7 2011, 17:11
Сообщение #15


Любитель
*****

Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695



Цитата(pr0m @ Feb 7 2011, 19:57) *
Нет, одна группа - 0-я, и в ней 15 ПОДприоритетов, к-е друг друга не вытесняют.

Хм, я тогда приведу другую картинку:
Прикрепленное изображение

В случае с STM32 используются только 4 бита регистра, поэтому отбрасываем 4 младших бита.

Что получается?
Читаем верхнюю строчку: кол-во вытесняющих приоритетов - 128 (в нашем случае - 16), кол-во подприоритетов - 2 (у нас - 1).

Когда происходит вытеснение? Когда вытесняющий приоритет больше.

1. Записываем в регистр 0: вытесняющий приоритет = 0, максимальный, подприоритет = 0.
2. Записываем в регистр 1: вытесняющий приоритет = 1, следующий за максимальным, подприоритет = 0.

Неужели не правильно рассуждаю?
Go to the top of the page
 
+Quote Post

3 страниц V   1 2 3 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 15:29
Рейтинг@Mail.ru


Страница сгенерированна за 0.0147 секунд с 7
ELECTRONIX ©2004-2016