RSS
people

Meine Werkzeuge: Logic Analyzer

Heute werden wir über die Werkzeuge sprechen, die uns in der so spannenden und interessnanten Sache wie Erfinden von etwas interessantes und spannendes helfen können. Und gerade jetzt sprechen wir über einen meiner letzten Werkzeuge — Logikanalysator

Alte gute Wikipedia sagt uns, dass «Ein Logikanalysator (engl. Logic Analyzer) ist ein elektronisches Gerät, das den Zeitverlauf von Signalen aus einer digitalen Schaltung bildlich darstellt.» Genau das mach mein Analysator — zeichnet die Signale auf, und später stellt die bildlich dar.

So sieht das Gerät von Aussen:

Логический анализатор - общий вид

Eigentlich — nichts besonderes — 8 Leitungen mit Tastköpfen für die Signale selbst (rot) und 9. Leitung für GND (schwarz)

Man schließt das Wundergerät an USB Port am PC an. Und das wird als virtuelles COM-Port erkannt. Weil ich hier einen USB <-> Seriellen Konverter benutzt habe. FTDI FT232BM. Wenn wir die Schaltung anschauen, dann werden wir nicht viel da sehen. Einen Mikrokontroller ATMega 128 und USB Kontroller FT232BM.

Die LEDs, die neben dem USB Konnektor platziert sind, zeigen uns, was das Gerät gerade macht.

  • P — Power — Hier ist alles klar — Strom gibt es, habe Sache ist erledigt.
  • A — Armed — Bereit — warten auf den bestimten Erreignis, um weiter zu arbeiten.
  • T — Triggered — Erreignis ist passiert — die Aufzeichnung läuft.
  • S — Send — Senden die Pakete — die Aufzeichnung ist zu Ende — senden

Und so sieht das Gerätchen innen drin:

Внутренности логического анализатора - вид сверху
Внутренности логического анализатора - вид снизу

Natürlich, für die richtige Funktionierung braucht das Gerät eine Frimware — das Programm, das für uns die Aufzeichnungen der Signalen machen wird und an uns senden wird.

Das Programm habe ich, wie man sagt, «auf der Schnelle» zusammen gebaut. Desswegen gibt es da nicht so viel Kommentaren. Aber die wichtigste Puntknte werden wir jetzt durchgehen.

Das wichtigste Teil des Programms, über die Sie sich wahrscheinlich interessieren werden, ist die Funktion der Aufzeichnung der Signale

Auf dem Schaltplan sieht das Teil so aus:

Схема логических входов

Im Prinzip — nichts kompliziertes. Manche Leserinen und Leser werden merken — es gibt keinen Eingangsschutz. Ja — gibt es keine. Aber dafür gibt es von mir einpaar Aussagen: Erstens — ich habe den Werkzeug «auf der Schnelle» gemacht, um eine andere Projekt zu untersuchen. Und zweitens — ich weiss, dass da keine Eingangsschutz gibt, und deswegen stecke ich die Tastköpfe nirgenwo rein, wo ich nicht weiss, was da für eine Spannung ist. 

Also, die Schaltung ist ganz einfach. Alles was wir brauchen ist im Programm nur den PORTC auslesen. Das Lesevorgang ist in der Timer-Funktion passiert.

  1. SIGNAL(SIG_OVERFLOW1)
  2. {
  3.  u08 register bByte;
  4.  outp(AnalyzerConfig.u16TimerCounter.bytes.high, TCNT1H);  // load counter value hi
  5.  outp(AnalyzerConfig.u16TimerCounter.bytes.low,  TCNT1L);  // load counter value lo
  6.  if (!gFlags.bDataHere)
  7.  {
  8.    // PORTB = PINB | 0x02;
  9.    bByte = ANALYZER_PINS;
  10.    if (!gFlags.bTrigger && !gFlags.bStopTriggering)
  11.    {
  12.      if (AnalyzerConfig.bTriggerType != TT_NO_TRIGGER)
  13.      {
  14.        if (AnalyzerConfig.bTriggerType == TT_FALLING_EDGE)
  15.        {
  16.          if (
  17.                 (bOldByte & bTrigMask)
  18.              && ((bByte & bTrigMask) == 0)
  19.             )
  20.          {
  21.             gFlags.bTrigger = 1;
  22.          }
  23.        }
  24.        else
  25.        {
  26.          if (
  27.                  ((bOldByte & bTrigMask) == 0)
  28.               && (bByte & bTrigMask)
  29.             )
  30.          {
  31.             gFlags.bTrigger = 1;
  32.          }
  33.        }
  34.      }
  35.      else
  36.      {
  37.        gFlags.bTrigger = 1;
  38.      }
  39.      bOldByte = bByte;
  40.    }
  41.    bAnalyze[wAnWriteIndex] = bByte;
  42.    if (gFlags.bTrigger && !gFlags.bStopTriggering)
  43.    {
  44.      LED_TRIGGER_ON;
  45.      LED_ARMED_OFF;
  46.      if(wAnWriteIndex < AnalyzerConfig.wMaxBytesToStore - 1)
  47.        wAnWriteIndex++;
  48.      else
  49.      {
  50.        gFlags.bDataHere = 1;
  51.        gFlags.bStopTriggering = 1;
  52.      }
  53.    }
  54.    else
  55.    {
  56.      LED_TRIGGER_OFF;
  57.    }
  58.    // PORTB = PINB & ~0x02;
  59.  }
  60. }

Ganze Lesevorgang besteht aus zwei Teilen — von 103. bis 136. Zeilen wird auf das Ereignis gewartet wenn nötig ist. Und zweite Teil von 138. bis 153. Zeile — hier wird die Calculation des Indexes des Arrays statt finden, in dem wir früher (am Anfang der Funktion auf der Zeile 105.) den PORTC Wert gespeichert haben.

In dem ersten Teil wird auf das Auslösungsereignis gewartet, aber nur dann, falls das noch nicht passiert. Darüber sagt uns der Flag gFlags.bTrigger. Fals der Flag noch nicht steht, dann prüfen wir die Auslöserbedinung — Änderung des Bits von 0 zu 1 oder von 1 zu 0.

Diese Parameters sind in dem Controlprogramm einzustellen. Darüber werde ich hier später erzählen.

Weiter, wenn wir die Beidenung des Auslösers definiert haben und die Bedienung ist eingetretten, wird eigentliche Speicherung der Daten passieren, und es wird der nächste Elementeindex kalkuliert. Wen es genug Daten gespeichert wurde, wird ein Flag gesetzt, dass die Daten da sind, und es die Zeit ist, die loszuschiecken: gFlags.bDataHere = 1; und gFlags.bStopTriggering = 1

Das Senden ervolgt in der main ():

  1.   if (gFlags.bDataHere)
  2.   {
  3.     LED_SEND_ON;
  4.     uart_putchar(UART_SYNC_BYTE);
  5.     uart_putchar(0xEF);
  6.     uart_putchar(UART_SYNC_BYTE);
  7.     uart_putchar(0x55);
  8.     uart_putchar(wAnWriteIndex);
  9.     uart_putchar(wAnWriteIndex >> 8);
  10.     u16 i;
  11.     u08 * bData = AnalyzerGetBuffer();
  12.     for (i = 0; i <= wAnWriteIndex && gFlags.bDataHere; i++)
  13.     {
  14.       SWdtReset    = 1;
  15.       uart_putchar(bData[i]);
  16.     }
  17.     wAnWriteIndex = 0;
  18.     gFlags.bDataHere = 0;
  19.     if (AnalyzerConfig.bTriggerType == TT_NO_TRIGGER)
  20.     {
  21.       gFlags.bTrigger = 1;
  22.       gFlags.bStopTriggering = 0;
  23.       LED_ARMED_ON;
  24.     }
  25.     else
  26.     {
  27.       if (AnalyzerConfig.bTriggerRepeat)
  28.       {
  29.         gFlags.bTrigger = 0;
  30.         gFlags.bStopTriggering = 0;
  31.         LED_ARMED_ON;
  32.       }
  33.     }
  34.     LED_SEND_OFF;
  35.   }

Hier werden erst einpaar Bytes weggeschickt, die werden der Kontrolporgramm sagen, dass gerade jetzt werden die Daten kommen, und nicht einen Text. Nach der Sync Bytes schicken wir die Länge der Daten, damit auf der anderen Ende wissen, wieviel Bytes von uns zu erwarten. Und dann, in einer Zyklus, werden die Daten geschickt. 

Dass ist die funktionalität des Gerätes.

Ganz kurz über die Einstellungen der Parameters bei dem Kontrolprogramm.

Datenempfang ist mit der Hilfe des UART Interrupts gemacht wurde.

  1. /* signal handler for receive complete interrupt */
  2. SIGNAL(SIG_UART0_RECV)
  3. {
  4.     uart_rxd_buffer[uart_Write_in_Index] = UDR0;
  5.     if (uart_rxd_buffer[0] == UART_SYNC_BYTE)
  6.     {
  7.       //*uart_rxd_in_ptr = ~(*uart_rxd_in_ptr);
  8.       uart_Write_in_Index++;
  9.       if (uart_Write_in_Index >= sizeof(TCommData))
  10.       {
  11.          LED2_OFF;
  12.          LED3_OFF;
  13.          LED4_OFF;
  14.          ProcessData((TCommData *)uart_rxd_buffer);
  15.          uart_Write_in_Index = 0;
  16.          uart_rxd_buffer[0] = 0;
  17.       }
  18.       if(uart_Write_in_Index >= UART_BUF_SIZE)
  19.        uart_Write_in_Index = 0;
  20.     }
  21.     else
  22.     {
  23.       uart_Write_in_Index = 0;
  24.     }
  25. }

Hier empfangen wird die Daten bis der Buffer voll ist. Der Empfang startet nur, wenn wir ein Syncbyte empfangen werden. Damit wird jeglicher Mühl und Rausch aussortiert. Wenn Buffer voll wird, werden die empfangene Daten untersucht:

  1. void ProcessData(TCommData * CommData)
  2. {
  3.   if (CommData->bSyncByte == UART_SYNC_BYTE)
  4.   {
  5.     switch (CommData->bCmd)
  6.     {
  7.       case UART_TRIGGER_RESET:
  8.  
  9.       break;
  10.       case UART_TRIGGER_SET:
  11.         AnalyzerConfig.bTriggerBit           = CommData->AnCfg.bTriggerBit;
  12.         AnalyzerConfig.bTriggerType          = CommData->AnCfg.bTriggerType;
  13.         AnalyzerConfig.bTriggerRepeat        = CommData->AnCfg.bTriggerRepeat;
  14.       break;
  15.       case UART_TIMER_SET:
  16.         AnalyzerConfig.bTimerPrescaler       = CommData->AnCfg.bTimerPrescaler;
  17.         AnalyzerConfig.u16TimerCounter.value = CommData->AnCfg.u16TimerCounter.value;
  18.       break;
  19.       case UART_SET_WIDTH:
  20.         if (CommData->AnCfg.wMaxBytesToStore <= AN_MAX_ANALYZES_BUFFER)
  21.         {
  22.           AnalyzerConfig.wMaxBytesToStore      = CommData->AnCfg.wMaxBytesToStore;
  23.         }
  24.       break;
  25.       case UART_SET_ALL:
  26.         AnalyzerConfig.bTimerPrescaler       = CommData->AnCfg.bTimerPrescaler;
  27.         AnalyzerConfig.u16TimerCounter.value = CommData->AnCfg.u16TimerCounter.value;
  28.  
  29.         AnalyzerConfig.bTriggerBit           = CommData->AnCfg.bTriggerBit;
  30.         AnalyzerConfig.bTriggerType          = CommData->AnCfg.bTriggerType;
  31.         AnalyzerConfig.bTriggerRepeat        = CommData->AnCfg.bTriggerRepeat;
  32.  
  33.         if (CommData->AnCfg.wMaxBytesToStore <= AN_MAX_ANALYZES_BUFFER)
  34.         {
  35.           AnalyzerConfig.wMaxBytesToStore      = CommData->AnCfg.wMaxBytesToStore;
  36.         }
  37.       break;
  38.     }
  39.     AnalyserSetupTimer();
  40.   }
  41. }

Hier gibt es nichts besonderes, nur Zuweisungen aus einer Strukt in eine andere.

Das Ganze ist aber nur in diesem kleinen schwarzen Körbchen passiert und nicht so spanned, wiel man sieht nicht viel. Und jetzt erzähle ich über das Kontrolprogramm, das Frontend

So sieht das Hauptfenster des Programms aus:

Главное окно программы

Im Prnizip — alles ist einfach. Links unten kann man die Anzahl der Kanäle einstellen. Maximale Anzahl bei dem Programm ist 16, aber unser Gerät unterstützt und sendet nur 8 dafon.

Ein bisschen unten sind die Vergrößerungs- und Verkleinerungsknöpfe. Weiter rechts ist die Gruppe der Ereignissenstellungs — Trigger. In der Gruppe kann man den Kanal wählen, auf welchem auf das Ereignis gewartet wird, den Ereignistype wählen — von 0 zu 1 - Rising edge oder von 1 zu 0 Falling edge oder überhaupt nicht darauf warten. Häckhen Repeat triggering sagt dem Gerät, dass es nicht schlechе wäre, nach dem gefangenen Ereigniss, auf einen weiteren zu warten.

Knopf Set in der Gruppe sendet den Befehl zu dem Gerät und setzt nur diesen Parameter.

Die nächste Gruppe  Sampling setzt die Paramers des Samplings — die Frequenz des Auslesen der Tastköpfe. Sample time ist die Wartezeit, nach dem das nächste Lesen passiert. Die kann man grob mit der Hilfe des Schiebers einstellen, der ein Stuck nach unten ist, oder genauer, mit der Tasten «Nach Oben» und «Nach Unten», auf der rechten Seite des Eingabefeldes. Minimaler Wert ist 5 Mikrosekunden. und maximaler ist 10 Sekunden

Knöpfhen  Set Timer in der Gruppe sendet den Befehl zu dem Gerät und setzt nur diesen Parameter. Interessant ist, dass die Kalkulation der Werte des Timers passiert in dem Programm, und gesendet werden schon nur die Registerwerte, die im Gerät direckt übernommen werden.

Samples — Anzahl der Auslese in einer Sendung, die erst gelesen werden, und anschließend vom Gerät zum Programm gesendet. Minmal is 1, maximal ist 3072.

Die Werte kann man vom Tastatur eintippen, oder mit der Tasten «Nach Oben» und «Nach Unten», auf der rechten Seite des Eingabefeldes ändern. 

Und die ganz große Taste - Set All. Sended alle Parameters zu dem Gerät in einem Rutsch.

Weiter rechts ist ein Informationsfeld Time/Div, in dem gegenwärtige Auflösung des Kanalbildschirmes angezeigt wird. Sekunden pro Kästchen.

Und ganz recht — einige Debugmeldungen für mich.

Im Menü gibt es nicht viel interessantes, nur die Einstellungen der Kommunikation — Communication Settings:

Настройки последовательного порта

Hier ist alles klar. Man mus für unseren Gerät einen Port wälen, dessen Nummer bringt uns der Gerätemanager. In dem muss man den Punkt «Anschlüße (COM und LPT)» wälen. Hier taucht unser USB <-> Seriel Converter auf, wenn wir das Gerät an dem PC's USB Port anschließen.

In den Programmtext werden wir uns nicht vertiefen, da es schon Programmierung unter Windows ist, in dem ich nicht so stark bin. Aber wenn jeman eine Frage darüber hat, gerne würde ich die in weiteren Folgen und Artikeln auf meiner Seite antworten.

Das Programm wurde mit der Hilfe des Borland C++ Builder 5 erstellt, und es kann passieren, dass das einige Bibliotheken verlangen wird.

Und wie immer, am Ende der Story, die Liste der Dateien, die hier erwähnt wurde: 

15 комментариев к “Meine Werkzeuge: Logic Analyzer”

  1. di-halt.livejournal.com/ пишет:

    Какая частота опроса?

  2. MasterAlexei пишет:

    Там в тексте — в описании программы самой есть :

    «Следующая группа Sampling устанавливает параметры сэмплирования — частоты чтения пробников. Sample time — это время задержки, с которой будет происходить счетние сигналов. Его можно установить грубо с помощью ползунка, что чуть ниже, и более точно с помощью кнопочек вверх/вниз, что справа. Диапазон значений от 5 микросекунд до 10 секунд.»

    Т.е. Максимальная частота опроса — 200 kHz (1 / 5 микросекунд). Минимальная — 100 Hz (1 / 10 секунд).

  3. Gre-kir пишет:

    Добрый день Алексей, можно ли спаять на АТмега 64 даную конструкцию? Есть ли ограничение по количеству отчетов для записи в программе? На чем написан исходник AVR на С?

  4. MasterAlexei пишет:

    Думаю, что конструкцию спаять можно. Надо будет только подправить исходники на другой процессор. Возможно, что имена регистров не будут совпадать со 128й атмегой. Особенно это касается USART.

    Ограничение по количеству отчетов есть — 3072 байта. Это число я взял примерно, посмотрев, сколько памяти надо для моих внутренних переменных и стека и все оставшееся отдал под массив считываемых данных. Так как у 64й атмеги тоже 4 кб РАМ, то этот параметр можно не менять.

    Исходники на GNU WinAVR — С.

  5. Gre-kir пишет:

    Добрый день, Алексей. Спаял по вашей схеме анализатор, только не могу запустить. При включении загорается светодиод на 15 ноге Меги, на 17 ноге мигает с частотой 10 раз в секунду, Я припаял к конвертеру USB-COM два светодиода RX, TX и по ним наблюдаю обмен данными. прибор постоянно передает посылки данных но программа их не принимает. Передача настроек с программы проходит (вижу по светодиоду). Но светодиоды А и Т не горят вообще. Частота генерации кварца Меги 8 Мгц (проверял мультиметром). Может-быть вспомните какие биты прописаны в Меге? Или знаете в чем проблема. Прибор очень необходим. Жду ответа. Заранее благодарен

  6. MasterAlexei пишет:

    Здравствуйте, Gre-kir!

    Тут в схеме есть небольшой косячек, но лечится относительно легко. Косяк в том, что на схеме указана частота кварца — 8 Мгц. А софт расчитан на кварц 16 Мгц. Просто я, когда разрабатывал это все — то просто скопировал кусок схемы с одного из своих проектов, и забыл подправить номиналы. А заметил только когда уже выставил на сайт.

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

  7. MasterAlexei пишет:

    Еще попутно вопрос — вы сделали анализатор на базе именно меги 128 или все же мегу 64ю взяли?

  8. Gre-kir пишет:

    Решил не искушать судьбу, поставил 128, сегодна кварц моменяю, сообщу о резулультатах...

  9. Gre-kir пишет:

    Заменил кварц- заработало. Хорошая штука. Только нет возможности записать снятые данные- я по крайней мере не смог. Как скинуть график ??

  10. MasterAlexei пишет:

    Рад, что понравилась вещь. :)

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

  11. vesel пишет:

    Спасибо за конструкцию,отличная вещь. Давно хотел подобное сварганить да только вот программирование для «большого брата» останавливало. Максимум что могу так это на VBA под SQL «морду» сделать. Обидно что не прочитал сразу отзывы а развел плату без кварца (посмотрел что 8мгц на схеме) и включил внутренний генератор. Пришлось внешний генератор подключать ))

    То что на 128 меге построено — отлично. Не задумывались добавить и считывание АЦП ? Удобственно выглядело бы еще и видеть например напряжение или еще что либо )) Удачи. Еще раз спасибо за конструкцию.

  12. MasterAlexei пишет:

    Классно, что железка оказалась полезной.

    Про АЦП — хм. Пока не думал, так как все же АЦП — это уже немного другой прибор, другая схемотехника должна быть и т.д. Вот чего я сейчас с этим анализатором делаю — так это SPI докручиваю. Теперь он у меня будет как SPI логгер, тестер. Т.е. можно будет либо послать пару тройку байт в SPI либо считать их. Все, что нужно будет — это добавить проводок до PB1 (SS) пина, да и то, это если нужна возможность работы в режиме Slave.

    Ну и перепрошить контроллер. GUI тоже изменится немного, но не сильно. Так что ждите, скоро будет!

  13. vesel пишет:

    ЫЫЫЫ )))

    Видать не зря я при разводке платы вывел SPI разьемчик ))) Не зряяя)))

  14. Мои инструменты: Logic Analyzer V. 2.0 | Fun Electronic пишет:

    [...] Ну я не долго думал и малость усовершенствовал свой Логический анализатор и добавил к нему новую [...]

  15. Новая версия Логического Анализатора, с возможностью добавления плагинов | Fun Electronic пишет:

    [...] обработки данных. Но пока часть анализатора для старого железа уже работает более менее стабильно, что не может не [...]

Оставить комментарий или два

Пожалуйста, зарегистрируйтесь для комментирования.