Проблема с прерываниями в avr-gcc

Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
Закрыто
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Пт мар 18, 2011 12:41:09

Сообщение ksv82 »

Есть проэктик на atmega32, где есть динамическая индикация - в главном цикле, и связь через rs-485. Все бы ничего, но для индикации используются два пина на порте D: pd3 и pd4. Для rs-485 требуется переключать направление передачи, что у меня делается через PD7. И вот тут появляются проблемы - команды в цикле динамической индикации

Код: Выделить всё

if((tmp_red & 1)==1)
PORTD |= (1<<PD3);
if((tmp_green & 1)==1)
PORTD |= (1<<PD4);
--задержка 20мс--
PORTD &= ~((1<<PD3) | (1<<PD4));
каким то образом устанавливают в 1 PD7. Если перед выполнением этих команд запретить прерывания, то все работает нормально. Что с этим можно сделать?
Реклама
Поставщик валерьянки для Кота
Сообщения: 1995
Зарегистрирован: Ср май 11, 2011 21:37:45
Откуда: Цветочный город

Сообщение Мастер Ломастер »

ksv82 писал(а):динамическая индикация - в главном цикле
если я верно понял, то это ужас какой-то...
ksv82 писал(а):Если перед выполнением этих команд запретить прерывания, то все работает нормально.
очевидно, что проблема не в этом куске кода, а в прерываниях: явно где-то в прерываниях происходит запись в PORTD.

имхо, лучшим решением ваших проблем будет тщательное "причесывание" проекта, возможно, кардинальная переделка.
битва с дураками проиграна, победители торжествуют. слава победителям!
Контактная информация:
Реклама
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Пт мар 18, 2011 12:41:09

Сообщение ksv82 »

Нет, проблема не в прерывании, тут все хитрее оказалось. Даже не ждал что удастся найти ответ так быстро.

При компиляции с ключем -O0 ассемблерный листинг выглядит вот так:

Код: Выделить всё

         PORTD &= ~(1<<PD5)
  9c:	82 e3       	ldi	r24, 0x32	; 50
  9e:	90 e0       	ldi	r25, 0x00	; 0
  a0:	22 e3       	ldi	r18, 0x32	; 50
  a2:	30 e0       	ldi	r19, 0x00	; 0
  a4:	f9 01       	movw	r30, r18
  a6:	20 81       	ld	r18, Z
  a8:	2f 7d       	andi	r18, 0xDF	; 223
  aa:	fc 01       	movw	r30, r24
  ac:	20 83       	st	Z, r18
Тут даже команд out или cbi я не наблюдаю... и как оно работает?

Если пересобрать тот же код с ключем -Os, то все становиться гораздо интререснее:

Код: Выделить всё

           PORTD &= ~(1<<PD5)
  94:	95 98       	cbi	0x12, 5	; 18
Ну и работает соответственно без проблем.
Поставщик валерьянки для Кота
Сообщения: 1995
Зарегистрирован: Ср май 11, 2011 21:37:45
Откуда: Цветочный город

Сообщение Мастер Ломастер »

я продолжаю настаивать на своем.

и с оптимизацией, и без компилятор генерирует 100% правильно работающий код, то, что вы его не понимаете, еще ни о чем не говорит. разумеется, неоптимизированный выполняется дольше, т.к. команд много, и при этом МЕЖДУ НИМИ могут возникать прерывания, которые ПОРТЯТ состояние порта ДО ТОГО, как этот многокомандный код закончит свои дела. включив оптимизацию, вы свели все к одной команде - это лишь частный случай вашего решения, проблема-то осталась: есть какое-то прерывание, которое тоже работает с портом. рано или поздно все повторится...
битва с дураками проиграна, победители торжествуют. слава победителям!
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 2029
Зарегистрирован: Сб ноя 15, 2008 10:09:56
Откуда: г. Тула

Сообщение IfoR »

ksv82 писал(а): Тут даже команд out или cbi я не наблюдаю... и как оно работает?
Зато я вижу ld и st. :)
Изображение
/dev/urandom - гигабайты информации.

OS: openSUSE 13.2 (x86_64)
Контактная информация:
Реклама
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Пт мар 18, 2011 12:41:09

Сообщение ksv82 »

Тут ситуация маленько другая - с портом прерывание действительно работает, но в прерывании и в цыкле вывода индикации я меняю РАЗНЫЕ биты.

А с кодом компилятора я все таки разобрался:

Код: Выделить всё

  9c:   82 e3          ldi   r24, 0x32   ; 50 
  9e:   90 e0          ldi   r25, 0x00   ; 0
  a0:   22 e3          ldi   r18, 0x32   ; 50 0x32 - адрес в памяти на который отражается порт D
  a2:   30 e0          ldi   r19, 0x00   ; 0
  a4:   f9 01          movw   r30, r18 Загружаем в младшую половину регистра Z смещение на адрес порта в памяти
  a6:   20 81          ld   r18, Z         Загружаем из порта D его значение
  a8:   2f 7d          andi   r18, 0xDF   ; 223   Изменяем нужный бит...
  aa:   fc 01          movw   r30, r24 А вот тут как раз подходящее время для появления прерывания:))  
                                                  Оно как раз с этим портом тоже работает.
  ac:   20 83          st   Z, r18 Пишем значение порта с измененным битом обратно ...  ну и иногда затираем то                что сделало прерывание:)
Реклама
Закрыто

Вернуться в «Микроконтроллеры и ПЛИС»