ivainc1789 0 17 марта, 2012 Опубликовано 17 марта, 2012 · Жалоба IAR EWARM v6.30.6 Пробую впервые организовать обмен через USART1 между двумя устройствами, одно из которых MASTER, другое SLAVE. MASTER передает SLAVE'у 1 раз в 5 секунд следующий пакет: IDLE, некоторое кол-во байт, BREAK. Сижу j-link'ом на приемнике слейва и вижу как этот пакет успешно принимается, но проблема в том, что определить начало приема пакета и прием BREAK (конец пакета) не получается - флаги IDLE и FE в USART->SR не устанавливаются. Из-за этого правильно переинициализировать счетчик принятых байтов невозможно и принять правильно очередной пакет соответственно невозможно. Вот часть кода обработчика прерываний от USART1, ответственная за прием: /********************************** ПРИЕМ *************************************/ // обнаружен IDLE ( начало нового пакета ) if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET){ Usart.RxCnt = 0;// сброс счетчика принятых байтов } // обнаружен BREAK if(USART_GetITStatus(USART1,USART_IT_FE) != RESET){ Usart.RxCnt = 0;// сброс счетчика принятых байтов // проверка целостности if (RxBuf[1] != LOCALE_RS_ADR)return;// не мой пакет else{// проверка CRC unsigned int i,crc; CRC_ResetDR(); for(i=0;i<RxBuf[0]-4;i++){CRC->DR = (unsigned int)RxBuf[i];}// CRC crc = *(unsigned int*)RxBuf[RxBuf[0]-4]; if (CRC->DR != crc)return;// ошибка CRC else BITSET(Usart.Status,PackReady); } } // получен байт if(USART_GetITStatus(USART1,USART_IT_RXNE) != RESET){ unsigned char RxData; RxData = USART_ReceiveData(USART1);// чтение байта данных // запись байта данных в буфер if (Usart.RxCnt <= RxBufSize-1){ RxBuf[Usart.RxCnt] = RxData;Usart.RxCnt++; }else Usart.RxCnt = 0;// сброс счетчика принятых байтов } /******************************************************************************/ Что-то здесь не так с анализом флагов? Дальнейшее изучение показало, что библиотечными функциями типа USART_GetITStatus можно проанализировать только один флаг при приеме очередного байта, остальные флаги, так необходимые для анализа правильности приема, сбрасываются!!!! Т. е. один раз прочитал USART1->SR с помощью USART_GetITStatus и пипец, все биты (PE,ORE,FE,IDLE) сбросились! Вопрос - нафига так сделано? И почему библиотеки написаны соотв образом? В обработчике было бы корректно прочитать ВЕСЬ регистр USART1->SR в самом начале и потом уже разбираться с его содержимым... но я не уверен что все здесь правильно понимаю... Упростил ПО, теперь MASTER каждые 5 сек шлет только BREAK, а я пытаюсь его ловить слейвом. Теперь по входу в обработчик видно, что в USART1->SR устанавливаются биты FE,IDLE,LBD,TXE,TC. Т.е. все правильно: детектится и IDLE и framing error как и должно. Все это подтверждает вышесказанное... Остается вопрос - как же все-таки правильно организовать обработчик прерывания? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ivainc1789 0 19 марта, 2012 Опубликовано 19 марта, 2012 · Жалоба А я все же продолжу. Сначала разберемся с битом IDLE в USART1->SR. 1. Что это за состояние "линия свободна"? В даташите объяснено, что такое IDLE фрейм, но неясно, в какой конкретно момент устанавливается флаг IDLE. По идее такое состояние возникает как ДО так и ПОСЛЕ передачи ЕДИНСТВЕННОГО пакета. Достаточно ли для установки флага наличие десяти "1" (старт, 8бит, стоп) или необходимы еще и стоп/старт бит предыдущего/последующего пакетов? 2. Путем экспериментов обнаружено, что состояние IDLE ловится нормально при: if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET){ Usart.RsCnt = 0; USART_ReceiveData(USART1); // сброс бита IDLE (если чтение убрать, IRQ вызывается непрерывно) } Но в даташите сказано, что сброс бита должен осущ с помощью спец последовательности: 1. Прочитать USART_DR 2. Прочитать USART_SR У меня здесь наоборот - сначала читается USART_SR, потом USART_DR - и это работает! Где же правда? 3. Если поставить точку останова в IAR EWARM C-CPY (используется j-link) на входе в обработчик IRQ, то вижу IDLE=0! Но это неверно! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Dejmos 0 20 марта, 2012 Опубликовано 20 марта, 2012 · Жалоба Что-то такое вспоминается, хотя давно это было. Попробуйте проверять флаги через USART_GetFlagStatus, а GetITStatus при проверке на RXNE перед чтением. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ivainc1789 0 20 марта, 2012 Опубликовано 20 марта, 2012 · Жалоба Что-то такое вспоминается, хотя давно это было. Попробуйте проверять флаги через USART_GetFlagStatus, а GetITStatus при проверке на RXNE перед чтением. Совершенно верно! Я потратил три дня на разборки с USART в STM32 и теперь написал обработчик уверенно, который работает! В кратце, проблема в том, что некоторые биты в USART->SR многофункциональны и используются по разному в разных режимах. И библиотеки написаны так, что GetITStatus можно использовать только в определенных режимах, иначе нужно биты обрабатывать через GetFlagStatus да еще многие и "под эгидой" RXNE. Но... Осталась непонятная проблема. Попробую объяснить, если кто-то захочет обсудить... Есть два девайса, общаются по RS-485 (ADM485 на обоих). Управление прием/передача по одному проводу, т. е. либо прием, либо передача. Софт написан примитивный для скорости 9600. Этапы общения: 1. Мастер шлет пакет слэйву, например: 0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01. 2. Слэйв успешно его принимает и отправляет подтверждение 0x05,0x04,0x03,0x02,0x01. 3. Мастер это подтверждение принимает без ошибок, если слэйв отправляет это подтверждение с задержкой более 4-5мс относительно приема от мастера. 4. Если слэйв отправляет сразу же, то приходит: 0x05,0x04,0x05,0x04,0x03,0x02,0x01. 5. Если скорость USART увеличить с 9600 до 115200 - все работает нормально. При этом обработчик одинаковый в обоих устройствах!!! Вчера сидел целый день, никак не вкурю как так может быть, что слэйв реально отправляет 5 байт, а мастер получает 7 ??? И почему такая зависимость от задержки ответа? J-link'ом смотрел счетчик передаваемых/принимаемых байтов - так и есть, слэйв отправляет 5, мастер принимает 7. Не понимаю... Вот обработчик приема/передачи: // USART1 прием/передача пакетов void USART1_IRQHandler(void){ /********************************** ПРИЕМ *************************************/ if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET){// линия RX свободна USART_ReceiveData(USART1);// сброс PE,FE,NE,ORE,IDLE bits in USART_SR Usart.RsCnt = 0; } if(USART_GetITStatus(USART1,USART_IT_RXNE) != RESET){// получен некий байт if(USART_GetFlagStatus(USART1,USART_FLAG_ORE) != RESET){// overrun USART_ReceiveData(USART1);// сброс PE,FE,NE,ORE,IDLE bits in USART_SR Usart.RsCnt = 0; }else if(USART_GetFlagStatus(USART1,USART_FLAG_NE) != RESET){// шум USART_ReceiveData(USART1);// сброс PE,FE,NE,ORE,IDLE bits in USART_SR Usart.RsCnt = 0; }else if (USART_GetFlagStatus(USART1,USART_FLAG_FE) != RESET){// конец пакета USART_ReceiveData(USART1);// сброс PE,FE,NE,ORE,IDLE bits in USART_SR Usart.RsCnt = 0;// сброс счетчика принятых байтов if (RsBuf[1] == LOCALE_RS_ADR)// мой пакет BITSET(Usart.Status,PackReady); }else{// сохранение данных в буфере RsBuf[Usart.RsCnt++] = USART_ReceiveData(USART1); if (Usart.RsCnt >= RsBufSize)Usart.RsCnt = 0; } } /********************************** ПЕРЕДАЧА **********************************/ if(USART_GetITStatus(USART1,USART_IT_TXE) != RESET){// передача байта if (Usart.RsCnt < RsBuf[0]){// передача байта данных USART_SendData(USART1,RsBuf[Usart.RsCnt++]); }else{// конец пакета USART_SendBreak(USART1);// признак конца пакета USART_ITConfig(USART1,USART_IT_TXE,DISABLE); USART_ITConfig(USART1,USART_IT_TC,ENABLE); } } if(USART_GetITStatus(USART1,USART_IT_TC) != RESET){// передача завершена PINCLR(RTX);// разрешить прием Usart.RsCnt = 0; USART_ITConfig(USART1,USART_IT_TC,DISABLE); } /******************************************************************************/ } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ivainc1789 0 21 марта, 2012 Опубликовано 21 марта, 2012 · Жалоба Таки обнаружил коварный глюк - в обработчике (код выше)! Причина в том, что состояние линии RX на предмет IDLE мониторится как при приеме, так и при передаче. Должно мониторится только при приеме. Итак, при успешном приеме от мастера пакета-запроса и переходе слэйва из режима приема в режим передачи ответа выставляется бит IDLE, что в режиме передачи ответа приводило к сбросу Usart.RsCnt в ноль (но почему-то перед передачей ТРЕТЬЕГО байта ответа!). Таким образом, слэйв передавал на 2 байта больше. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться