dim3740

Ошибка / пропуски при буферизации данных

16 сообщений в этой теме

dim3740    4

Читается порт UART на микроконтроллере Atmega. Применяю типовой алгоритм, но аппаратно вижу ошибки. Что неверное, или отчего они могут быть?
 

unsigned char rx_buffer[128]; //накопительный буфер
unsigned char indexW; // индекс при наполнении накопительного буфера
unsigned char Count; // счетчик накопительного буфера
unsigned char indexR; // индекс при опорожнении накопительного буфера
int Max; // максимум до переполнения
char tempMessage; // временная переменная

int main(void)
{

   Max=100; // пробовал разные

   while(1)
    {
        _delay_us(40); // пробовал от 10 мкс до мс
        
                if (Count > 0) 
        {
            tempMessage=rx_bufferR[indexR];  
            
                        MesComplite(tempMessage); //тут анализ каждого считанного байта. Это занимает время 
                                        //поэтому и нужен буфер
            
            indexR++;  
            
            if (indexR>=Max)  indexR=0;  //Значение Max одинаковое для чтения и записи. Может разные проба?
            
            cli();  // для надежности запрет прерывания
            Count--;
            sei(); //разрешение
            
            if (Count>=Max)  Count=0;
        
        }
        
    }
}

ISR(USART_RXC_vect)  
{
    if (UCSRA & (1<<7))   
    {
        
        rx_buffer[indexW]=UDR;
        
        indexW++;  
        
        if (indexW>=Max)  indexW=0;
     
            Count++;
        
        if (Count>Max)  Count=0; 
    
    }
}


1. Задержка нужна в цикле whole? У меня при нуле еще больше ошибок(((
2. Размеры 128 и 100 методом подбора?
3. Инкременты ++ ставить после команды?
4. запреты прерывания нужны?
5. If делаю на "равенство и больше". Верно?
6. Какие есть иные методы повышения надежности, кроме повторной отправки при ошибке?

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


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

Вопрос в том ещё, что скажем есть 2-3 алгоритма устранения дребезга. Неужели нет других алгоритмов и по сабжу? Скажем что если юзать сразу три буферных одномерных массивов и потом сверять их на идентичность данных по одному и тому же индексу?

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


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

Странноватый код. Я правда не помню когда я атмел последний раз видел, так что тапками не кидаться, но все-таки:

0) Вы уверены что инициализация UART правильная? Как минимум, проверьте что ошибка в baud rate на разных сторонах линка не более 2%, иначе будут глюки. Из вашего сорца не видно какой baud вы пытаетесь получить и все такое.

1) Delay какой-то в основном цикле. Он несет какой-то смысл? Обработчик прерывания свое время сам урвет. На то оно и прерывание что вышибет основную программу. Похоже на костыль маскирующий истинную проблему.

2) Размеры буфера - по размеру максимального пакета который вы хотите жевать за раз (и доступной памяти). Это зависит от того что вы намереваетесь делать с данными и какими порциями они имеют смысл. Кроме того, лимит в 100 байтов в обработчике при 128 байтах буфера приводит к тому что 28 байтов оперативки сжираются под буфер но никогда не используются, поскольку при достижении 100 обработчик делает разворот. Оставшиеся байты на вид вроде бы просто потеряны, а у атмела не настолько уж огромная оперативка.

3) В вашем коде нет никаких способов понять где начало передачи данных и все такое прочее. Ну то-есть если алгоритм начал вкалывать с середины передачи с той стороны - он что-то конечно примет. С произвольного места. А вот имеет ли принятое смысл - отдельный вопрос.

4) При малейшей неидеальности ваш код вероятно рассинхронизируется с передатчиком и врядли вернется в синхронизм. Ну как, протокола у вас нет, чексум нет, анализа ошибок UART тоже нет. Причина ошибок останется загадкой, просто потому что никто нигде не проверяет ошибки и не заморачивается ре-синхронизацией по допустим протокольному таймауту (т.е. сброс состояния протокола на исходное по таймауту например).

5) Подозрительно выглядит main loop, например sei вы сделали, а потом if (Count>=Max)  Count=0; - а если между сравнением и присвоением приедет IRQ, то чего? IRQ не в курсе намерений сделать Count = 0, он что-то сделает с Сount, наверное не просто, вернется. А тут вы хлоп Count в 0 когда выполнение вернулось обратно main. Но хотели вы наверное не этого? Похоже на race condition вроде.

6) Неплохо бы чтобы у протокола еще и чексуммы какие-то были для понимания что данные побились. Или если это интерактив через терминалку то короткие команды и выход по таймаутам или характерным маркерам типа перевода строк на исходное состояние "ждем команду".

7) Что до дребезга, железо UART обычно делает oversampling порядка 8 отсчетов на бит и принимает решение что за бит по мажоритарному принципу. Как оно у атмела написано в их даташите. И если у вас все настолько плохо что uart ловит мусор и вас беспокоит дребезг - где хотя-бы обработка framing error и проч? Да и после того как вы узнали что ошибка - часть данных возможно потеряна. У вас на этот счет был план? Если UART поймает стартовый бит там где его не было, вся последовательность будет сдвинута. UART поймает сколько-то данных, в конце концов заметит framing error, когда STOP в нужном месте не окажется. Часть данных окажется порушена, часть не принята. Если вы хотите работать в окружении где ошибки норма, придется сделать какой-нибудь протокол. Если данные ценные, их придется попросить у отправителя еще раз. Если не очень - хотя-бы выйти на исходное состояние.

8) Сразу 3 массива - да вы эстет. Вы хотите слать данные 3 раза и выбирать по мажоритарному принципу? А оно надо? К тому же при framing error uart может принять что-то из середины битового потока и не сразу заметить проблему. В конце концов он скорее всего отхватит framing error, не найдя STOP вовремя, но сколько данных до этого приедет и что в них будет - никто не обещает. И трояная посылка одного и того же байта может в этом случае не помочь.

А так для повышения надежности можно слать не абы что а пакет с характерным маркером начала, указанием длины и чексумой, возможно маркером конца. И подтверждать отправителю что получили, если это важно. Если подтверждения нет - слать пакет еще раз. При этом понятно и где начало данных (маркер должен совпасть, иначе пропускаем мусор мимо ушей пока правильный маркер не появится), и получили ли мы все что хотел послать отправитель (по размеру пакета и возможно маркеру конца), и правильно ли это приехало (по чексуме). При этом и хардварные проблемы будут видны не в виде нежданчиков а в виде какой-нибудь статистики протокола. Кстати все это актуально и для второй стороны линка. Особенно забавно когда там компьютер с многозадачной ОС, там некоторые забавные особенности есть.

Изменено пользователем guest87

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


Ссылка на сообщение
Поделиться на других сайтах
dim3740    4
13 минуты назад, guest87 сказал:

Странноватый код. Я правда не помню когда я атмел последний раз видел, так что тапками не кидаться, но все-таки:

0) Вы уверены что инициализация UART правильная? Как минимум, проверьте что ошибка в baud rate на разных сторонах линка не более 2%, иначе будут глюки. Из вашего сорца не видно какой baud вы пытаетесь получить и все такое.

31250. Прием MIDI сообщений в музыкальном оборудовании.  Сбой примерно 1 на сотню нажатых клавиш (т.е. получено около 600 байт)

13 минуты назад, guest87 сказал:

1) Delay какой-то в основном цикле. Он несет какой-то смысл? Обработчик прерывания свое время сам урвет. На то оно и прерывание что вышибет основную программу. Похоже на костыль маскирующий истинную проблему.

Это методом тыка. Почему то без него сбоев гораздо больше

13 минуты назад, guest87 сказал:

2) Размеры буфера - по размеру максимального пакета который вы хотите жевать за раз (и доступной памяти). Это зависит от того что вы намереваетесь делать с данными и какими порциями они имеют смысл. Кроме того, лимит в 100 байтов в обработчике при 128 байтах буфера приводит к тому что 28 байтов оперативки сжираются под буфер но никогда не используются, поскольку при достижении 100 обработчик делает разворот. Оставшиеся байты на вид вроде бы просто потеряны, а у атмела не настолько уж огромная оперативка.

Пакетов нет... все непрерывно. Оперативка, выделение памяти по "правильные" переменные, оптимизация ее - это удел профи, и нехватки ресурсов. У меня примитивная задача, и минимальной атмеги хватит за глаза)))) Зачем экономит то, то не жалко?

13 минуты назад, guest87 сказал:

3) В вашем коде нет никаких способов понять где начало передачи данных и все такое прочее. Ну то-есть если алгоритм начал вкалывать с середины передачи с той стороны - он что-то конечно примет. С произвольного места. А вот имеет ли принятое смысл - отдельный вопрос.

Да. Но сбой именно где-то в середине и т.п. передачи...

13 минуты назад, guest87 сказал:

4) При малейшей неидеальности ваш код вероятно рассинхронизируется с передатчиком и врядли вернется в синхронизм. Ну как, протокола у вас нет, чексум нет, анализа ошибок UART тоже нет. Причина ошибок останется загадкой, просто потому что никто нигде не проверяет ошибки и не заморачивается ре-синхронизацией по допустим протокольному таймауту (т.е. сброс состояния протокола на исходное по таймауту например).

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

13 минуты назад, guest87 сказал:

5) Подозрительно выглядит main loop, например sei вы сделали, а потом if (Count>=Max)  Count=0; - а если между сравнением и присвоением приедет IRQ, то чего? IRQ не в курсе намерений сделать Count = 0, он что-то сделает с Сount, наверное не просто, вернется. А тут вы хлоп Count в 0 когда выполнение вернулось обратно main. Но хотели вы наверное не этого? Похоже на race condition вроде.

М.б. это действительно, ошибка.  Я не проф. программист, а музыкант. Поэтому многое делаю не понимая((((

13 минуты назад, guest87 сказал:

6) Неплохо бы чтобы у протокола еще и чексуммы какие-то были для понимания что данные побились. Или если это интерактив через терминалку то короткие команды и выход по таймаутам или характерным маркерам типа перевода строк на исходное состояние "ждем команду".

7) Что до дребезга, железо UART обычно делает oversampling порядка 8 отсчетов на бит и принимает решение что за бит по мажоритарному принципу. Как оно у атмела написано в их даташите. И если у вас все настолько плохо что uart ловит мусор и вас беспокоит дребезг - где хотя-бы обработка framing error и проч? Да и после того как вы узнали что ошибка - часть данных возможно потеряна. У вас на этот счет был план? Если UART поймает стартовый бит там где его не было, вся последовательность будет сдвинута. UART поймает сколько-то данных, в конце концов заметит framing error, когда STOP в нужном месте не окажется. Часть данных окажется порушена, часть не принята. Если вы хотите работать в окружении где ошибки норма, придется сделать какой-нибудь протокол. Если данные ценные, их придется попросить у отправителя еще раз. Если не очень - хотя-бы выйти на исходное состояние.

Про деребезг - это я для примера, и конечно, простых кнопок, а не UART.

13 минуты назад, guest87 сказал:

8) Сразу 3 массива - да вы эстет. Вы хотите слать данные 3 раза и выбирать по мажоритарному принципу? А оно надо? К тому же при framing error uart может принять что-то из середины битового потока и не сразу заметить проблему. В конце концов он скорее всего отхватит framing error, не найдя STOP вовремя, но сколько данных до этого приедет и что в них будет - никто не обещает. И трояная посылка одного и того же байта может в этом случае не помочь.

Это я не подумал. Я предполагал, один UART и писать в три массива. Но, думаю, что ошибки идут чисто аппаратные (фронты сигналов, помехи и т.п.) и ошибка запишется во все три массива. Забыли эту мысль!

13 минуты назад, guest87 сказал:

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

 

Но за подробный разбор спасибо! Просто я бы хотел абстрагироваться от мелочей, и понять, нельзя ли кардинально решить задачу иначе? Я сейчас добавлю пост еще одним сообщением....

 

Вообще имеем черный ящик. На него приходят байты от источника (синтезатор). С него уходят байта на другой синтезатор. В Ч,Я - разные алгоритмы преобразования инфы. Допустим, что преобразования не нужно. Тогда справедлив ли код в обработчике UART, типа:

 temp=UDR  и сразу UDR=temp.

Да, он работает. Тут нет буфера, ибо зачем он нужен, если программист знает алгоритм работы девайса в целом и понимает, что НИЧТО не прервет эту отправку СРАЗУ. Ибо нет более высокого уровня задачи, нет падений питания, нет нажатия кнопок, таймеров и т.п. Но... он н универсален, ибо это частный случай. Идем дальше: пусть надо "вклинить" опрос пары кнопок. Размещаем этот опрос в главном цикле. Но опять таки играя музыкант НЕ нажимает эти кнопки. Так может опять буфер не нужен?  А когда он нужен? Когда, нужно сделать что-то именно с поступающими байтами. Логика верна? Я не знаю, просто советуюсь....

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


Ссылка на сообщение
Поделиться на других сайтах
guest87    0
28 minutes ago, dim3740 said:

31250. Прием MIDI сообщений в музыкальном оборудовании. 

Ого, понятно. Тогда про блоки придется забыть. А вы запрограммили именно такой baud rate на стороне МК, с точностью не хуже 2%? Уж простите я не помню как у атмела синтез baud делается.

Сбой примерно 1 на сотню нажатых клавиш (т.е. получено около 600 байт)

Понятно. А если для начала без прерываний читать в tight loop из регистра, без задержек (ориентируясь на флаг приема) ничего с данными не делая - ошибки будут? Если да - похоже на проблему "железного" характера. Если нет - логика буферизации. Если проблема с железом - у вас сделана опторазвязка как советуют на https://learn.sparkfun.com/tutorials/midi-tutorial/all ? Без этого есть шанс собрать солидные наводки и принимать черти-что, у вас наверное провода длинные. Спасибо если только это - хорошая наводка на длинный кабель может и порт вынести. В случае опторазвязки нет левых токов в порты, да и убить транзистор малореально в отличие от порта IO.

Это методом тыка. Почему то без него сбоев гораздо больше

Нет смысла прятать проблему под ковер. Она от этого не пропадет - стоит понять в чем причина. Мне не нравится что обработчик и main живут своими жизнями настолько независимо что одурачивают друг друга внезапными сменами переменных. Хотя у вас и аппаратная проблема может быть.

Пакетов нет... все непрерывно. Оперативка, выделение памяти по "правильные" переменные, оптимизация ее - это удел профи, и нехватки ресурсов. У меня примитивная задача, и минимальной атмеги хватит за глаза)))) Зачем экономит то, то не жалко?

Да я уж посмотрел. Хоть и не занимался именно миди, но протокол нашел по быстрому. Там и правда все побайтово. Но сказать что пакетов нет - не совсем так. Есть некое состояние - байты описывающие что это такое и потом 1 или несколько ожидаемых байтов для некоторых команд как я понимаю. Это не совсем независимые байты и вывод о том получили ли все что хотели сделать можно.

Кстати данных немного и можно наверное вообще в tight loop ловить все и там же парсить. Или если хочется по фэншую, с прерыванием и буфером, наверное в прерывание вынести немного логики разбора midi, как минимум понимание где начало очередной команды, сколько байтов ждать и поймали ли всю команду или нет. И анонс main что все что хотели - приехало. Или если вся команда за разумное время не приехала - забываем и ждем новую.

Да. Но сбой именно где-то в середине и т.п. передачи...

На самом деле может быть по куче причин, от несовпадения baud и длинного шнура поймавшего помехи до кривой логики буферизации. Я бы попробовал для начала получать байты как есть без прерываний глупым poll. Это фи по использованию ресурсов, зато все предельно просто и ошибиться негде. Кстати 31250 битов в секунду это 3125 байтов в секунду (8-N-1=10 битов). У вас есть 1/3125 секунды (=32мкс) чтобы с байтом что-то сделать, не потеряв следующий. Это не то чтобы очень много, но для простых вещей хватит.

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

Да, тут уж увы, если это миди - тогда так. И тут только добиваться приема без ошибок. Что на стороне железа что на стороне софта. Но все-таки анализ флагов типа ошибок фрейминга или что там атмел умеет - позволит понять есть ли проблемы "железного" характера. Ну как, в идеале ошибок фрейминга и проч быть не должно и если они есть это повод посмотреть что с "железом".

М.б. это действительно, ошибка.  Я не проф. программист, а музыкант. Поэтому многое делаю не понимая((((

Однако ж начать с довольно продвинутой работы с прерываниями и чем-то типа кольцевого буфера - замах весьма солиден. И хотя ряд вещей вызывают подозрения, общая идея работы с прерыванием какая-то такая. Вот только такой кольцевой буфер вам наверное вообще не надо. А переменные которые меняет ISR стоит указывать как volatile. Иначе си может оптимизировать доступ к ним на свою голову, оформив переменную как значение регистра а не адрес в памяти. ISR же не в курсе такой подляны, он вызывается железом, регистры в этот момент уже другое и можно потенциально огрести глюков. Но это "в си и МК вообше", я не помню насколько это критично для атмела, но все с чем имеет дело IRQ стоит декларить как volatile.

Про деребезг - это я для примера, и конечно, простых кнопок, а не UART.

Однако аппаратные UART нечто подобное в виде оверсэмпла делают. Так устойчивее.0

Это я не подумал. Я предполагал, один UART и писать в три массива. Но, думаю, что ошибки идут чисто аппаратные (фронты сигналов, помехи и т.п.) и ошибка запишется во все три массива. Забыли эту мысль!

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

Но за подробный разбор спасибо! Просто я бы хотел абстрагироваться от мелочей, и понять, нельзя ли кардинально решить задачу иначе? Я сейчас добавлю пост еще одним сообщением...

Я бы попробовал для начала тупым poll из регистра UART читать все что валится и посмотреть насколько то что валится (не)правильное для понимания виновато ли железо в чем либо. За 32 мкс до следующего байта (быстрее он не приедет чисто физически) можно успеть и флаги ошибок посмотреть и даже что-то сделать (например в второй uart загнать если у него baud выше, отфорвардив на комп).

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

 

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


Ссылка на сообщение
Поделиться на других сайтах
dim3740    4
2 часа назад, guest87 сказал:

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

Это не страшно)) Главное, что Вы не пытаетесь учить меня профкодированию, а согласны подойти к проблеме обобщенно. Я также сейчас выдаю все "от печки", по сути задачи в целом, но и ваши советы проанализирую. Итак. На базе вышеприведенного кода я сделал почти 2 десятка МИДИ устройств за 3 года. И, для любительских задач "1\600" ошибка приемлима. Но, сейчас хотел бы все таки решить этот косяк. Ибо в профоборудовании его не наблюдаю. Кабели те же. Другое железо попробовать? МК есть PIC STM  и т.п. Может вообще на AVR нет позитивных результатов ни у кого? Но тогда возникает вопрос об сравнимости "условий" эксперимента. Одно дело компьютерщик-музканант тыкает мышкой на компе, набирая по-нотке. Другое - сцена и игра 10 пальцами, кулаками, и еще и ногами и головой (как я). Тут поток сообщений гораздо выше.  Идея: нужно создать тестовый генератор МИДИ последовательностей с регулируемым периодом посыла. И получить функцию "ошибка от периода". А сейчас все идет так: барабаню на клавишах ахинею, - "чем быстрее и больше - тем более вероятна ошибка". И жду, когда она появится.. А она непредсказуема((( Но если появляется - то это конфуз на сцене.... Вот так. Это эмоции))). Далее. Я вообще не могу найти алгоритмов как сделано подобное в проф.девайсах. ПОэтому - все - "от любительского опыта".  Потом выложу код, что "разбор" 3-х байтов (определение стартового = "некого "пакета") и прочее я делаю ПОСЛЕ выхода из п\п уарта. Вы пИшите, что можно сделать его в самой п\п. Это мне нужно понять))) Тут надо оценить и вложенность прерываний, что я пока не анализировал. А мысль, что пока попробовать вообще опросом бита регистра - вообще нова до нельзя!  

Изменено пользователем dim3740

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


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

1.

        rx_buffer[indexW]=UDR;                  indexW++;                    if (indexW>=Max)  indexW=0;                   Count++;                  if (Count>Max)  Count=0; 

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

2. у вас не синхронизирован прием и чтение из данного буфер

 

Читайте про кольцевой буфер.

Если вы читали, значит поняли что тоне так

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


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

@hasl пример слизал отсюда...http://www.proavr.narod.ru/z5.htm и приложил скрин фрагмента.

А синхронизация, имхо, как раз не нужна... на то и буфер. Хотя, думаю, что под синхро вы имели что-то другое. Скажу тогда, что игра на пианино имеет "паузы", и опорожнение буфера будет всегда. Да, код НЕ универсален, но я хочу делать то, что нужно именно в конкретном случае по ТЗ.

И еще: как объяснить, что на 99% код работает? 

 

 

пример.jpg

Изменено пользователем dim3740

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


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

1. на заборе много что пишут

2.Слизав не разобравшись - от сюда ошибки

 

У вас может быть на столько большая задержка что принятые данные обнулят Count.

т.е. фактически данные были но вы их как бы не видите

Размер буфера должен быть на столько большим, чтобы при самых жестких задержках в него могли влезть все данные и еще остаться

Еще раз говорю, код кольцевого буфера не корректный

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


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

Я не только слизал с весьма авторитетного источника, но и разобрался в меру своего опыта. Ваша мысль про размер буфера понятна и принята. Конечно, если приемник НЕ ГОТОВ по скорости принять инфу, то буфер переполнится. Но... мой приемник - это не более, как... скажем, громкоговоритель. Там нет никаких других процессов, кроме чтения. Синтезатор, который воспроизводит приемный поток свободен... на нем никто не играет (в отличие от синтезатора- источника). Поэтому в МОЕМ случае, имхо, ошибка никак не связана с размером буфера. Я пробовал кольцевой ставить всего 2 (и то успевает) , а пробовал 1000, ибо памяти мне не жалко. Эффект одинаковый. Т.е. сбой есть, но редкий.

Изменено пользователем dim3740

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


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

. сделайте размер буфера 1 и посмотрите, что будет

11 минуту назад, dim3740 сказал:

с весьма авторитетного источника,

LOL

авторитетные источники н-и-к-а-д-а не пишут статей, они пишут DataSheet & userManual но  и там косяков хватает

Изменено пользователем hasl

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


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

Ну это для меня авторитетные они))) Сделал 1, т.е. фактически это один байт стал [0] , тоже работает на вскидку. Сбой, как всегда, после пары минут интенсивной игры...... Это все не дело)))) . я точно понял, что надо писать тестовый генератор (как писал выше), чем сейчас и занимаюсь на C#.  Но это не просто, потому что надо тогда и МИДИ входной порт аппаратно задействовать.  Но имхо тут все же мне помогут)))) На форуме программистов вообще МК не хотят заниматься(((( 

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


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

Выкиньте этот Count, он тут и даром не нужен. Проверка новых байтов просто по неравенству indexR и indexW:

while(1)
{
    if (indexR !=  indexW) 
    {
        tempMessage=rx_bufferR[indexR];  
        MesComplite(tempMessage); //тут анализ каждого считанного байта. Это занимает время 
        indexR++;  
        if (indexR>=Max)  indexR=0; 
    }
}
ISR(USART_RXC_vect)  
{
    if (UCSRA & (1<<7))   
    {
        rx_buffer[indexW]=UDR;
        indexW++;  
        if (indexW>=Max)  indexW=0;
    }
}

 

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


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

а MAX вы тоже сделали 1?

я больше скажу

сделав размер массива = 1, но оставив МАХ=100 вы портите память, т.е. если за массивом будут стоять еще переменными, вот будет веселуха

программирование МК на чистом Си не в тапки ссать, это не када за вас все проверяет VS.

В 16.09.2017 в 08:51, dim3740 сказал:

            Count--;             sei(); //разрешение                          if (Count>=Max)  Count=0;

вот здесь еще веселее

вычитая вы сравниваете на макс. 

 

выше вам дали рабочий пример

Изменено пользователем hasl

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


Ссылка на сообщение
Поделиться на других сайтах
guest87    0
11 hours ago, dim3740 said:

Это не страшно)) Главное, что Вы не пытаетесь учить меня профкодированию, а согласны подойти к проблеме обобщенно.

Если обобщенно, сбоить может или физический уровень (на уровне сигналов), или логический (на уровне софта). Или оба сразу, тогда и профи с ума сойдут.

Quote

 temp=UDR  и сразу UDR=temp. 

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

11 hours ago, dim3740 said:

Я также сейчас выдаю все "от печки", по сути задачи в целом, но и ваши советы проанализирую. Итак. На базе вышеприведенного кода я сделал почти 2 десятка МИДИ устройств за 3 года. И, для любительских задач "1\600" ошибка приемлима. Но, сейчас хотел бы все таки решить этот косяк. Ибо в профоборудовании его не наблюдаю. Кабели те же.

У вас свой физический уровень и софт. Сбоить могут оба. В профоборудовании инженеры делали правильно и то и другое. UART не очень помехоустойчив. По ссылочке которую я дал советуют опторазвязку для MIDI. Соединение устройств с разными сетевыми источниками питания может подкинуть сюрпризов из-за текущих по линиям токов которые вы не заказывали. В случае UART при этом может приняться хрен знает чего.

11 hours ago, dim3740 said:

Другое железо попробовать? МК есть PIC STM  и т.п. Может вообще на AVR нет позитивных результатов ни у кого?

Не думаю что проблема в AVR, с такими проблемами в чипе производители долго не живут. PIC после AVR врядли понравится, разве что PIC32. STM? STM32 крутые и веселые, могут в разы больше, даже те что дешевле. Но НАМНОГО навернутее. Такое там можно на DMA выгрузить - DMA сам будет байты таскать. Но это имеет смысл лишь при ОЧЕНЬ больших потоках, DMA все-равно надо программить а промашки в нем чреваты. К тому же STM32-ы 3.3V-only, в миди как я понимаю 5V в почете, в "электрике" добавится костылей. В общем avr как мне кажется достаточно сбалансированный выбор, если возможностей хватает.

На лично мое мнение я бы проверил "физику" на безглючность в жестких условиях (типа сцены) и если вы хотите продвинутости типа irq и кольцевого буфера, их придется сделать нормально. Разобравшись как это работает и что реально происходит в системе. Вообще отгрохать такую штуку для любителя - неслабо. Если нормально работает :)

11 hours ago, dim3740 said:

Но тогда возникает вопрос об сравнимости "условий" эксперимента. Одно дело компьютерщик-музканант тыкает мышкой на компе, набирая по-нотке. Другое - сцена и игра 10 пальцами, кулаками, и еще и ногами и головой (как я). Тут поток сообщений гораздо выше.

А еще на сцене чего доброго провода длиннее и какая-нибудь силовуха рядом...

11 hours ago, dim3740 said:

 Идея: нужно создать тестовый генератор МИДИ последовательностей с регулируемым периодом посыла. И получить функцию "ошибка от периода".

Можно с второго микроконтроллера послать, хоть в цикле из main без всяких IRQ, конструкцией в духе while (TxC показывает что Tx не занят) {UDR = чтонибудь}. Получите очень плотный поток данных ограниченный только битрейтом. Быстрее некуда. Можно его проредить, воткнув задержки.

11 hours ago, dim3740 said:

А сейчас все идет так: барабаню на клавишах ахинею, - "чем быстрее и больше - тем более вероятна ошибка". И жду, когда она появится.. А она непредсказуема((( Но если появляется - то это конфуз на сцене.... Вот так. Это эмоции))).

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

11 hours ago, dim3740 said:

Далее. Я вообще не могу найти алгоритмов как сделано подобное в проф.девайсах. ПОэтому - все - "от любительского опыта".  Потом выложу код, что "разбор" 3-х байтов (определение стартового = "некого "пакета") и прочее я делаю ПОСЛЕ выхода из п\п уарта. Вы пИшите, что можно сделать его в самой п\п. Это мне нужно понять))) Тут надо оценить и вложенность прерываний, что я пока не анализировал. А мысль, что пока попробовать вообще опросом бита регистра - вообще нова до нельзя!  

Я имел в виду "машины состояний". Когда есть состояния протокола и переходы между ними по неким правилам. Можно в виде диаграммы разрисовать. Обработчик IRQ может смотреть на состояния и даже менять их, если это быстро. Зачем? В лучшем случае фоновая программа может получать относительно готовый пакет и неспешно жевать в фоне, не озадачиваясь как он взялся. Но для миди это наверное не пойдет.

И да, из irq надо вываливаться быстро. Но быстро и мгновенно разные вещи. До того как будет новый такой же IRQ, пройдет минимум 32 мкс. Можно посчитать сколько команд проц выполнит за это время зная частоту (порядка сотен или даже тысяч). Есть еще расходы на сохранение состояния фона при входе в irq и возврат проца в вид как было при выходе, а еще времени должно остаться фону и irq других железок (если они используются).

Вложенные IRQ от одной железки - показатель что вы зашились и не успеваете за реальным временем. Нафиг. Фоновая программа при этом встрянет, кстати, а проц будет только вертеться на прерывания. Поэтому прерывания должны завершаться как можно быстрее и их не должно валиться слишком много. У вас максимум 3125 irq в секунду от uart, на частотах близких к максимуму это вполне ок. Много логики я бы в irq при этом не засовывал.

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


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

Спасибо. Займусь на выходных...пока занят((( Вот из спецификации по приему МИДИ фрагмент:

2017-09-20 19 17 17.jpg

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


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

Создайте аккаунт или войдите в него для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!

Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Похожие публикации

    • Автор: mvdrussia
      Хочу понять суть и смысл цепи обратной связи у TL494. Объясните на пальцах, как первокласснику.
      1. Зачем она нужна и может ли шим работать без неё?
      2. Если не сложно, накидайте словами простую схему с использованием обратки у ШИМа в инверторе УМЗЧ к примеру.
      Только не кидайтесь бананами. Нет у меня желания курить гугл, вычитывать и вдумываться в заумные радиотехнические термины.
    • Автор: LoKeR
      Доброго времени суток, нашел хорошую статью Usart прием и отправка строки. Настроил на порт Usart3 перестал работать, попробовал на Usart2 перекинуть тоже не работает, как правильно переделать подскажите...
      stm32-uart-spl.rar
    • Автор: Тимур1992
      Доброго времени суток.
      Решил пробудить свои скилы по написанию программ под stm32f103. Поигрался с SMT32CUDEMX и HAL, но вернулся к SLP библиотеке.  Начал постепенно наращивать программу по примерам, начиная с GPIO, тактирования и на работе c USART встал. Суть в том что передача по UART идет нормально, а вот прием приводит к "зависанию". Устанавливая бесконечные while с мигалками внутри, я выяснил что по все видимости МК не переходит в прерывания USART1_IRQHandler. Я не могу понять в чем ошибка, раньше с таким не сталкивался, хотя написал несколько программ для stm32f100 .____.
      Среда разработки Atollic TrusStudio 9.0.0.
       
      #include "stm32f10x.h" #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h" #include "stm32f10x_usart.h" #include "misc.h" #include <string.h> // тактовый светодиод для индикации #define LED GPIO_Pin_5 #define RX_BUF_SIZE 80 volatile char RX_FLAG_END_LINE = 0; volatile char RXi; volatile char RXc; volatile char RX_BUF[RX_BUF_SIZE] = {'\0'}; volatile char buffer[80] = {'\0'}; void init_GPIO(void); void SetSysClockTo72(void); void init_uart(void); void clear_RXBuffer(void); void USARTSend(const char *pucBuffer); void USART1_IRQHandler(void) { GPIO_ResetBits(GPIOA, LED); //GPIOA->ODR ^= LED; //USART_ITConfig(USART1, USART_IT_RXNE, DISABLE); //if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { //if ((USART1->SR & USART_FLAG_RXNE) != RESET) { //if ((USART1->SR & USART_SR_RXNE) != (u16)RESET) { if (USART1->SR & USART_SR_RXNE) { // Сбрасываем флаг прерывания USART1->SR &=~ USART_SR_RXNE; //RXc = USART_ReceiveData(USART1); //RX_BUF[RXi] = RXc; //RXi++; //if (RXc != 13) { // if (RXi > RX_BUF_SIZE-1) { // clear_RXBuffer(); // } //} //else { // RX_FLAG_END_LINE = 1; //} //Echo //USARTSend("Interrapt_UART1\r\n"); //USART_SendData(USART1, RXc); } //return } int main(void) { int i; //SetSysClockTo72(); init_GPIO(); init_uart(); USARTSend("Test USART1\r\n"); while (1) { //if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_9) != 0) { /* Toggle LED which connected to PC13*/ GPIOA->ODR ^= LED; // Invert C13 /* delay */ for(i=0;i<0x100000;i++); /* Toggle LED which connected to PC13*/ GPIOA->ODR ^= LED; /* delay */ for(i=0;i<0x100000;i++); USARTSend("Test USART1\r\n"); //} //else { //GPIO_SetBits(GPIOA, LED); //} } } void init_GPIO(void) { // Создаем класс для постепенной настройки параметров и единовременного применени¤ GPIO_InitTypeDef GPIO_InitStructure; //Настрайваем светодиод, включаем тактирование GPIOA RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // Конфигурация для светодиода, режим работы, максимальная скорость GPIO_InitStructure.GPIO_Pin = LED; // GPIO_Mode_Out_OD выход с открытым стоком, GPIO_Mode_Out_PP выход двумя состояниями // GPIO_Mode_AF_OD выход с открытым стоком для альтернативных функций, GPIO_Mode_AF_PP то же самое, но с двумя состояниями GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // Устанавливаем начальное значение SetBits -> High level ("1"), ResetBits -> Low level ("0") GPIO_ResetBits(GPIOA, LED); // Настрайваем пин 9, регистра B на вход, для отладки, включаем тактирование регистра B RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // Настрайваем для кнопку, пин, режим, максимальная частота входного сигнала GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // GPIO_Mode_AIN аналоговый вход, GPIO_Mode_IN_FLOATING вход без подтяжки, болтающийся // GPIO_Mode_IPD вход с подтяжкой к земле, GPIO_Mode_IPU вход с подтяжкой к питанию GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); } void SetSysClockTo72(void) { ErrorStatus HSEStartUpStatus; /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration -----------------------------*/ /* Системный RESET RCC (делать не обязательно, но полезно на этапе отладки) */ RCC_DeInit(); /* Включаем HSE (внешний кварц) */ RCC_HSEConfig( RCC_HSE_ON); /* Ждем пока HSE будет готов */ HSEStartUpStatus = RCC_WaitForHSEStartUp(); /* Если с HSE все в порядке */ if (HSEStartUpStatus == SUCCESS) { /* HCLK = SYSCLK */ /* Смотри на схеме AHB Prescaler. Частота не делится (RCC_SYSCLK_Div1) */ RCC_HCLKConfig( RCC_SYSCLK_Div1); /* PCLK2 = HCLK */ /* Смотри на схеме APB2 Prescaler. Частота не делится (RCC_HCLK_Div1) */ RCC_PCLK2Config( RCC_HCLK_Div1); /* PCLK1 = HCLK/2 */ /* Смотри на схеме APB1 Prescaler. Частота делится на 2 (RCC_HCLK_Div2) потому что на выходе APB1 должно быть не более 36МГц (смотри схему) */ RCC_PCLK1Config( RCC_HCLK_Div2); /* PLLCLK = 8MHz * 9 = 72 MHz */ /* Указываем PLL от куда брать частоту (RCC_PLLSource_HSE_Div1) и на сколько ее умножать (RCC_PLLMul_9) */ /* PLL может брать частоту с кварца как есть (RCC_PLLSource_HSE_Div1) или поделенную на 2 (RCC_PLLSource_HSE_Div2). Смотри схему */ //RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); RCC_PLLConfig(0x00010000, RCC_PLLMul_9); /* Включаем PLL */ RCC_PLLCmd( ENABLE); /* Ждем пока PLL будет готов */ while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) { } /* Переключаем системное тактирование на PLL */ RCC_SYSCLKConfig( RCC_SYSCLKSource_PLLCLK); /* Ждем пока переключиться */ while (RCC_GetSYSCLKSource() != 0x08) { } } else { /* Проблемы с HSE. Тут можно написать свой код, если надо что-то делать когда микроконтроллер не смог перейти на работу с внешним кварцом */ /* Пока тут заглушка - вечный цикл*/ // while (1) { //} } } void init_uart(void) { /* Enable USART1 and GPIOA clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA, ENABLE); /* Configure the GPIOs */ GPIO_InitTypeDef GPIO_InitStructure; /* Configure USART1 Tx (PA.09) as alternate function push-pull */ 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); /* Configure USART1 Rx (PA.10) as input floating */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); /* Configure the USART1 */ USART_InitTypeDef USART_InitStructure; /* USART1 configuration ------------------------------------------------------*/ /* USART1 configured as follow: - BaudRate = 115200 baud - Word Length = 8 Bits - One Stop Bit - No parity - Hardware flow control disabled (RTS and CTS signals) - Receive and transmit enabled - USART Clock disabled - USART CPOL: Clock is active low - USART CPHA: Data is captured on the middle - USART LastBit: The clock pulse of the last data bit is not output to the SCLK pin */ USART_InitStructure.USART_BaudRate = 9600; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, &USART_InitStructure); /* Enable USART1 */ USART_Cmd(USART1, ENABLE); /* Enable the USART1 Receive interrupt: this interrupt is generated when the USART1 receive data register is not empty */ USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); /* NVIC Configuration */ NVIC_InitTypeDef NVIC_InitStructure; /* Enable the USARTx Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); //NVIC_EnableIRQ(USART1_IRQn); } void clear_RXBuffer(void) { for (RXi=0; RXi<RX_BUF_SIZE; RXi++) RX_BUF[RXi] = '\0'; RXi = 0; } void USARTSend(const char *pucBuffer) { while (*pucBuffer) { USART_SendData(USART1, *pucBuffer++); while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) { } } }  
    • Автор: Nitro N
      Здравствуйте! 
      Дано: 
      BLE модуль JDY-10 Гироскоп + Акселерометр модуль GY-521  USB UART CH340G USB bluetooth адаптер Цель:
      передавать сигналы датчика гироскопа и акселерометра через bluetooth модуль на ПК. Мои рассуждения:
      Модуль GY-521 имеет I2C интерфейс, на JDY-10 стоит МК CC2541 который тоже имеет I2C интерфейс. Надо как-то их соединить и заставить отправлять показания на ПК. Как это сделать пока мне не понятно. Иногда приходят мысли что без перепрошивки контроллера не обойтись. 

      Подскажите пожалуйста как это реализовать?

      П.С. В идеале вообще конечно использовать один контроллер для снятия значений и отправки на ПК, но пока так. 
    • Автор: vimay
      Господа Ланзаростроители. Дабы не засорять ветку по основному Ланзару предлагаю здесь делиться своими идеями по доработке базовой схемы. Мое предложение - инвертирующее включение + буфер на входе. Начало обсуждения здесь.
      Итак, в продолжение дискуссии...
      @finn32 , несколько вопросов по модели:
      1. В чем было дело?
      2. Искажения не великоваты?