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

Знающий
   
Группа: Свой
Сообщений: 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] - для короткого!!! форматирование
|
|
|
|
|
 |
Ответов
(15 - 29)
|
Mar 7 2016, 10:10
|

Знающий
   
Группа: Свой
Сообщений: 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 микросекунд. т е десятикратно от длительности передачи одного байта. посмотрю еще как все это себя ведет , может засада эшелонированная.
|
|
|
|
|
Mar 7 2016, 12:02
|

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

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

Гуру
     
Группа: Модераторы
Сообщений: 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)
|
|
|
|
|
Mar 7 2016, 13:32
|

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

|
Ну какой же вы тупой! (с) Цитата(firstvald @ Mar 7 2016, 17:59)  ну так, чтение модификация запись собственно это и делает. мы прочитали (да, этого можно было и не делать) , сбросили нужный бит и записали . Вам уже и пример привели, и на словах объяснили. Вы прочитали, там ещё несколько нулей. И все эти биты вы сбросили записью. А между тем моментом, когда вы прочитали, и записью, могли взвестись ещё флаги. И вы их таким образом потеряете. Именно для того, чтобы избежать таких ситуаций, делают rc_w0. Чтобы можно было смело писать единичку в остальные биты, и от этого их состояние не менялось.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Mar 7 2016, 14:16
|

Знающий
   
Группа: Свой
Сообщений: 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).
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|