Forum: Digitale Signalverarbeitung / DSP / Machine Learning Falsche Bytefolge bei UART-Übertragung


von Robert M. (andro86)


Lesenswert?

Hallo zusammen.

Ich arbeite gerade an einem Projekt bei dem ich eine Stromregelung auf 
einem FPGA (Altera Cyclon IV) implementiert habe. Über eine in MatLab 
entworfene GUI gebe ich den Sollwert vor. Die Übertragung von MatLab zum 
FPGA geschieht über UART. Nachfolgend die Codes die ich geschrieben 
habe.

Der MatLabcode für die GUI:
1
function Current_Source_Control_GUI_OpeningFcn(hObject, eventdata, handles, varargin)
2
3
handles.output = hObject;
4
5
guidata(hObject, handles);
6
7
global serialPort;
8
serialPort = [];  %Initialisiere serialPort mit Nullen.
9
10
global USB_COM_Port;
11
USB_COM_Port = handles.USB_COM_Port;
12
13
global connect_COM_Port;
14
connect_COM_Port = handles.connect_COM_Port;
15
16
guidata(hObject, handles);
17
18
19
% --- Executes on selection change in USB_COM_Port.
20
function USB_COM_Port_Callback(hObject, eventdata, handles)
21
22
USB_COM_Port
23
24
guidata(hObject, handles);
25
26
27
% --- Executes on button press in connect_COM_Port.
28
function connect_COM_Port_Callback(hObject, eventdata, handles)
29
30
global serialPort;
31
global USB_COM_Port;
32
global connect_COM_Port;
33
34
set(handles.static_USB_COM, 'String', get(USB_COM_Port, 'String'));
35
36
37
instrfind()%:= Finde alle Serial-Port-Objekte, die existeren.
38
if ~isempty(instrfind) % Finde herraus, ob irgendein Serial-Port in Ver-
39
    fclose(instrfind)  % wendung ist, wenn ja schließe es!
40
end
41
42
%------------------------ Erzeuge USB-Serial Port ------------------------%
43
if(isempty(serialPort))
44
    try
45
                 % Erzeuge ein serial Port Objekt mit dem Namen "serialPort".
46
                 % Verbinde Objekt mit dem USB-Com-Port.
47
        serialPort = serial(get(USB_COM_Port, 'String'), 'BaudRate', 9600); % Setze Übertragungsrate auf 19200.
48
    
49
        serialPort.Parity = 'none'; % Prüfung auf gerader Parität.
50
        serialPort.Databits = 8;    % Setze die Anzahl, der zu übertragenden Bits auf 8.
51
        serialPort.StopBits = 1;    % Zwei Bits, die das Ende einer Nachricht signalisieren.
52
    
53
        serialPort.BytesAvailableFcnMode = 'byte';  % Legt fest, dass ein BytesAvailable event ausgelöst wird, sobald
54
                                                    % eine festlegbare Anzahl an ankommenden Bytes erreicht wurde.
55
        serialPort.BytesAvailableFcnCount = 1;      % Legt die Anzahl der ankommenden Bytes fest, um ein BytesAvailable
56
                                                    % event zub sarten.
57
        serialPort.BytesAvailableFcn = @incomingAcknowledgment  % Sobald ein BytesAvailable event vorliegt, sprich so-
58
                                                                % bald ein Byte im Input-Buffer ankommt, erfolgt der
59
                                                                % Aufruf der Callback-Function incomingAcknowledgment.
60
        %disp('Serialobjekt erzeugt');
61
        if(~isempty(serialPort))
62
            try
63
                 fopen(serialPort);  % Verbinde das serial Port Objekt serialPort mit dem Port-Gerät.
64
                                     % Schreibt handles.Iref als binäre Daten in den USB-COM-Port, welches
65
                                     % mit dem serial Port Objekt 'serialPort' verbunden ist. Der verwendete 
66
                                     % Datentyp ist hier als 'float' gewählt.
67
                                     % fwrite(serialPort, handles.Iref,'float');
68
                 boxhandle=msgbox(['Verbindung hergestellt.']);
69
                 waitfor(boxhandle);
70
                 disp('Verbindung hergestellt');
71
                 get(serialPort,{'Name', 'Status', 'Port'}); 
72
                 
73
            catch exc
74
                 boxhandle=msgbox(['Objekt serialPort is leer. ' exc.identifier ';' exc.message]);
75
                 waitfor(boxhandle);
76
            end
77
        end
78
        
79
    catch exc
80
        boxhandle=msgbox(['Fehler beim Herstellen der Verbindung: ' exc.identifier ';' exc.message]);
81
        waitfor(boxhandle);
82
        serialPort=[];
83
    end
84
else
85
    try
86
        fclose(serialPort);    % Trennt das serial Port Objekt 'serialPort' vom USB-COM-Port Gerät.
87
        boxhandle=msgbox(['Verbindung beendet.']);
88
        waitfor(boxhandle);
89
        disp('Verbindung beendet');
90
        get(serialPort,{'Name', 'Status', 'Port'})
91
        
92
    catch exc
93
        boxhandle=msgbox(['Fehler beim Beenden der Verbindung: ' exc.identifier ';' exc.message]);
94
        waitfor(boxhandle);
95
    end
96
    serialPort=[];
97
end
98
99
if(isempty(serialPort))
100
    set(connect_COM_Port, 'string', 'Verbindung herstellen');
101
else
102
    set(connect_COM_Port, 'string', 'Verbindung beenden');
103
end
104
105
guidata(hObject, handles);
106
107
108
% --- Executes on button press in Send.
109
function Send_Callback(hObject, eventdata, handles)
110
111
global serialPort;
112
%global USB_COM_Port;
113
114
      fwrite(serialPort, [11, 23, 32, 44], 'uchar');
115
116
117
guidata(hObject, handles);

Und hier der Code, den ich auf dem Nios-Prozessor implementiert habe:
1
#include <stdio.h>
2
#include <unistd.h>
3
#include<stdint.h>
4
#include <string.h>
5
#include "system.h"
6
#include "alt_sys_init.h"
7
#include "altera_avalon_pio_regs.h"
8
#include "altera_avalon_timer_regs.h"
9
#include "altera_avalon_timer.h"
10
#include "altera_avalon_uart.h"
11
#include "sys/alt_irq.h"
12
#include "main.h"
13
#include "clk_timer.h"
14
#include "communication.h"
15
16
17
     // Create a pointer for UART communication. FILE is an object for storing
18
     // information for a file stream.
19
 FILE* uart_pointer;
20
21
  unsigned short received_uart_message;
22
  unsigned short crc_checksum_value;
23
24
25
 int main();
26
27
 void init(void)
28
 {
29
   /*---------------------- Initialisiere UART-Schnittstelle -----------------------*/
30
      /* The HAL system library API provides a complete access to the UART core's
31
         features by treating the UART core as a character mode device, and send
32
         and receive data using the C standard library.
33
         File fopen(const char *filename, const char* mode) opens the filename pointed
34
         to, by filename using the given mode. Mode "r+" = opens a file to update both
35
         reading an writing.*/
36
   uart_pointer = fopen("/dev/uart", "r+");  // Öffnet das UART-Gerät.
37
   if(uart_pointer)
38
   {
39
     printf("Initialization of the UART interface successful \n\n ");
40
   }
41
   else
42
   {
43
     printf("Initialization of the UART interface failed \n\n");
44
   }
45
46
 }
47
48
 int main()
49
 {
50
   init();
51
52
  while(1)
53
  {
54
        }
55
56
    received_uart_message = get_uart_message(uart_pointer);
57
    printf("Angekommene UART-Nachricht: %d\t", received_uart_message);
58
59
60
  }
61
62
void get_uart_message(FILE* uart_pointer)
63
 {
64
   unsigned short read_message;
65
   char message_array[] = {0,0,0,0};    /* Array mit 4 Feldern für die ankommende
66
                                   32-Bit Nachricht. */
67
   unsigned short rx_uart_message0;    /* Hilfsvariable zur Sortierung der ankommenden
68
                                   Bytes. */
69
   unsigned short rx_uart_message1;    /* Hilfsvariable zur Sortierung der ankommenden
70
                                      Bytes. */
71
   unsigned short rx_uart_message2;    /* Hilfsvariable zur Sortierung der ankommenden
72
                                      Bytes. */
73
   unsigned short rx_uart_message3;    /* Hilfsvariable zur Sortierung der ankommenden
74
                                      Bytes. */
75
76
77
   read_message = fread(&message_array, sizeof(char), sizeof(message_array), uart_pointer);
78
79
   if (read_message != sizeof(message_array))    // Konnten alle Bytes gelesen werden?
80
   {
81
    printf("Es ist ein Fehler beim Auslesen der UART-Schnittstelle aufgetretten. \n");
82
   }
83
   else
84
   {
85
    rx_uart_message0 |= message_array[0];
86
    rx_uart_message1 |= message_array[1];
87
    rx_uart_message2 |= message_array[2];
88
    rx_uart_message3 |= message_array[3];
89
90
    printf("Angekommene UART-Nachricht 1.Byte: %d\n", received_uart_message0);
91
    printf("Angekommene UART-Nachricht 2.Byte: %d\n", received_uart_message1);
92
    printf("Angekommene UART-Nachricht 3.Byte: %d\n", received_uart_message2);
93
    printf("Angekommene UART-Nachricht 4.Byte: %d\n", received_uart_message3);
94
95
    printf("UART-Schnittstelle erfolgreich ausgelesen.\n");
96
   }
97
 }
98
99
  return 0;
100
 }

Im Endeffekt habe ich vor, über Matlab eine 32-Bit Nachricht zu 
verschicken. Zum Empfang dieser Nachricht habe ich im Nios ii Prozessor 
ein Array mit 4 Feldern implementiert, wo der Reihe nach Byte für Byte 
der 32-Bit Nachricht abgespeichert werden.
Zum testen habe ich die Werte [11 23 32 44] rüber geschickt. Folgendes 
Ergebnis habe ich erhalten:
1. Byte = 0
2. Byte = 11
3. Byte = 23
4. Byte = 32.
Es scheit so als ob mein Array erst ab den zweiten Feld gefüllt wird und 
der letzte Wert, die 44 dabei verloren gehen. Doch wenn ich umittelbar 
danach die selben Wert erneut sende, erhalte ich folgendes Ergebnis:
1. Byte = 44
2. Byte = 11
3. Byte = 23
4. Byte = 32.
Der letzte Wert schein nun im ersten Feld meines Arrays gespeichert zu 
werden und soltte dabei eigentlich im letzten Feld gespeichert werden.

Meine Theorie ist, vor dem erstmaligem Senden wird durch den 
Programmablauf der Rx-Buffer ausgelesen und der leere Bufferwert im 
ersten Feld meines Arrays gespeichert. Nachdem ich die Zahlenfolge 
gesendet habe, werden die ersten drei Zahlen in den restlichen Felder 
meines Arrays gespeichert. Der letzte Wert hat nun kein freies Feld 
mehr, in das es abgelegt werden kann, also wird es im Rx-Buffer zwischen 
gespeichert bis zum nächsten Empfang der Zahlenfolge. Wenn nun die 
Zahlenfolge erneut ankommt, wird der Rx-Buffer ausgelesen, in dem zuvor 
der letzte Wert gespeichert wurde und diesmal im ersten Feld meines 
Arrays abgespeichert.
Was ich schon probiert habe ist, denn Buffer erst dann auszulesen, 
nachdem ich die Zahlenfolge gesendet habe, doch das Ergebnisse war das 
selbe.

Nun hoffe ich, dass ihr mir sagen könnt, was ich machen kann, damit 
meine gesendete Zahlenfolge in der richtigen Reihenfolge in meinem Array 
abgespeichert wird.

von Kanack (Gast)


Lesenswert?

Was du da hast ist kein Buffer, sondern ein Array! Das ist ein 
klassischer Fehltritt. Oftmals wird bei der Initialisierung 
fälschlicherweise ein byte gesendet und schon läuft nix. Erhöhe den 
Buffer auf 256 und schreibe ein Protokoll mit einen Header und 
Terminator.
1
 while(1)
2
  {
3
    received_uart_message = get_uart_message(uart_pointer);
4
    printf("Angekommene UART-Nachricht: %d\t", received_uart_message);
5
  }
6
7
void get_uart_message(FILE* uart_pointer){

"get_uart_message" ist von typ !void. Ein kleines delay bei der while 
Schleife wäre für ein Testdurchlauf nicht schlecht.

von Robert M. (andro86)


Lesenswert?

Erstmal danke für deine Antwort Kanack.


Kanack schrieb:
> Was du da hast ist kein Buffer, sondern ein Array!

Mein Altera besitzt zwei Register, ein Holding- und ein Shiftregister. 
Ankommende Nachrichten kommen zuerst ins Holding Register bevor sie ans 
Shift Register weitergegeben und ausgelesen werden. Das meinte ich mit 
Buffer. Sorry ich hätte da vielleicht etwas ausführlicher werden sollen.


Kanack schrieb:
> Das ist ein klassischer Fehltritt. Oftmals wird bei der Initialisierung
> fälschlicherweise ein byte gesendet und schon läuft nix. Erhöhe den
> Buffer auf 256 und schreibe ein Protokoll mit einen Header und
> Terminator.

Sorry ich muss dann nochmal nachfragen. Welchen Buffer meinst du?
Also soll ich jetzt jede Nachricht mit einem Header ausstatten an der 
mein Nios II Prozessor erkennt, ob die Nachricht angenommen oder wieder 
verworfen werden soll. Das klingt logisch, danke.


Kanack schrieb:
>
1
>  while(1)
2
>   {
3
>     received_uart_message = get_uart_message(uart_pointer);
4
>     printf("Angekommene UART-Nachricht: %d\t", received_uart_message);
5
>   }
6
> 
7
> void get_uart_message(FILE* uart_pointer){
8
>
>
> "get_uart_message" ist von typ !void. Ein kleines delay bei der while
> Schleife wäre für ein Testdurchlauf nicht schlecht.

Ups, da ist mir ein Fehler unterlaufen. Die Funktion sollte eigentlich 
vom Typ
1
 unsinged short get_uart_message(FILE* uart_pointer){
 sein.

von Kanack (Gast)


Lesenswert?

Servus,
du hast zwei Programme geschrieben und somit sind zwei Fehlerquellen 
möglich.

Lade dir ein Terminal Programm wie hTerm und such nach den Fehler.

Weiterhin rate ich dir einen fifo Buffer mit einen Protokoll zu 
erstellen, damit die Fehlerwahrcheinlichkeit minimiert wird. Bei 
konstanter Wortlänge reicht ein header oder terminator oftmals für erste 
aus.

mfg

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.