AVR Раздел по микроконтроллерам компании Atmel - AVR / ATtiny / ATmega / ATMega128 / ATxmega, вопросы по программированию в AVR studio и все, относящееся к AVR... |
25.08.2013, 13:35
|
#11
|
Почётный гражданин KAZUS.RU
Регистрация: 13.10.2007
Адрес: Беларусь
Сообщений: 8,048
Сказал спасибо: 60
Сказали Спасибо 3,954 раз(а) в 2,309 сообщении(ях)
|
Re: Глюк с UART при засыпании
Как я понимаю, смотреть ассемблерный листинг нынче считается дурным тоном...
|
|
|
|
25.08.2013, 13:46
|
#12
|
Частый гость
Регистрация: 27.08.2008
Адрес: Москва
Сообщений: 29
Сказал спасибо: 6
Сказали Спасибо 1 раз в 1 сообщении
|
Re: Глюк с UART при засыпании
Сообщение от Godzilla82
|
Залез в даташит. Везде ссылки на UBRR0, UCSR0A, UCSR0B, UDR0 и т.п.
Ну и сами
Код:
|
uart_print()
uart_tx_flush()
uart_putch() |
в студию.
|
всякие регистры без нулей - просто дефайны под конкретный контроллер. Код целиком есть в аттаче второго письма, но для желающих дублирую:
Код:
|
// defs:
#define NOINLINE __attribute__((__noinline__))
// dual-port fix
#ifndef UDRE
#define UDR (UDR0)
#define UDRE (UDRE0)
#define UBRRH (UBRR0H)
#define UBRRL (UBRR0L)
#define UCSRA (UCSR0A)
#define UCSRB (UCSR0B)
#define UCSRC (UCSR0C)
#define RXCIE (RXCIE0)
#define TXCIE (TXCIE0)
#define UDRIE (UDRIE0)
#define RXEN (RXEN0)
#define TXEN (TXEN0)
#define U2X (U2X0)
#define URSEL (URSEL0)
#define UCSZ0 (UCSZ00)
#define UCSZ1 (UCSZ01)
#define UCSZ2 (UCSZ02)
#define TXC (TXC0)
#define RXC (RXC0)
#endif
#if defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)
#define USART0_UDRE_vect (USART_UDRE_vect)
#define USART0_TXC_vect (USART_TX_vect)
#define USART0_RXC_vect (USART_RX_vect)
#endif
// кусочки uart.c
#define UART_TX_BUF_MASK (UART_TX_BUF_SIZE-1)
#define UART_RX_BUF_MASK (UART_RX_BUF_SIZE-1)
static volatile struct {
uint8_t in, out, cnt;
uint8_t buf [UART_TX_BUF_SIZE];
} _tx;
NOINLINE uint8_t uart_putch(uint8_t data) {
uint8_t sreg = SREG;
// Return failure for non-blocking mode
#ifdef UART_BLOCK
#warning *** UART IN BLOCKING MODE ***
while(_tx.cnt ›= UART_TX_BUF_SIZE) { ; }
#else
if (_tx.cnt ›= UART_TX_BUF_SIZE) return 0;
#endif
cli();
#ifdef RS485PORT
RS485PORT |= (1‹‹RS485PIN); // switch to TX
#endif
_tx.buf[_tx.in] = data;
_tx.in = (_tx.in + 1) & UART_TX_BUF_MASK;
_tx.cnt++;
UCSRB |= (1‹‹UDRIE);
SREG=sreg;
return 1;
}
void uart_tx_flush(void) {
while (_tx.cnt) {
UCSRB |= (1‹‹UDRIE);
}
while (
(UCSRA & ((1‹‹UDRE)|(1‹‹TXC))) != ((1‹‹UDRE)|(1‹‹TXC))
) { ; }
}
NOINLINE uint8_t uart_print(const char *str) {
while (*str ) {
if (!uart_putch(*str++)) return 0;
}
return 1;
}
ISR(USART0_UDRE_vect) {
if (_tx.cnt) {
UDR = _tx.buf[_tx.out];
_tx.out = (_tx.out + 1) & UART_TX_BUF_MASK;
_tx.cnt--;
}
if (_tx.in==_tx.out) {
_tx.cnt = 0;
_tx.in = 0;
_tx.out = 0;
UCSRB &= ~(1 ‹‹ UDRIE);
}
} |
|
|
|
|
25.08.2013, 13:52
|
#13
|
Частый гость
Регистрация: 27.08.2008
Адрес: Москва
Сообщений: 29
Сказал спасибо: 6
Сказали Спасибо 1 раз в 1 сообщении
|
Re: Глюк с UART при засыпании
Сообщение от niXto
|
Как я понимаю, смотреть ассемблерный листинг нынче считается дурным тоном...
|
Ну, почему же
Пока просто до этой стадии не дошло ибо давненько на столь низкий уровень не заползал (с неделю назад вообще кощунство устроил - начал с java под андроид ковыряться), потому и не задумывался.
Подозревал-то какую-нить очевидность или невниательность, ан - нет, сходу никто носом не ткнул (разве что про принудительную чистку TXC)
|
|
|
|
25.08.2013, 14:06
|
#14
|
Почётный гражданин KAZUS.RU
Регистрация: 29.10.2006
Сообщений: 1,443
Сказал спасибо: 99
Сказали Спасибо 315 раз(а) в 231 сообщении(ях)
|
Re: Глюк с UART при засыпании
PHP код:
|
void uart_tx_flush(void) {
while (_tx.cnt) {
UCSRB |= (1‹‹UDRIE);
}
while (
(UCSRA & ((1‹‹UDRE)|(1‹‹TXC))) != ((1‹‹UDRE)|(1‹‹TXC))
) { ; }
}
|
То есть пока _tx.cnt›0 (есть, что отправлять), разрешаем передатчик.
И ждём, пока в регистре состояния установятся флаги прерываний UDRE и TXC.
Причём, единожды установленный TXC нигде не сбрасывается.
В даташите не нашёл момента, когда очищается флаг UDRE. Или сам, после выполнения прерывания, или при записи 1. Если сам, то этот цикл могёт зациклится.
|
|
|
|
25.08.2013, 14:10
|
#15
|
Почётный гражданин KAZUS.RU
Регистрация: 29.10.2006
Сообщений: 1,443
Сказал спасибо: 99
Сказали Спасибо 315 раз(а) в 231 сообщении(ях)
|
Re: Глюк с UART при засыпании
Сообщение от av0000
|
Электрически - мега328Р на макетке, встроенный RC на 8МГц, питание 3.3В, TX/RX напрямую подключены к FT232RL (с неё же идёт питание через 1117-3.3) и (в процессе эксперментов) через резисторы 10к на землю.[/CODE]
|
То есть, когда трансмиттер отключён (нога на вход), формируется старт-бит?
|
|
|
|
25.08.2013, 14:28
|
#16
|
Почётный гражданин KAZUS.RU
Регистрация: 29.10.2006
Сообщений: 1,443
Сказал спасибо: 99
Сказали Спасибо 315 раз(а) в 231 сообщении(ях)
|
Re: Глюк с UART при засыпании
я бы переписал
PHP код:
|
void uart_tx_flush(void) { while (_tx.cnt); // { // UCSRB |= (1‹‹UDRIE); // } // зачем каждый раз разрешать прерывания, когда они сами должны // разрешатся при передаче очередного байта. // Если этого не происходит - надо исправлять ошибки с передачей. while ( (UCSRA & (1‹‹TXC)) != 0); // здесь ждём окончания передачи последнего байта. }
|
PHP код:
|
ISR(USART0_UDRE_vect) { if (_tx.cnt) { UCSRA = (UCSRA & 0b00011111) | (1‹‹TXC) ; UDR = _tx.buf[_tx.out]; _tx.out = (_tx.out + 1) & UART_TX_BUF_MASK; _tx.cnt--; }
if (_tx.in==_tx.out) { _tx.cnt = 0; _tx.in = 0; _tx.out = 0; UCSRB &= ~(1 ‹‹ UDRIE); } }
|
Последний раз редактировалось Godzilla82; 25.08.2013 в 15:07.
|
|
|
|
25.08.2013, 15:45
|
#17
|
Частый гость
Регистрация: 27.08.2008
Адрес: Москва
Сообщений: 29
Сказал спасибо: 6
Сказали Спасибо 1 раз в 1 сообщении
|
Re: Глюк с UART при засыпании
Godzilla82,
UDRE сам очищается при выходе из прерывания, если прерывания разрешены. (есть где-то там строчка в даташите про это)
Сообщение от Godzilla82
|
То есть, когда трансмиттер отключён (нога на вход), формируется старт-бит?
|
по поводу лишнего кода и 10k на "землю" - это издержки поиска источника глюков. там вообще сейчас лишних действий с избытком. Из серии "be paranoid" как любят писать наши англо-говорящие друзья, присваивая что-то переменной _за_ бесконечным циклом
Сообщение от Godzilla82
|
я бы переписал
|
Не уверен на счёт проверки только TXC - он может взвестись между посылками. Исходно было 3 проверки:
1. Ждём обнуления _tx.cnt ("тупо", как предложенном варианте)
2. Ждём взвода UDRE
3. Ждём взвода TXC
Сообщение от Godzilla82
|
UCSRA = (UCSRA & 0b00011111) | (1‹‹TXC) ;
|
А вот так делать, ЕМНИП, нельзя. Возможно, конкретно про UCSRA я и ошибаюсь, но в даташите регулярно говорится использовать промежуточную переменную для подобного.
Собственно, пока всё сводится к регулярному сбросу TXC. Завтра начну пробовать именно с этого.
|
|
|
|
25.08.2013, 17:08
|
#18
|
Почётный гражданин KAZUS.RU
Регистрация: 29.10.2006
Сообщений: 1,443
Сказал спасибо: 99
Сказали Спасибо 315 раз(а) в 231 сообщении(ях)
|
Re: Глюк с UART при засыпании
Сообщение от av0000
|
UDRE сам очищается при выходе из прерывания, если прерывания разрешены. (есть где-то там строчка в даташите про это)
|
Обычно, когда есть - явно пишут. Конкретно про UDRE на MEGA328 я не нашёл.
Сообщение от av0000
|
по поводу лишнего кода и 10k на "землю" - это издержки поиска источника глюков.
|
Издержки - издержками, но зачем посылать старт-бит. ФТ-шка будет думать, что началась передача байта. И по идее должна зафиксировать ошибку фрейма.
Сообщение от av0000
|
Не уверен на счёт проверки только TXC - он может взвестись между посылками.
|
Программа "однопотоковая". Следовательно, как мы попали в функцию flush(), ничто не должно увеличить _tx.cnt.
В ней мы ждём, чтобы количество данных для отправки _tx.cnt стало равным нулю.
Как только дождались - в этот момент передаётся последний байт. Флаг перед передачей очищен. И мы ждём, когда он возведётся. Всё. Проверять UDRE нет смысла. Тем более, если он сам может очиститься (что сомнительно) после выполнения прерывания.
Сообщение от av0000
|
А вот так делать, ЕМНИП, нельзя. Возможно, конкретно про UCSRA я и ошибаюсь, но в даташите регулярно говорится использовать промежуточную переменную для подобного.
|
Си при компиляции сам выделит для промежуточных результатов какой-нить регистр. Не вижу ничего криминального. Кроме как упрощения.
RXC0 - флаг USART Receive Complete.
UDRE0 - флаг USART Data Register Empty
Явно не написано, что эти флаги можно сбросить записью 1.
Поэтому сброс флага TXC можно упростить:
PHP код:
|
UCSRA |= (1‹‹TXC) ;
|
Последний раз редактировалось Godzilla82; 25.08.2013 в 17:13.
|
|
|
Сказали "Спасибо" Godzilla82
|
|
|
25.08.2013, 18:17
|
#19
|
Частый гость
Регистрация: 27.08.2008
Адрес: Москва
Сообщений: 29
Сказал спасибо: 6
Сказали Спасибо 1 раз в 1 сообщении
|
Re: Глюк с UART при засыпании
Godzilla82, Прорыл мануал, про UDRE говорит, что он сбрасывается записью в UDR и в него надо всегда писать "0" для совместимости. Так что всё верно.
ЗЫ: резисторы, разумеется, уберу. Там, кстати, другая засада есть - у FT232 выходы-то 5В, а я схему от 3.3 питаю, неаккуратненько получается (с). А городить преобразование уровней неохота - 232 порт нужен только сейчас, в макете...
|
|
|
|
25.08.2013, 18:27
|
#20
|
Почётный гражданин KAZUS.RU
Регистрация: 29.10.2006
Сообщений: 1,443
Сказал спасибо: 99
Сказали Спасибо 315 раз(а) в 231 сообщении(ях)
|
Re: Глюк с UART при засыпании
Сообщение от av0000
|
Прорыл мануал, про UDRE говорит, что он сбрасывается записью в UDR и в него надо всегда писать "0" для совместимости.
|
Тогда не совсем понятно с прерыванием. Ну выставился он в 1. Теперь, если прерывание разрешено, оно возникает. Но мы в нём ничего не пишем в UDR0. И UDRIE0 не трогаем. При выходе из прерывания - так как флаг остался взведённым - опять будет возникать прерывание?
Логичнее обрабатывать прерывание по TXC. Завершилась передача 1 байта - прерывание. Флаг очистился. Меньше телодвижений.
А согласование уровней - через резисторы 330 ом.
|
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 01:24.
|
|