Непонятная работа Arduino Nano с COM в Linux

Автор Shaman, 12 Июнь, 2023, 17:12

« предыдущая - следующая »

Shaman

Имеем Arduini Nano  со скетчем:
int val; 
void setup() {
  
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
 }


void loop() {
  int8_t i;
  
  if (Serial.available()) {
     val = Serial.read();
   if (val == '1') {
    for (i=0; i<5 ; i++) {
    digitalWrite(LED_BUILTIN, HIGH);   
  delay(500);                       
  digitalWrite(LED_BUILTIN, LOW);   
  delay(500);
    }
}

Это упрощенная, для дебага, версия скетча эмулирующего пульт ДУ, просто вместо отправки пакетов на ИК светодиод он моргает встроенным. В исходном виде код работает аналогично, пульт эмулируется.

Если для отправки команд использовать программы picocom, minicom, монитор порта ардуино и любые другие терминалы всё работает. Но если просто плюнуть в порт командой:
echo "1" > /dev/ttyUSB0

Ничего не произойдет. Ардуинка его получает, начинает исполнять, но исполнение срывается. Команда начинает работать только в том случае если открыть на блокирующее чтение фал COM-порта ардуинки, любой командой способной это делать cat, grep и т.д.
Код: Пример
cat > /dev/ttyUSB0

При этом на осциллограмме всегда одни и те же данные, щупы подключены непосредственно к выводам UART.

RigolDS14.png

Первый байт - это 49 , ascii код символа "1" в десятичной системе. Второй - это 10, код символа LF (line feed), он подставляется автоматически.
Т.е. данные до процессора доходят всегда и всегда одинаковые, каких то изменений мне отловить не удалось. Но в одном случае код срабатывает, а в другом срывается. С повторяемостью 100% на 2-х разных платках Nano и разных ПК.

Кто-нибудь имеет представление, чем обусловлено такое поведение?

Под спойлером видео представление правильной и не правильной работы, для лучшего понимания. Оно короткое, посмотрите пожалуйста
Видео работы
[свернуть]

Slabovik

Смотрел только порт приёма. А порт отправки не смотрел?
Общением на форуме подпитываю свою эгоистичную, склонную к самолюбованию сущность.

Shaman

Либо я чего-то не понимаю либо вы

Я подключился вот сюда
electrical_shema_arduino_nano.png

На скрине RX желтая TX синяя  (подписаны)

При прошивке пакеты по ним видно, при работе устройство ничего не отправляет да и не должно.

Или вы про что-то другое?

Slabovik

#3
Я про то, что если используемые библиотеки ничего не отсылают, они ничего и не должны ждать. А если отсылают - затык может быть на стороне приёма (сигналы управления портом).

Из описания я понял, что при приёме байта из одной программы ардуина что-то делает, а при приёме точно такого же (вплоть до бита) из другой программы, не делает. По факту это мистика и нужно выявлять побочный неявный функционал.

зы: а ты уверен, что любой терминал точно всегда добавляет 0Ah после? Не в этом ли собака порылась? Потому что Echo точно довабляет конец строки/перевод, а вот терминал... ? Не зависает ли ардуиновский алгоритм по приходу этого 0Ah вследствие "неожиданного" прихода при отсутствии обработки этого прихода (не прописано прерывание и т.п.), а в это время у тебя там Delay Delay?
Общением на форуме подпитываю свою эгоистичную, склонную к самолюбованию сущность.

Shaman

Думаю что не в этом дело. 0Ah не влияет на работу поскольку команда Serial.read(); читает только первый приходящий байт, и что там на конце ей фиолетово. Пробовал через монитор порта изменять конец строки всё работает одинаково правильно.
Да и у echo  есть параметр не вносить 0Ah
Код: Выглядит вот так
echo -n "1" > /dev/ttyUSB0

А осциллограмма вот так
RigolDS15.png

С командой echo начинает работать только тогда когда файл /dev/ttyUSB0 открыт на бесконечное считывание какой-нибудь программой.

И да одиночное моргание светодиодом L скорее всего означает перезагрузку атмеги (по крайней мере при перезагрузке она так же моргает). Но почему это происходит при приёме команды.
Я пробовал подключать логический анализатор, но ни при открытом на чтение файле /dev/ttyUSB0, ни при использовании терминала, ни просnо при отправке echo каких-то еще данных кроме вышеуказанных не передаётся.

Мне не обоснованно кажется, что проблема может крыться в настройке COM порта, но я пока не могу разобраться как работает команда stty
У COM порта вон ажно сколько параметров
stty -F /dev/ttyUSB0 -a
speed 9600 baud; rows 0; columns 0; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 hupcl -cstopb cread clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff
-iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
echoctl echoke -flusho -extproc

Всё что я научился ей делать это менять скорости.

Ради интереса пробовал в тупую заинитить UART в ардуине кодом на СИ
#include <IRremote.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#define FOSC 16000000
#define BAUD 9600
#define MYUBRR FOSC/16/BAUD-1
IRsend irsend;
int val;
uint8_t rx_buf;
uint8_t rx_end = 0;
uint8_t temp = 0b00110001;
void setup() {
  
  pinMode(LED_BUILTIN, OUTPUT);


  //Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
}
void USART_Init( unsigned int ubrr)
{
  /*установка битрейта */
  UBRR0H = (unsigned char)(ubrr >> 8);
  UBRR0L = (unsigned char)ubrr;

  UCSR0A = 0;                                  //Режим двойной скорости выключен:
  UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0); // Установка параметров: включение портов ввода и вывода, разрешение прерывание по окончанию приёма
  UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); // Установка формата фрейма: 8data, 1stop bit
}
// the loop function runs over and over again forever
ISR (USART_RX_vect)
{ 
  rx_buf = UDR0;
  rx_end = 1;

}
void loop() {
  USART_Init(MYUBRR);
  sei();                      //разрешаем глобальные прерывания
  int8_t i;
/*while(!(UCSR0A&(1<<UDRE0)));
                UDR0 = temp;*/
  if (rx_end == 1) {
    val = rx_buf; // переменная val равна полученной команде
    
    rx_end = 0;
    if (val == 49) {
      for (i = 0; i < 5 ; i++) {
        digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
        delay(500);                       // wait for a second
        digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
        delay(500);
      }
}
}

Но в таком виде он почему-то не обрабатывает прерывания хотя отправка идёт отлично.

Slabovik

терминал по-дефолту открывает порт и на чтение и на запись.
Цикл так-то закрыть надо, он не оформлен (заначка есть, но что-то пошло не так). По окончании прохода прога вываливается в никуда.
Переменным RX_xxx надо бы свойство Volatile сделать, чтобы явно указать, что компилятору их оптимизировать не надо.
Общением на форуме подпитываю свою эгоистичную, склонную к самолюбованию сущность.