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

USART1 на STM32F100C6T6

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 как и должно. Все это подтверждает вышесказанное... Остается вопрос - как же все-таки правильно организовать обработчик прерывания?

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


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

А я все же продолжу. Сначала разберемся с битом 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! Но это неверно!

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


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

Что-то такое вспоминается, хотя давно это было. Попробуйте проверять флаги через USART_GetFlagStatus, а GetITStatus при проверке на RXNE перед чтением.

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


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

Что-то такое вспоминается, хотя давно это было. Попробуйте проверять флаги через 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);
  }
/******************************************************************************/
}

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


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

Таки обнаружил коварный глюк - в обработчике (код выше)!

Причина в том, что состояние линии RX на предмет IDLE мониторится как при приеме, так и при передаче. Должно мониторится только при приеме.

Итак, при успешном приеме от мастера пакета-запроса и переходе слэйва из режима приема в режим передачи ответа выставляется бит IDLE, что в режиме передачи ответа приводило к сбросу Usart.RsCnt в ноль (но почему-то перед передачей ТРЕТЬЕГО байта ответа!). Таким образом, слэйв передавал на 2 байта больше.

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


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

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

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

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

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

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

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

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

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