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

 
 
> stm32f100 USART задержка передачи и потеря символов, Физически передача начинается с задержкой. Теряется 1 или 2 байт.
firstvald
сообщение Mar 6 2016, 12:58
Сообщение #1


Знающий
****

Группа: Свой
Сообщений: 580
Регистрация: 3-06-08
Пользователь №: 38 041



Кристалл stm32f100. Плата Discovery.

Вижу, что передача по USART начинается с задержкой. Т е после записи в DR, на ножке процессора посылка появляется примерно через время равное передачи байта (без стопов и паритета) на выбранной скорости. Для 115200 физически передача начинается через 8 микросекунд, для 19200 - через 400, для 1200 - через 10 миллисекунд. Т е такое впечатление, что после записи в DR автомат вхолостую отрабатывает сдвиг регистра ничего не выдавая на ножку и после одного холостого цикла уже забирает данные из DR.

При одновременной работе нескольких портов теряется первый или второй байт в передаваемой последовательности или даже первый со вторым переставляются местами (во всех портах или в каком то одном , картина может меняться при изменении кода). Причем, даже в длинной последовательности все остальные байты передаются нормально. Это возникает при как при одновременной работе нескольких портов так и если оставить один порт.


Инициирование USART

CODE
//Инициируем UARTы

void USART1_INI(unsigned char spd, unsigned char par, unsigned char stp)
//spd - скорости обмена
// 10 115200
// 9 57600
// 8 38400
// 7 19200
// 6 9600
// 5 4800
// 4 2400
// 3 1200
// 2 600
//par - паритет
// 0 без паритета
// 1 нечетный паритет
// 2 четный паритет
//stp - число стоп битов
// 0, 1 - 1
// 2 - 2
//
//
//
{
GPIO_InitTypeDef GPIO_InitStructure;
short unsigned int i;



//*********************************************************
//Конфигурируем ножки под ввод вывод


//включаем тактирование портов
RCC->APB2ENR|=RCC_APB2ENR_IOPAEN;//GPIOA


//TX1 PA9
//Ножка назначается на вывод пуш пуль
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init( GPIOA , &GPIO_InitStructure);
//RX1 PA10
//Ножка назначается на ввод
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init( GPIOA , &GPIO_InitStructure);

USART1->CR1=0;
USART1->CR1|=USART_CR1_UE;//включили UART
USART1->CR1&=~USART_CR1_M;//8 бит
USART1->CR1&=~USART_CR1_WAKE;// пробуждение по IDLE LINE

//if(par==0){
USART1->CR1&=~USART_CR1_PCE;//без паритета
USART1->CR1&=~USART_CR1_PS;// нечетный паритет
USART1->CR1&=~USART_CR1_M;//8 бит
// }
if(par==1){
USART1->CR1|=USART_CR1_PCE;//паритет
USART1->CR1|=USART_CR1_PS;// нечетный паритет
USART1->CR1|=USART_CR1_M;//9 бит
}
if(par==2){
USART1->CR1|=USART_CR1_PCE;//паритет
USART1->CR1&=~USART_CR1_PS;// четный паритет
USART1->CR1|=USART_CR1_M;//9 бит
}



USART1->CR1|=USART_CR1_PEIE;//общее разрешение прерывания
// USART1->CR1|=USART_CR1_TXEIE;//разрешение прерывания по опустошению буфера передачи
USART1->CR1&=~USART_CR1_TXEIE;//запрещение прерывания по опустошению буфера передачи
USART1->CR1&=~USART_CR1_TCIE;//запрещено прерывание от "передача закончена"
//USART1->CR1|=USART_CR1_TCIE;// прерывание от "передача закончена"
USART1->CR1|=USART_CR1_RXNEIE;// разрешение прерывания по приему
USART1->CR1&=~USART_CR1_IDLEIE;//запрещено прерывание от IDLE
USART1->CR1|=USART_CR1_TE;//передатчик включен
USART1->CR1|=USART_CR1_RE;//приемник включен
USART1->CR1&=~USART_CR1_RWU;//приемник в активном режиме
USART1->CR1&=~USART_CR1_SBK;//запрос передачи длинного 0 выключен

USART1->CR2=0;
//if(stp<=1){//1 стоп
USART1->CR2&=~USART_CR2_STOP;//1 стоп
// }
if(stp==2){//2 стоп
USART1->CR2&=~USART_CR2_STOP;//1 стоп
USART1->CR2|=USART_CR2_STOP_1;//2 стоп
}

USART1->CR3=0;

USART1->SR&=0;//Флаги всех прерываний сбросили


USART1->BRR=0X0480;//19200
if(spd==10){
USART1->BRR=0X00C0;//115200
}

// готовим буферы обмена

//#define rx_buf_long 256
//#define tx_buf_long 256


i=0;
while(i<rx_buf_long){
rx_buf1[i]=0;
i++;
}
i=0;
while(i<tx_buf_long){
tx_buf1[i]=0;
i++;
}

USART1->SR=0;//СБРАСЫВАЕМ ФЛАГИ
// CTS
// LBD
// TC
// RXNE
// IDLE
// NE
//

rx_ptr1=0;
tx_ptr1=0;
//индекс последнего передаваемого элемента буфера
tx_last1=0;

rx_state1=0;
tx_state1=0;

}


Само прерывание от одного порта

CODE
void USART1_IRQHandler(void)
{
//прием
if((USART1->SR&USART_SR_RXNE)!=0) {//что то пришло
USART1->SR&=~USART_SR_RXNE;//сбросим флаг
rx_buf1[rx_ptr1]=USART1->DR;
if(rx_ptr1<rx_buf_long){
rx_ptr1++;
}

}//что то пришло

//передача

if((USART1->SR&USART_SR_TC)!=0) {//данные переписались из буфера в сдвиговый регистр и ушли из него
if(tx_state1==1){//идет передача
USART1->SR&=~USART_SR_TC;//сбросим флаг
if(tx_ptr1>=tx_last1){//ушел последний байт
tx_state1=0;
GPIOC->ODR &= ~GPIO_ODR_ODR4;// смотрим этой ножкой момент, когда закончилась передача
USART1->CR1&=~USART_CR1_TCIE ;
}//ушел последний байт
else{//передаем дальше
tx_ptr1++;
USART1->DR=tx_buf1[tx_ptr1];
}//передаем дальше
}//идет передача
else{//фантомное прерывание- мы ничего не должны передавать
USART1->CR1&=~USART_CR1_TCIE ;//сбросим разрешение этого прерывания
}//фантомное прерывание- мы ничего не должны передавать
}//данные переписались из буфера в сдвиговый регистр
USART1->SR=0;

}



и затравка которая начинает передачу:

CODE
InitGPIO();
Init_OSC_my();//инициализация и переключение синхронизации

USART1_INI(3,2,2);//1200







tx_buf1[0]=0x30;
tx_buf1[1]=0x31;
tx_buf1[2]=0x32;
tx_buf1[3]=0x33;
tx_buf1[4]=0x34;
tx_buf1[5]=0x35;
tx_buf1[6]=0x36;
tx_buf1[7]=0x37;
tx_buf1[8]=0x38;
tx_buf1[9]=0x39;
tx_buf1[10]=0x41;
tx_buf1[11]=0x42;
tx_buf1[12]=0x43;
tx_buf1[13]=0x44;
tx_buf1[14]=0x45;
tx_buf1[15]=0x46;
tx_buf1[16]=0x47;
tx_buf1[17]=0x48;
tx_buf1[18]=0x49;
tx_buf1[19]=0x4a;
tx_buf1[20]=0x4b;

tx_state1=1;
tx_last1=20;
tx_ptr1=0;


__NOP();



USART1->CR1|=USART_CR1_TCIE ;
GPIOC->ODR |= GPIO_ODR_ODR4;// между выставлением этой ножки и началом передачи на ножке - выдержка времени
USART1->DR=tx_buf1[tx_ptr1];


Сообщение отредактировал IgorKossak - Mar 6 2016, 14:00
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!! форматирование
Go to the top of the page
 
+Quote Post
3 страниц V  < 1 2 3 >  
Start new topic
Ответов (15 - 29)
firstvald
сообщение Mar 7 2016, 10:10
Сообщение #16


Знающий
****

Группа: Свой
Сообщений: 580
Регистрация: 3-06-08
Пользователь №: 38 041



вот что удалось понять.

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


т е, в инициализации приемопередатчика нужно предусмотреть формальную передачу одного двух байт. если критично появление посылок на ножках - переключение ножек на альтернативные функции нужно перенести после окончания посылки.

Код
    USART3->SR&=~USART_SR_TC;
    USART3->DR=0xff;
    while((USART3->SR&USART_SR_TC)==0){
;
                                         }
    
    
    USART3->SR&=~USART_SR_TC;


после инициализации и вот такого кусочка кода, дальше посылки уходят правильно.

отмечу, что этот кусочек для скорости 115200 выполнятся порядка 100 микросекунд. т е десятикратно от длительности передачи одного байта.


посмотрю еще как все это себя ведет , может засада эшелонированная.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Mar 7 2016, 10:49
Сообщение #17


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Все не так, ребята! (с) ВВС
Проверьте все свои тактовые частоты на шинах.
Нужно проверять
if (USART2->SR & USART_SR_TXE && USART2->CR1 & USART_CR1_TXEIE) {
...
Go to the top of the page
 
+Quote Post
firstvald
сообщение Mar 7 2016, 10:55
Сообщение #18


Знающий
****

Группа: Свой
Сообщений: 580
Регистрация: 3-06-08
Пользователь №: 38 041



а что значит проверить? скорости обмена соответствуют для линейки от 1200 до 115200. для шин 1 и 2 выбрано 1:1.

и это как-то может объяснить, что приемопередатчик умудряется переставить два байта местами? кстати, это означает, что унутре у него вовсе все не так устроено, как на блок схеме нарисовано.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Mar 7 2016, 11:02
Сообщение #19


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(firstvald @ Mar 7 2016, 13:55) *
и это как-то может объяснить, что приемопередатчик умудряется переставить два байта местами? кстати, это означает, что унутре у него вовсе все не так устроено, как на блок схеме нарисовано.

Я принимаю и передаю и никаких проблем не имею. Все согласно документации.

Первый байт посылаете не в прерывании. Разрешаете прерывания от TXE. Остальные байты посылаете по прерыванию. Сбрасывать флаг не нужно. Перед передачей последнего байта ('\n'), запрещаете прерывания.
Go to the top of the page
 
+Quote Post
firstvald
сообщение Mar 7 2016, 11:18
Сообщение #20


Знающий
****

Группа: Свой
Сообщений: 580
Регистрация: 3-06-08
Пользователь №: 38 041



мне не нужно TXE , мне нужно TC. фокусы с \n не пройдут (да где вы все работаете что у вас символьные строки бегают до сих пор ?!). все что происходит я описал подробнейшим образом. и как лечится тоже.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Mar 7 2016, 11:21
Сообщение #21


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(firstvald @ Mar 7 2016, 14:18) *
мне не нужно TXE , мне нужно TC. фокусы с \n не пройдут (да где вы все работаете что у вас символьные строки бегают до сих пор ?!). все что происходит я описал подробнейшим образом. и как лечится тоже.

Я всякое передаю. Последний байт может быть любым, главное, знать, что он последний. Попробуйте TXE, если не хотите время терять (как свое, так и процессора).
Go to the top of the page
 
+Quote Post
firstvald
сообщение Mar 7 2016, 12:02
Сообщение #22


Знающий
****

Группа: Свой
Сообщений: 580
Регистрация: 3-06-08
Пользователь №: 38 041



вот на самом деле именно обратно! чтобы понять, что мы окончили передачу, нужно использовать TC, иначе сразу начинается геморрой с выдержкой времени после TXE, да еще перестраиваемая в зависимости от скорости.

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

TXE я, наверное, посмотрю, как он себя ведет. но дело не в них.
Go to the top of the page
 
+Quote Post
adnega
сообщение Mar 7 2016, 12:11
Сообщение #23


Гуру
******

Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702



TXE и TC - это две большие разницы.
Записывать в буфер передатчика нужно по TXE, а после записи последнего байта пакета
разрешаем прерывание от TC. При возникновении TC можно быть уверенным, что байт полностью передан.
Сбрасывать флаги нужно как написано в документации (rc_w0), а не "как обычно".
Go to the top of the page
 
+Quote Post
firstvald
сообщение Mar 7 2016, 12:42
Сообщение #24


Знающий
****

Группа: Свой
Сообщений: 580
Регистрация: 3-06-08
Пользователь №: 38 041



TC поднимается когда TXE выставлен -> записывая в буферный регистр по TC мы имеем двойную гарантию что делаем это вовремя: и из буферного регистра в сдвиговый переписались и уже и из сдвигового выдвинули.

да , флаги помечены как сбрасываются записью нуля (кстати, хорошее замечание). но отладчиком я вижу , что чтение модификация работают (да если посмотреть примеры кода в сети , то народ чтением модификацией стирает).
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 7 2016, 12:54
Сообщение #25


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(firstvald @ Mar 7 2016, 14:42) *
TC поднимается когда TXE выставлен -> записывая в буферный регистр по TC мы имеем двойную гарантию что делаем это вовремя:
Первой гарантии достаточно. Вторая гарантия даст только паузы между байтами если программа делет что-нибудь еще кроме передачи.
Цитата(firstvald @ Mar 7 2016, 14:42) *
да если посмотреть примеры кода в сети , то народ чтением модификацией стирает
Да если посмотреть примеры в сети, то народ и дорогу на красный переходит, и через двойную сплошную переезжает... Продолжать?


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
firstvald
сообщение Mar 7 2016, 12:59
Сообщение #26


Знающий
****

Группа: Свой
Сообщений: 580
Регистрация: 3-06-08
Пользователь №: 38 041



сразу не сообразил.
чтение модификация запись - как раз точно то, что надо и делает.
флаг помечен как rc_w0 - т е его можно прочитать и он сбрасывается записью нуля.
ну так, чтение модификация запись собственно это и делает. мы прочитали (да, этого можно было и не делать) , сбросили нужный бит и записали .
все в стандартной, принятой для битовой работе манере. и то, что нужно по описанию регистру
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Mar 7 2016, 13:32
Сообщение #27


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Ну какой же вы тупой! (с)
Цитата(firstvald @ Mar 7 2016, 17:59) *
ну так, чтение модификация запись собственно это и делает. мы прочитали (да, этого можно было и не делать) , сбросили нужный бит и записали .

Вам уже и пример привели, и на словах объяснили. Вы прочитали, там ещё несколько нулей. И все эти биты вы сбросили записью. А между тем моментом, когда вы прочитали, и записью, могли взвестись ещё флаги. И вы их таким образом потеряете.
Именно для того, чтобы избежать таких ситуаций, делают rc_w0. Чтобы можно было смело писать единичку в остальные биты, и от этого их состояние не менялось.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
ViKo
сообщение Mar 7 2016, 13:49
Сообщение #28


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(adnega @ Mar 7 2016, 15:11) *
... а после записи последнего байта пакета
разрешаем прерывание от TC. При возникновении TC можно быть уверенным, что байт полностью передан.

А когда (зачем) это нужно знать? А, ну если приемопередатчики RS-485 переключать со входа на выход...
Go to the top of the page
 
+Quote Post
firstvald
сообщение Mar 7 2016, 14:16
Сообщение #29


Знающий
****

Группа: Свой
Сообщений: 580
Регистрация: 3-06-08
Пользователь №: 38 041



Цитата(AHTOXA @ Mar 7 2016, 17:32) *
Ну какой же вы тупой! (с)

Вам уже и пример привели, и на словах объяснили. Вы прочитали, там ещё несколько нулей. И все эти биты вы сбросили записью. А между тем моментом, когда вы прочитали, и записью, могли взвестись ещё флаги. И вы их таким образом потеряете.
Именно для того, чтобы избежать таких ситуаций, делают rc_w0. Чтобы можно было смело писать единичку в остальные биты, и от этого их состояние не менялось.


это надумано. тогда подумайте что будет в момент между чтением флагов когда мы решили что они нули и записью туда 0 прямой командой записи.
не повторяйте чужие мантры, учитесь думать сами и внимательно слушать, когда до вашего сведения аккуратно доводят, что тут что-то не так.
а как научитесь, милости просим на форум.

Цитата(ViKo @ Mar 7 2016, 17:49) *
А когда (зачем) это нужно знать? А, ну если приемопередатчики RS-485 переключать со входа на выход...


ну двухпроводной уарт в промышленности практически не используется (если только диагностический порт с морды или какой прибор с несетевым обменом). если только при общении с беспроводными модулями - у них еще отдельные TX RX. А так, поголовно RS485 (там где не TCP).
Go to the top of the page
 
+Quote Post
ViKo
сообщение Mar 7 2016, 14:19
Сообщение #30


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(firstvald @ Mar 7 2016, 17:12) *
это надумано. тогда подумайте что будет в момент между чтением флагов когда мы решили что они нули и записью туда 0 прямой командой записи.

Вы не разобрались, как работает rc_w0. Такой бит можно прочитать, или сбросить, записав 0. А записать 1 в него невозможно. И поэтому можно смело записывать единицы, они не повредят.
Go to the top of the page
 
+Quote Post

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

 


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


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