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

 
 
> 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
 
Start new topic
Ответов
AHTOXA
сообщение Feb 7 2011, 06:06
Сообщение #2


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

Группа: Свой
Сообщений: 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
Сообщение #3


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

Группа: Участник
Сообщений: 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
Сообщение #4


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

Группа: Свой
Сообщений: 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
Сообщение #5


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

Группа: Участник
Сообщений: 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   STM32F10x   Feb 6 2011, 20:02
- - akimych   Интересно то, что после while(TIM3->SR & TI...   Feb 6 2011, 21:29
- - pr0m   Победил. Не была задана группировка с вытеснением ...   Feb 7 2011, 14:18
|- - sonycman   Цитата(pr0m @ Feb 7 2011, 17:18) Задал пр...   Feb 7 2011, 15:21
|- - pr0m   Цитата(sonycman @ Feb 7 2011, 18:21) Так ...   Feb 7 2011, 15:39
|- - sonycman   Цитата(pr0m @ Feb 7 2011, 18:39) Высший-т...   Feb 7 2011, 16:04
|- - AHTOXA   Цитата(sonycman @ Feb 7 2011, 21:04) По у...   Feb 7 2011, 16:17
|- - sonycman   Цитата(AHTOXA @ Feb 7 2011, 19:17) Ненене...   Feb 7 2011, 16:25
|- - pr0m   Цитата(sonycman @ Feb 7 2011, 19:25) Так ...   Feb 7 2011, 16:57
||- - sonycman   Цитата(pr0m @ Feb 7 2011, 19:57) Нет, одн...   Feb 7 2011, 17:11
|||- - pr0m   Цитата(sonycman @ Feb 7 2011, 20:11) Хм, ...   Feb 7 2011, 17:17
||- - AHTOXA   Цитата(pr0m @ Feb 7 2011, 21:57) Нет, одн...   Feb 7 2011, 17:15
||- - sonycman   Цитата(AHTOXA @ Feb 7 2011, 20:15) Всё же...   Feb 7 2011, 17:22
||- - pr0m   Цитата(AHTOXA @ Feb 7 2011, 20:15) Всё же...   Feb 7 2011, 17:31
||- - AHTOXA   Цитата(pr0m @ Feb 7 2011, 22:22) А моя пр...   Feb 7 2011, 17:32
||- - KnightIgor   Цитата(pr0m @ Feb 7 2011, 18:31) А моя пр...   Feb 7 2011, 17:58
||- - pr0m   Цитата(KnightIgor @ Feb 7 2011, 20:58) По...   Feb 7 2011, 18:05
|- - AHTOXA   Цитата(sonycman @ Feb 7 2011, 21:04) По у...   Feb 7 2011, 17:06
- - pr0m   Разобрался. sonycman прав. 15 подгрупп после ресет...   Feb 7 2011, 17:53
|- - sonycman   Цитата(pr0m @ Feb 7 2011, 20:53) И что ж ...   Feb 7 2011, 18:05
|- - pr0m   Цитата(sonycman @ Feb 7 2011, 21:05) В эт...   Feb 7 2011, 18:11
- - akimych   Цитата1) Для детерминированности времени исполнени...   Feb 7 2011, 19:06
|- - pr0m   Цитата(akimych @ Feb 7 2011, 22:06) Стран...   Feb 7 2011, 19:31
- - akimych   ЦитатаВ этой ветке переплелись мои вопросы по двум...   Feb 7 2011, 21:24
|- - pr0m   Цитата(akimych @ Feb 8 2011, 00:24) На сч...   Feb 8 2011, 07:03
|- - ReAl   Цитата(pr0m @ Feb 8 2011, 09:03) Там долж...   Feb 8 2011, 23:27
- - akimych   ЦитатаВы наверное имеете ввиду доступ к bit-bandin...   Feb 8 2011, 22:00
|- - pr0m   Цитата(akimych @ Feb 9 2011, 01:00) А что...   Feb 9 2011, 16:48
|- - ReAl   Цитата(pr0m @ Feb 9 2011, 18:48) Не знаю....   Feb 9 2011, 21:08
|- - pr0m   Цитата(ReAl @ Feb 10 2011, 00:08) Значени...   Feb 10 2011, 06:06
|- - vmp   Цитата(pr0m @ Feb 10 2011, 09:06) Спасибо...   Feb 10 2011, 07:39
||- - pr0m   Цитата(vmp @ Feb 10 2011, 10:39) Преимуще...   Feb 10 2011, 12:19
|- - ReAl   Цитата(pr0m @ Feb 10 2011, 08:06) Спасибо...   Feb 10 2011, 14:07
|- - pr0m   Цитата(ReAl @ Feb 10 2011, 17:07) Проблем...   Feb 10 2011, 21:48
- - pr0m   Красиво, получается, но основной недостаток - чуть...   Feb 11 2011, 14:31
- - akimych   В принципе, запись в буфер и запись в регистр ЦАП-...   Feb 13 2011, 02:17
- - pr0m   Цитата(akimych @ Feb 13 2011, 05:17) Изме...   Feb 13 2011, 07:03


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

 


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


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