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

 
 
 
Reply to this topicStart new topic
> Проблема снятия флага, Различные проявления при варьировании уровнем оптимизации
proga
сообщение Mar 21 2013, 11:32
Сообщение #1


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

Группа: Участник
Сообщений: 86
Регистрация: 17-01-06
Из: иркутск
Пользователь №: 13 278



Здравствуйте. Я разрабатываю программу на базе микроконтроллера STM32F417. У меня возникла проблема следующего характера. В одной части своей программы мне необходимо запретить DMA исполнение. Делаю я это стандартным способом

Код
    
        DMA_Cmd(DMA1_Stream5, DISABLE);
    while(DMA1_Stream5->CR & DMA_SxCR_EN);

Однако программа в цикле застревает навечно. Если же я в отладчике пошагово исполняю этот кусок кода, то без проблем прохожу цикл.
Если же я изменяю уровень оптимизации с O3 на O1, то программа начивает застревать раньше в подобном же блоке
Код
    DMA_Cmd(DMA2_Stream0, DISABLE);
    while(DMA2_Stream0->CR & DMA_SxCR_EN);

, который раннее при оптимизации O3 программа проходила без проблем. Прошу помощи в разрешении данной проблемы.
Go to the top of the page
 
+Quote Post
1113
сообщение Mar 21 2013, 11:50
Сообщение #2


Знающий
****

Группа: Свой
Сообщений: 604
Регистрация: 24-02-06
Из: Москва
Пользователь №: 14 658



Периферийные регистры
Встраиваемые системы содержат оборудование со сложной периферией. В составе периферии есть регистры, чьи значения могут изменяться асинхронно алгоритму программы. В качестве простого примера рассмотрим 8-битный регистр состояния, отображаемый в памяти по адресу 0х1234. Допустим, нам нужно опрашивать регистр состояния до тех пор, пока он не станет ненулевым. Простая и неправильная реализация может быть такой:

uint8_t * pReg = (uint8_t *) 0x1234;

// Wait for register to become non-zero
while (*pReg == 0) { } // Do something else
В этом случае, почти наверняка будет сбой, как только вы включите оптимизацию. Компилятор сгенерирует ассемблерный код подобный этому:

mov ptr, #0x1234
mov a, @ptr
loop:
bz loop
Логическое обоснование оптимизатора довольно простое: уже считав значение переменной в аккумулятор (вторую строка кода), нет необходимости считывать его заново, поскольку значение всегда будет тем же. Таким образом, в третьей строке мы окажемся в бесконечном цикле. Чтобы заставить компилятор сделать то, что нам нужно, мы изменим описание на:

uint8_t volatile * pReg = (uint8_t volatile *) 0x1234;

Ассемблерный код теперь выглядит следующим образом:

mov ptr, #0x1234
loop:
mov a, @ptr
bz loop

Требуемый ход процесса достигнут.
Неуловимые проблемы могут возникать в регистрах, имеющих специфические характеристики. Например, множество периферийных устройств содержат регистры, которые очищаются при простом их прочтении. Несколько дополнительных прочтений сверх ваших намерений (или же наоборот, меньше, чем вы планировали) могут привести в этих случаях к неожиданным результатам.

Применительно к программированию микроконтроллеров AVR, нет никакой необходимости в использовании указателей на периферийные регистры, потому что код в этом случае получается весьма громоздким. Pashgan.
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Mar 21 2013, 12:08
Сообщение #3


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(1113 @ Mar 21 2013, 15:50) *
Я заранее почти на 100% уверен, что DMA2_Stream0->CR имеет квалификатор volatile. Так что проблема не тут.

2ТС: Пальцем в небо: что нибудь изменится если написать так ?
Код
    DMA_Cmd(DMA1_Stream5, DISABLE);
    __DSB();
    while (DMA1_Stream5->CR & DMA_SxCR_EN);


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Mar 21 2013, 12:28
Сообщение #4


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(proga @ Mar 21 2013, 12:32) *

Код
    
        DMA_Cmd(DMA1_Stream5, DISABLE);
    while(DMA1_Stream5->CR & DMA_SxCR_EN);

1. Вопрос: зачем ждать сброса флага? Неужели есть опасение, что DISABLE не сработает?!
2. Идея: смотрится как излишество в контексте С, но мне помогало:

while((DMA1_Stream5->CR & DMA_SxCR_EN) !=0);

3. Облом лезть в доку за битами, но может стОит проверять не CR, а SR?

Сообщение отредактировал KnightIgor - Mar 21 2013, 12:51
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Mar 21 2013, 13:07
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



не излишество, а определенность, и помогли вам другие скобки.
while((DMA1_Stream5->CR & DMA_SxCR_EN) !=0);
равносильно
while((DMA1_Stream5->CR & DMA_SxCR_EN));
но не равносильно
while(DMA1_Stream5->CR & DMA_SxCR_EN);
в кейле несколько раз на это нарывался, не совсем корректная работа компилятора, иногда можно объяснить приоритетом действий иногда нет, но за правило для себя принял запись
while((DMA1_Stream5->CR & DMA_SxCR_EN) !=0);
так нагляднее и надежнее работает!
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Mar 21 2013, 14:41
Сообщение #6


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Да ну!
Это же конкретная бага в компиляторе!
Какая версия компилятора так себя ведёт, кстати?


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
proga
сообщение Mar 22 2013, 07:01
Сообщение #7


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

Группа: Участник
Сообщений: 86
Регистрация: 17-01-06
Из: иркутск
Пользователь №: 13 278



Спасибо всем за советы. К сожалению они не помогли. Я просмотрел код через дизасемблер. Копилятор отработал нормально. Дело не в том, что некорректна проверка флага, а в том, что флаг изначально не сбрасывается, либо сбрасывается и тут же устанавливается логикой. Как я уже писал, при пошаговом прохождении этой части кода программа исполняется нормально. А вот при выполнении программы налету она застревает в этом цикле. Возникает ощущение, что логика всё же возвращает флаг на место, просто в пошаговом режиме почему-то не может этого сделать. Скорее всего я, что то делаю не так, хоть и ума не приложу в чём я ошибаюсь. Ну что ж, буду думать.

Сообщение отредактировал proga - Mar 22 2013, 09:07
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Mar 22 2013, 11:22
Сообщение #8


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(proga @ Mar 22 2013, 08:01) *
Спасибо всем за советы. К сожалению они не помогли.

Поскольку чудес не бывает, то если подумать над симптомом - под отладчиком все работает, а "на лету" нет (бит всплывает из небытия), - приходит мысль, что бит взводится в каком-то прерывании: под отладчиком с правильным адаптером прерывание при пошаговом проходе не вызывается, а "на лету" скорее - да. Ищите ошибку в логике своего кода.

P.S. Вдогонку еще мысль: гдет-то на задворках моей памяти всплывает воспоминание, что, якобы, если выключить DMA во время передачи, то могут быть странные глюки с битами. Рекомендую перед DISABLE сделать еще STOP.

Сообщение отредактировал KnightIgor - Mar 22 2013, 11:28
Go to the top of the page
 
+Quote Post

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

 


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


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