proga 0 21 марта, 2013 Опубликовано 21 марта, 2013 · Жалоба Здравствуйте. Я разрабатываю программу на базе микроконтроллера 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 программа проходила без проблем. Прошу помощи в разрешении данной проблемы. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
1113 5 21 марта, 2013 Опубликовано 21 марта, 2013 · Жалоба Периферийные регистры Встраиваемые системы содержат оборудование со сложной периферией. В составе периферии есть регистры, чьи значения могут изменяться асинхронно алгоритму программы. В качестве простого примера рассмотрим 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. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 21 марта, 2013 Опубликовано 21 марта, 2013 · Жалоба Я заранее почти на 100% уверен, что DMA2_Stream0->CR имеет квалификатор volatile. Так что проблема не тут. 2ТС: Пальцем в небо: что нибудь изменится если написать так ? DMA_Cmd(DMA1_Stream5, DISABLE); __DSB(); while (DMA1_Stream5->CR & DMA_SxCR_EN); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KnightIgor 2 21 марта, 2013 Опубликовано 21 марта, 2013 (изменено) · Жалоба 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? Изменено 21 марта, 2013 пользователем KnightIgor Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Golikov 0 21 марта, 2013 Опубликовано 21 марта, 2013 · Жалоба не излишество, а определенность, и помогли вам другие скобки. 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); так нагляднее и надежнее работает! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 21 марта, 2013 Опубликовано 21 марта, 2013 · Жалоба Да ну! Это же конкретная бага в компиляторе! Какая версия компилятора так себя ведёт, кстати? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
proga 0 22 марта, 2013 Опубликовано 22 марта, 2013 (изменено) · Жалоба Спасибо всем за советы. К сожалению они не помогли. Я просмотрел код через дизасемблер. Копилятор отработал нормально. Дело не в том, что некорректна проверка флага, а в том, что флаг изначально не сбрасывается, либо сбрасывается и тут же устанавливается логикой. Как я уже писал, при пошаговом прохождении этой части кода программа исполняется нормально. А вот при выполнении программы налету она застревает в этом цикле. Возникает ощущение, что логика всё же возвращает флаг на место, просто в пошаговом режиме почему-то не может этого сделать. Скорее всего я, что то делаю не так, хоть и ума не приложу в чём я ошибаюсь. Ну что ж, буду думать. Изменено 22 марта, 2013 пользователем proga Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KnightIgor 2 22 марта, 2013 Опубликовано 22 марта, 2013 (изменено) · Жалоба Спасибо всем за советы. К сожалению они не помогли. Поскольку чудес не бывает, то если подумать над симптомом - под отладчиком все работает, а "на лету" нет (бит всплывает из небытия), - приходит мысль, что бит взводится в каком-то прерывании: под отладчиком с правильным адаптером прерывание при пошаговом проходе не вызывается, а "на лету" скорее - да. Ищите ошибку в логике своего кода. P.S. Вдогонку еще мысль: гдет-то на задворках моей памяти всплывает воспоминание, что, якобы, если выключить DMA во время передачи, то могут быть странные глюки с битами. Рекомендую перед DISABLE сделать еще STOP. Изменено 22 марта, 2013 пользователем KnightIgor Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться