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

 
 
> AVR Надежная работа UART и прерывания прочей переферии, Код UART из DS (реализован без прерываний) и все равно проблемы
Didro
сообщение Mar 10 2010, 12:30
Сообщение #1


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

Группа: Участник
Сообщений: 94
Регистрация: 9-04-07
Пользователь №: 26 893



Добрый день,

столкнулся с такой непонятной для меня ситуацией.
Есть ATMega32, которая реализует: ШИМ (1 таймер), импульсы переменной длительности (1 таймер), замеры напряжения с двух каналов АЦП и общение с ПК. Общение с ПК по UART. Протокол общения строго синхронный. Запрос с ПК - ответ с МК.

Взял код UART из спецификации на mega32.

Если контроллер не загружен - буквально, если выключить АЦП (предделитель 64), а всю остальную переферию оставить (2 таймера), то UART работает нормально - проходит тестирование в 60 тыс. обменов с ПК.

Только стоит подключить АЦП начинаются проблемы - ПК фиксирует, что контроллер не отвечает ему за отведенное время.
При этом если код функций работы UART заключить в скобки cli-sei, то даже при включенном АЦП, обмен идет хорошо. Если запрещение прерываний убрать, начинаются проблемы.

Код UART навсякий случай:
Код
void usrtSendByte( u08 data )
{
  cli();
    /* Wait for empty transmit buffer */
    while ( !( UCSRA & (1<<UDRE)) )
       _delay_ms(2);
    /* Put data into buffer, sends the data */
    UDR = data;
    sei();
}

u08 usrtReadByte( void )
{
  cli();
    /* Wait for data to be received */
    while ( !(UCSRA & (1<<RXC)) )
        _delay_ms(2);
    /* Get and return received data from buffer */
    u08 temp=UDR;
    sei();
    return temp;
}


На лицо полное не понимание чего-то smile.gif

Прошу помощи.

Спасибо

Сообщение отредактировал rezident - Mar 10 2010, 14:12
Причина редактирования: оформление цитаты исходника.
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
aaarrr
сообщение Mar 10 2010, 12:47
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(Didro @ Mar 10 2010, 15:30) *
Код UART навсякий случай:

Зачем, если очевидно, что виновато прерывание АЦП? Его и приведите.

P.S. _delay_ms(2) зачем?
Go to the top of the page
 
+Quote Post
Didro
сообщение Mar 14 2010, 12:30
Сообщение #3


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

Группа: Участник
Сообщений: 94
Регистрация: 9-04-07
Пользователь №: 26 893



Цитата(aaarrr @ Mar 10 2010, 15:47) *
Зачем, если очевидно, что виновато прерывание АЦП? Его и приведите.

Написал минимальный код при котором проявляется проблема:

CODE
#include <avr/io.h>
#include <avr/interrupt.h>

// Code compatibility to new AVR-libc
// outb(), inb(), inw(), outw(), BV(), sbi(), cbi(), sei(), cli()
#ifndef outb
#define outb(addr, data) addr = (data)
#endif
#ifndef inb
#define inb(addr) (addr)
#endif
#ifndef inw
#define inw(addr) (addr)
#endif
#ifndef BV
#define BV(bit) (1<<(bit))
#endif
#ifndef cbi
#define cbi(reg,bit) reg &= ~(BV(bit))
#endif
#ifndef sbi
#define sbi(reg,bit) reg |= (BV(bit))
#endif
#ifndef cli
#define cli() __asm__ __volatile__ ("cli" :smile.gif
#endif
#ifndef sei
#define sei() __asm__ __volatile__ ("sei" :smile.gif
#endif

//*****************************************************************************
//
// TIMERS
//
//*****************************************************************************

void initTimer()
{
outb(TCNT0, 0); // reset TCNT0
sbi(TIMSK, TOIE0); // enable TCNT0 overflow interrupt
outb(TCCR0, (inb(TCCR0) & ~0x07) | 0x02);

outb(TCNT1H, 0); // reset TCNT1
outb(TCNT1L, 0);
sbi(TIMSK, TOIE1); // enable TCNT1 overflow
outb(TCCR1B, (inb(TCCR1B) & ~0x07) | 0x02);

outb(TCNT2, 0); // reset TCNT2
sbi(TIMSK, TOIE2); // enable TCNT2 overflow
outb(TCCR2, (inb(TCCR2) & ~0x07) | 0x02);
}

//! Interrupt handler for tcnt0 overflow interrupt
ISR(TIMER0_OVF_vect)
{
PORTD=0xFF;
}

//! Interrupt handler for tcnt1 overflow interrupt
ISR(TIMER1_OVF_vect)
{

}

//! Interrupt handler for tcnt2 overflow interrupt
ISR(TIMER2_OVF_vect)
{

}

//*****************************************************************************
//
// UART
//
//*****************************************************************************

#define BAUD_RATE 9600ul
#define USART_UBBR_VALUE ((F_CPU/(BAUD_RATE<<4))-1)

void usrtInit( )
{
/* Set baud rate */
UBRRH = (unsigned char)(USART_UBBR_VALUE>>8);
UBRRL = (unsigned char)USART_UBBR_VALUE;
/* Enable Receiver and Transmitter */
UCSRB = (1<<RXEN)|(1<<TXEN);
/* Set frame format: 8data, 2stop bit */
UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
}

void usrtSendByte( unsigned char data )
{
/* Wait for empty transmit buffer */
while ( !( UCSRA & (1<<UDRE)) )
;
/* Put data into buffer, sends the data */
UDR = data;
}

unsigned char usrtReadByte( void )
{
/* Wait for data to be received */
while ( !(UCSRA & (1<<RXC)) )
;
/* Get and return received data from buffer */
return UDR;
}

//*****************************************************************************
//
// ADC
//
//*****************************************************************************

// initialize a2d converter
void a2dInit(void)
{
sbi(ADCSRA, ADEN); // enable ADC (turn on ADC power)
sbi(ADCSRA, ADATE); // choose free running mode
outb(ADCSRA, ((inb(ADCSRA) & ~0x07) | 0x06));
outb(ADMUX, ((inb(ADMUX) & ~0xC0) | (0x01<<6)));
cbi(ADMUX, ADLAR); // set to right-adjusted result

outb(ADMUX, (inb(ADMUX) & ~0x1F) | (0 & 0x1F)); // set channel

sbi(ADCSRA, ADIE); // enable ADC interrupts
}

// start a conversion on the current a2d input channel
void a2dStartConvert(void)
{
sbi(ADCSRA, ADIF); // clear hardware "conversion complete" flag
sbi(ADCSRA, ADSC); // start conversion
}

//! Interrupt handler for ADC complete interrupt.
SIGNAL(SIG_ADC)
{
unsigned char sample=(inb(ADCL) | (inb(ADCH)<<8)) >>2; // n?eoaai iiia?yiiia 10-aeoiia cia?aiea e ioa?inei 2 ieaaoeo aeoa
}

//*****************************************************************************
//
// MAIN
//
//*****************************************************************************

int main()
{
sei();
DDRD=0xFF;

initTimer();
a2dInit();
a2dStartConvert();

unsigned char data;
usrtInit( );
while(1)
{
data=usrtReadByte();
usrtSendByte(data);
}
}


Код для ПК (на C#):
Код
private static void VerySimpleEchoTest()
{
  port = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.Two);
  port.Open();

  port.DiscardInBuffer(); port.DiscardOutBuffer();
  port.ReadTimeout = 50;
  int i = 0;
            
  while (true)
  {
     i++;
                
     port.Write(new byte[] { (byte)random.Next(0, 255) }, 0, 1);
     Console.WriteLine("   echo:          " + port.ReadByte());
                
     Console.WriteLine("# " + i);
   }
}
Этот код падает при пересылке ~30000 сообщений (5-10 минут работы).
При этом до момента падения пересылаемое значение совпадает с ответом из AVR.

Контроллер ATMega32A-PU. Связь с ПК через Max232 (осциллограф каких-то проблем (завалы) на сигнальных линиях UART не показывает). Питание 5В от компьютерного БП.

Компилятор WinAVR-20090313, AVRStudio 4, -0s.
Фреймирование с помощью байтов со значениями 0, 0xFF соответственно до и после послыки байта данных пробовал - не помогает.

Цитата(aaarrr @ Mar 10 2010, 15:47) *
P.S. _delay_ms(2) зачем?
Последствия танцев с бубном.

Никак не пойму, где же быть ошибке...

для удобства тот же код, только с подсветкой:
Код для AVR: http://pastebin.com/43J3unFw
Код для ПК: http://pastebin.com/ZJdip1ft
Go to the top of the page
 
+Quote Post
smac
сообщение Mar 14 2010, 18:52
Сообщение #4


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

Группа: Участник
Сообщений: 149
Регистрация: 2-06-08
Из: Москва
Пользователь №: 38 003



Цитата(Didro @ Mar 14 2010, 15:30) *
Написал минимальный код при котором проявляется проблема:

Компилировать Ваш код и смотреть асм. листинг желания нет, уж больно длинный.
рекомендации:
а) написать действительно минимальный код - если проблема в АЦП, оставить только код относящийся к УАРТУ И АЦП
б) оформить обработчик прерывания от АЦП аналогично остальным, при этом не извращаться при чтении АЦП, а сделать так
Код
ISR(ADC_vect){
  unsigned char sample = ADCW;
/*Я поначалу не стал заводить лишнюю переменную и написал просто ADCW; но скомпилив увидел, что там в обработчике прерывания какой-то rcall нарисовался, ну его нафиг*/
}


в) на мой взгляд выражения типа outb(TCCR1B, (inb(TCCR1B) & ~0x07) | 0x02) не добавляют читаемости кода, наверное лучше так TCCR1B = (TCCR1B&0xf8)|(1<<CS11)

Да, кстати, может это и новый стиль, но я чего-то не понимаю, зачем эти sbi() и outb() мне они глаз режут, по-моему обычным макаром
Код
TCNT0 = 0;
код лучше выглядит.

ЗЫ ~30000 это случайно не 32767?

Сообщение отредактировал smac - Mar 14 2010, 18:57
Go to the top of the page
 
+Quote Post
Didro
сообщение Mar 15 2010, 09:39
Сообщение #5


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

Группа: Участник
Сообщений: 94
Регистрация: 9-04-07
Пользователь №: 26 893



Цитата(smac @ Mar 14 2010, 21:52) *
Компилировать Ваш код и смотреть асм. листинг желания нет, уж больно длинный.
рекомендации:
а) написать действительно минимальный код - если проблема в АЦП, оставить только код относящийся к УАРТУ И АЦП

Сделано - минимальный код только АЦП и UART: http://pastebin.com/BGZUMdz9
Вот asm-листинг этого кода при компиляции с ключом -Os: http://pastebin.com/9sZTuTXS
Вот asm-листинг этого кода при компиляции с ключом -O1: http://pastebin.com/d5VbNSL8

При компиляции с ключом -O1 проблема не наблюдается (версия WinAVR от 20100110), при компиляции с ключом -Os стабильно падает - проблем в asm коде не обнаружил (видимо что-то упускаю)

Цитата(smac @ Mar 14 2010, 21:52) *
ЗЫ ~30000 это случайно не 32767?
Нет падения происходят в различное время (от 7 тыс до 50 тыс).
Go to the top of the page
 
+Quote Post
smac
сообщение Mar 16 2010, 04:43
Сообщение #6


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

Группа: Участник
Сообщений: 149
Регистрация: 2-06-08
Из: Москва
Пользователь №: 38 003



Цитата(Didro @ Mar 15 2010, 12:39) *
При компиляции с ключом -O1 проблема не наблюдается (версия WinAVR от 20100110), при компиляции с ключом -Os стабильно падает - проблем в asm коде не обнаружил (видимо что-то упускаю)

Что-то я тоже ничего криминального не вижу. Попробуйте все-же оформить обработчик АЦП как ISR(ADC_vect){...} и еще попробуйте сделать следующее в майне сначала настройте уарт, затем настройте АЦП, затем запустите АЦП и только потом глобально разрешите прерывания, т. е. sei() должна стоять непосредственно перед входом в бесконечный цикл.
Опишите поподробней в чем выражаются "падения".
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- Didro   AVR Надежная работа UART и прерывания прочей переферии   Mar 10 2010, 12:30
- - defunct   Цитата(Didro @ Mar 15 2010, 11:39) Нет па...   Mar 20 2010, 23:46
- - Didro   Цитата(defunct @ Mar 21 2010, 02:46) Веро...   Mar 21 2010, 00:35
- - defunct   Цитата(Didro @ Mar 21 2010, 02:35) Вы не ...   Mar 21 2010, 00:48
- - RodionGork   //! Interrupt handler for tcnt0 overflow inter...   Mar 21 2010, 05:03
- - Didro   Цитата(RodionGork @ Mar 21 2010, 08:03) С...   Mar 21 2010, 06:36
- - RodionGork   Цитата(Didro @ Mar 21 2010, 09:36) Сигнал...   Mar 21 2010, 07:03
- - defunct   Цитата(Didro @ Mar 21 2010, 08:36) Если у...   Mar 22 2010, 01:26
- - RodionGork   Цитата(defunct @ Mar 22 2010, 04:26) Если...   Mar 22 2010, 06:40
- - Didro   Вчера обнаружил неправильно запрограммированный fu...   Mar 22 2010, 08:55
|- - RodionGork   Цитата(Didro @ Mar 22 2010, 11:55) Вчера ...   Mar 23 2010, 05:37
- - defunct   Цитата(RodionGork @ Mar 22 2010, 08:40) Э...   Mar 22 2010, 11:57


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

 


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


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