Перейти к содержанию
    

Проблема с Т3 в ATMEGA128

Подобная тема поднималась уважаемым klen 16.11.2007 http://electronix.ru/forum/index.php?showt...%E0%E9%F2%E0%ED . К сожалению, проблема решена не была. Вернее уважаемый klen в частном случае решил, но сослася на потусторонние силы - "ШАЙТАН - БАЙРАМ" .

Суть проблемы - по ходу работы программы необходимо останавливать и вновь запускать таймер Т3 и менять содержимое регистров OCR3A/OCR3B/TCNT3. Первичная инициализация Т3 проходит успешно:

void timer3_init(void)

{

TCCR3B = 0x00; //stop

TCNT3H = 0xC1; //setup

TCNT3L = 0x81;

OCR3AH = 0x07;

OCR3AL = 0xCF;

OCR3BH = 0x07;

OCR3BL = 0xCF;

OCR3CH = 0x07;

OCR3CL = 0xCF;

ICR3H = 0x07;

ICR3L = 0xCF;

TCCR3A = 0x00;

TCCR3B = 0x09; //start Timer

}

Далее открываем фирменное описание на ATMEGA128 на странице 114 и читаем:

"The TCNTn, OCRnA/B/C, and ICRn are 16-bit registers that can be accessed by the AVR CPU via the 8-bit data bus. The 16-bit register must be byte accessed using two read or write operations. Each 16-bit timer has a single 8-bit register for temporary storing of the high byte of the 16-bit access. ".

 

Спасибо, что предупредили. Более того на странице 116 описания написано:

"The following code examples show how to do an atomic write of the TCNTn Register contents. Writing any of the OCRnA/B/C or ICRn Registers can be done by using the same principle."

И дается пример кода:

TIM16_WriteTCNTn:

; Save global interrupt flag

in r18,SREG

; Disable interrupts

cli

; Set TCNTn to r17:r16

out TCNTnH,r17

out TCNTnL,r16

; Restore global interrupt flag

out SREG,r18

ret

НО ЭТОТ КОД НИКОГДА РАБОТАТЬ НЕ БУДЕТ!

Потому что, на странице 365 того же описания с изумлением читаем:

($89) TCNT3H Timer/Counter3 – Counter Register High Byte

($88) TCNT3L Timer/Counter3 – Counter Register Low Byte

($87) OCR3AH Timer/Counter3 – Output Compare Register A High Byte и т. д.

Т. е. out TCNTnH,r17 в принципе не возможно(как к регистру ввода-вывода, т.к. такой регистр в регистровом файле отсутствует), а должно быть, по крайней мере, sts TCNTnH,R17 (как к адресному пространству памяти данных).

Применяем вот такую функцию :

void WriteOCR3A( unsigned int i )

{

unsigned char sreg;

CLI();

sreg = SREG;

OCR3A = i;

SREG = sreg;

SEI();

}

Но таймер Т3 правильно не настраивается. Причем есть действительно чертовчина. Например:

TCCR3B = 0x00; //stop

WriteTCNT3(Mem_TCNT);

WriteOCR3A(Mem_D_Period);

TCCR3B = 0x09; //start - не работает,

 

TCCR3B = 0x00; //stop

WriteTCNT3(Mem_TCNT);

WriteOCR3С(Mem_D_Period);

TCCR3B = 0x09; //start - не работает.

В симуляторе AVRStudio(Version 4.14 Beta 2) все работает без проблем.

Прошу помощи советом, ссылками для решения этой проблемы. Заранее благодарен.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

out TCNTnH,r17 - обобщенный вид инструкций out TCNT0H,r17, out TCNT1H,r17 и т.д. по числу таймеров. Так что работать должно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

out TCNTnH,r17 - обобщенный вид инструкций out TCNT0H,r17, out TCNT1H,r17 и т.д. по числу таймеров. Так что работать должно.

 

Позвольте с Вами не согласиться. Дело в том, что команда out P,Rr допустима для операндов P и Rr, где

P - порт(или регистр имеющий адрестр в регистровом файле), а Rr - регистр общего назначения. Так вот

TCNT3H, TCNT3L и т.д. не находятся в регистровом файле, а доступны лишь как память данных. Т.Е. КОМАНДА OUT К НИМ НЕ ДОПУСТИМА.

 

$2D ($4D) TCNT1H Timer/Counter1 – Counter Register High Byte

$2C ($4C) TCNT1L Timer/Counter1 – Counter Register Low Byte

 

Для TCNT1H таймера Т1 возможно out $2D, Rr или sts $4D, Rr но для таймера T3

 

($89) TCNT3H Timer/Counter3 – Counter Register High Byte

 

доступно долько sts $89, R. См. стр. 361, 362 описания 2467P–AVR–08/07

http://www.atmel.com/dyn/resources/prod_do...nts/doc2467.pdf

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для TCNT1H таймера Т1 возможно out $2D, Rr или sts $4D, Rr но для таймера T3

Я для таких случаев написал макрос

//**************************************************************************
// OutPort - generate out or sts instruction
OutPort MACRO Port,reg
    IF (Port)<0x40
        OUT Port, reg
    ELSE
        STS Port, reg
    ENDIF
  ENDM

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я для таких случаев написал макрос

//**************************************************************************
// OutPort - generate out or sts instruction
OutPort MACRO Port,reg
    IF (Port)<0x40
        OUT Port, reg
    ELSE
        STS Port, reg
    ENDIF
  ENDM

Уважаемый KRS, спасибо за совет. Возьму на вооружение, но проблема в том, что 16 разрядные регистры таймера Т3 даже при правильном обращении STS ведут себя не адекватно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо, что предупредили. Более того на странице 116 описания написано:

 

На самом деле это серьёзный плюс! Впервые такая конструкция была применена в i8054, так как в i8053 было сделано "обычно", в результате чего вы могли получить ошибку превышающую 256 единиц!

 

НО ЭТОТ КОД НИКОГДА РАБОТАТЬ НЕ БУДЕТ!

Потому что, на странице 365 того же описания с изумлением читаем...

Да эта ошибка у них практически в каждом даташите, где появилось обращение к регистрам ч/з LD/ST.

 

Так как вы применяете, я тоже применяю таймера. Никаких проблем не возникало никогда. AVR Studio отлично эмулирует и достаточно точно. Единственно, что AVR Studio неверно эмулирует это обращения по не верным адресам. Ну например сделали вы стэк в области адресов ввода/вывода (например там даже устройств нет), - а в AVR Studio всё прекрасно работает. А в кристалле - шиш. :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

но проблема в том, что 16 разрядные регистры таймера Т3 даже при правильном обращении STS ведут себя не адекватно.

 

о "граблях" когда когда долго мучился с "глюком", а в результате "сам дурак" оказался

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Применяем вот такую функцию :

void WriteOCR3A( unsigned int i )

{

unsigned char sreg;

CLI();

sreg = SREG;

OCR3A = i;

SREG = sreg;

SEI();

}

а зачем сохранять sreg?

обычно всетки функция выгдядит так

void WriteOCR3A( unsigned int i )
{
unsigned char sreg;
sreg = SREG;
CLI();
OCR3A = i;
SREG = sreg;
}

 

или под IAR это делается так

unsigned char oldState;
oldState = __save_interrupt();
__disable_interrupt();
/* Critical section goes here */
__restore_interrupt(oldState);

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

На самом деле это серьёзный плюс! Впервые такая конструкция была применена в i8054, так как в i8053 было сделано "обычно", в результате чего вы могли получить ошибку превышающую 256 единиц!

Да эта ошибка у них практически в каждом даташите, где появилось обращение к регистрам ч/з LD/ST.

 

Так как вы применяете, я тоже применяю таймера. Никаких проблем не возникало никогда. AVR Studio отлично эмулирует и достаточно точно. Единственно, что AVR Studio неверно эмулирует это обращения по не верным адресам. Ну например сделали вы стэк в области адресов ввода/вывода (например там даже устройств нет), - а в AVR Studio всё прекрасно работает. А в кристалле - шиш. :)

 

Уважаемый SasaVitebsk, Вы можете, в качестве примера привести код при работе с таймером Т3 для MEGA128. Заранее благодарен.

 

 

Уважаемый Дон Амброзио, есть три опытных образца и все ведут себя одинаково. Правда MEGA128 из одной партии. Может быть. Не охота конечно демонтировать MEGA128.

 

Уважаемый KRS, поначалу SREG не сохранял, но сохранять советует описание ATMEGA128. Но эффекта нет. Возможно предлагают сохранять SREG по такой причине:

"2. Interrupts may be lost when writing the timer registers in the asynchronous timer If one of the timer registers which is synchronized to the asynchronous timer2 clock is written in the cycle before a overflow interrupt occurs, the interrupt may be lost." (Errata ATmega128 Rev. M) стр. 370.

Изменено пользователем aai_m

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Уважаемый SasaVitebsk, Вы можете, в качестве примера привести код при работе с таймером Т3 для MEGA128. Заранее благодарен.

Я не работал с м128. Но какая разница? Таймеры у них у всех один к одному и давно уже не меняются. Работал с м640/м2560 (вплоть до 5 включительно) и, недавно с at90can128 (применял программный ШИМ).

Ну и как обычно м8/м4/м88/м16/м64.

 

Что именно у вас не работает? Опишите по подробнее!

 c = UDR0;                                                // Прочитать символ
TCNT3 = -(TIMOUT485);                                    // Начать сначала
TIFR3 = TIFR3;
TIMSK3    = 1;                                            // Разрешить прерывания    от Таймера 3 (Расчёт таймаута)

 

...
#pragma    vector=TIMER3_OVF_vect                            // Тайм-аут    для    485    интерфейса.    Время переключения 5мс
__interrupt    static void    TimeOutFor485(void)
{
...
  TIMSK3 = 0;                                            // Запретить прерывания    от таймера
}
...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...