Forum: PC-Programmierung USART in Matlab zu langsam


von Daniel V. (voda) Benutzerseite


Lesenswert?

Hallo liebes Forum,

ich versuche mit meinem selbstentwickelten Testsystem, Bilddaten eines 
ADNS390 auszulesen und in Matlab einzulesen um diese Daten später 
weiterzuverarbeiten.

Mein Testsystem sieht folgendermaßen aus:

Mit dem Bildsensor ADNS 3090 von PixArt, 8 Bit, 30 x 30-Matrix

lese ich die Daten per SPI von einem STM32F4 aus und diese werden auf 
eine USART weitergeleitet. Auf der Platine selber habe ich einen FTDI-IC 
verbaut. In HTerm und auf dem Oszilloskop bzw. mit einem LA kann ich die 
Bilddaten sehen. In derzeitiger Konfiguration (30x30x8 Bit) liegen ca. 
60 fps auf den Bus.

Mein Lösungsansatz ist folgender: Ich erzeuge in Matlab eine 
30x30-Matrix und diese Matrix fülle ich mit den Werten, die ich von der 
seriellen Schnittstelle bekomme. Mit dieser Matrix werde ich weitere 
mathematische Operationen durchführen.

Mein Problem ist, das die Matlab-Schnittstelle extrem langsam ist:

Matlab-Code
1
% Öffne serielle Schnittstelle
2
adns3090_data = serial ('COM28', 'Baudrate',256000);
3
4
%Wenn ich diesen auf 900 setze, dauert das ewig
5
adns3090_data.InputBufferSize = 1; 
6
fopen(adns3090_data);
7
8
n = 0;
9
horizontal_pixel = 30;
10
vertical_pixel   = 30;
11
12
%Erzeuge 30x30 Matrix gefüllt mit 0
13
Picture = zeros(horizontal_pixel,vertical_pixel);
14
15
%Die Schleife
16
while(n<900)
17
    n = n + 1;
18
    Picture = uint8(fread(adns3090_data));
19
    disp(n);
20
end

Kann mir jemand einen Tipp geben, warum alles so langsam ist? Vielen 
Dank im Voraus!

Gruß
Daniel

von PittyJ (Gast)


Lesenswert?

30*30 Pixel = 900 Bytes.
* 60 fps = 54000 Bytes / sec.
= 432 KBit / Sekunde.

Deine Schnittstelle macht aber nur 256 Kbit?

Habe ich mich da verrechnet?
Oder ist ein Uart da etwas falsch am Platz?

von Daniel V. (voda) Benutzerseite


Angehängte Dateien:

Lesenswert?

Sorry, ich hatte den falschen Code gepostet, eingestellt habe ich 512000 
Baud (in der Senderoutine im µC-Code und im Matlabcode. Deine Rechnung 
stimmt jedoch.

Erhöhe ich den Buffer z.B. auf 15, wird alles sehr langsam und im Array 
"Picture" sind die Werte (0 - 255), allerdings nur in einer Spalte. Die 
ausgelesenen Werte scheinen zu stimmen. Die Prozedur dauert aber viel zu 
langsam (> 5 s).

Normalerweise brauche ich 900 Bits und das dauert fast 5 Minuten für ein 
Bild.

: Bearbeitet durch User
von Gustl B. (-gb-)


Lesenswert?

512000 ist keine übliche Baudrate, verwende mal 921600.

von Walter T. (nicolas)


Lesenswert?

1
disp(n);

Das dauert.

von Daniel V. (voda) Benutzerseite


Angehängte Dateien:

Lesenswert?

So, das habe ich nun getan. Im µC auf 921600 Baud eingestellt und im 
Matlab ebenso. So sieht meine Implementierung aus (siehe Datei).

Ziel ist es, die Bilderdaten meines ADNS3090 als 30x30-Matrix als csv zu 
speichern. Diese lese ich anschließend wieder ein und mache z.B. eine 
Opticalflow-Messung.

Führe ich das Skript aus, kommt die Fehlermeldung

Warning: Unexpected Warning: The input buffer was filled before the 
Terminator was reached.

Ich interpretiere daraus, das mein Buffer zu schnell gefüllt wird. Wie 
definiere ich in Matlab ein Buffer, am besten 900 Bytes groß?

Danke und Gruß
Daniel

: Bearbeitet durch User
von HG (Gast)


Lesenswert?

Daniel V. schrieb:
> Warning: Unexpected Warning: The input buffer was filled before the
> Terminator was reached.
>
> Ich interpretiere daraus, das mein Buffer zu schnell gefüllt wird. Wie
> definiere ich in Matlab ein Buffer, am besten 900 Bytes groß?

im neuen Beispielcode verwendest du fgetl(), das ist aber nur für 
Ascii-Daten brauchbar. Warum nicht wie am Anfang fread() verwenden, das 
ist für Binärdaten und man kann als size[30,30] zurückgegeben um sofort 
ein zweidimensionaes array mit den Bilddaten zu erhalten.

Siehe:
https://de.mathworks.com/help/matlab/ref/serial.fread.html

von HG (Gast)


Lesenswert?

grummel, kann nicht editieren:

... man kann als size[30,30] übergegeben ...

von Daniel V. (voda) Benutzerseite


Lesenswert?

Jau, stimmt eigentlich. Das führt das der Buffer schon gefüllt ist, 
bevor ich irgendwas mache?

: Bearbeitet durch User
von HG (Gast)


Lesenswert?

ja, wenn soviel schon im seriellen Puffer ist, sonst wartet read() bis 
genug Daten da sind um das 30x30-Array zu füllen.

Allgemein ist es in Matlab immer besser selbstprogrammierte Schleifen zu 
vermeiden, die Funktionen die ganze Arrays/Zeilen/Spalten auf einen 
Rutsch bearbeiten sind um Größenordnungen schneller.

von Daniel V. (voda) Benutzerseite


Lesenswert?

HG schrieb:
> ja, wenn soviel schon im seriellen Puffer ist, sonst wartet read()
> bis
> genug Daten da sind um das 30x30-Array zu füllen.
>
> Allgemein ist es in Matlab immer besser selbstprogrammierte Schleifen zu
> vermeiden, die Funktionen die ganze Arrays/Zeilen/Spalten auf einen
> Rutsch bearbeiten sind um Größenordnungen schneller.

Wie realisiere ich das denn? Kannst Du mir ein Beispiel geben? Ich muss 
ja im diesen Falle die Arrays ja füllen. Später benutze ich ja die 
komplette Matrix um z.B. Vektoren zu bestimmen.

Danke und Gruß
Daniel

von HG (Gast)


Lesenswert?

sowas in der art sollte funktionieren:

1
horizontal_pixel = 30;
2
vertical_pixel   = 30;
3
4
adns3090_data = serial ('COM28', 'Baudrate',921600);
5
6
7
adns3090_data.InputBufferSize = 900; 
8
9
fopen(adns3090_data);
10
11
%Erzeuge 30x30 Matrix gefüllt mit 0 
12
% ist wohl unnötig
13
Picture = zeros(horizontal_pixel,vertical_pixel);
14
15
Picture = fread(adns3090_data,[horizontal_pixel,vertical_pixel],'uint8');


Das kann ich hier aber nicht testen, habe zuhause kein Matlab 
installiert.

von Daniel V. (voda) Benutzerseite


Lesenswert?

Danke dir, ich werde das heute abend zuhause mal testen. Dann war mein 
erster Ansatz gar nicht so falsch. Danach kann ich diese eigentlich in 
einer csv- oder xls-Datei speichern und für spätere Analysen verwenden.

Ich sag bescheid.

Danke und Gruß
Daniel

von Daniel V. (voda) Benutzerseite


Angehängte Dateien:

Lesenswert?

So, jetzt habe ich mal Deine Lösung implementiert. Das auslesen dauert 
immer noch viel zu lang, aber zumindest habe ich schonmal ein Bild. Nach 
ungefähr 533 Bytes kommt die Fehlermeldung:

Irgendwo habe ich einen Flaschenhals. Siehe Bild. Gerne kann ich auch 
den µC-Code (STM34F4) hochladen.
1
% USART Kommunikation
2
clc; clear all, close all;
3
4
if ~isempty(instrfind)
5
   fclose(instrfind); 
6
end
7
8
adns3090_data = serial ('COM28', 'Baudrate',921600);
9
adns3090_data.InputBufferSize = 900;
10
set(adns3090_data,'Timeout', 15000);
11
12
fopen(adns3090_data);
13
14
horizontal_pixel = 30;
15
vertical_pixel   = 30;
16
17
Picture = fread(adns3090_data,[horizontal_pixel,vertical_pixel],'uint8');
18
19
20
fclose(adns3090_data);
21
disp('erfolgreich');
22
23
colormap(gray(256));
24
image(Picture);

Danke und Gruß
Daniel

: Bearbeitet durch User
von Vincent H. (vinci)


Lesenswert?

Dein Flaschenhals lautet MATLAB. Alles über 115200 Baud ist leider reine 
Glückssache, bzw. stark abhängig von der PC-Hardware und dem OS.

Solltest du wirklich was schnelleres brauchen, dann empfehle ich auf 
Python inkl. pyserial umzusteigen. Damit fahre ich problemlos 2MBaud 
inklusive Echtzeit-Plots.

von HG (Gast)


Lesenswert?

Wie lautet denn die Fehlermeldung nun?

Das Bild hat ja nur 900 Byte, also sollte auch bei einer Baudrate vom 
9600 die Übertragung nur eine Sekunde brauchen. Das wär für Matlab 
erstmal einfacher, wenn das klappt kann man immer noch testen wie 
schnell man die Übertragung noch hochkitzeln kann.

von Daniel V. (voda) Benutzerseite


Lesenswert?

HG schrieb:
> Wie lautet denn die Fehlermeldung nun?
>
> Das Bild hat ja nur 900 Byte, also sollte auch bei einer Baudrate vom
> 9600 die Übertragung nur eine Sekunde brauchen. Das wär für Matlab
> erstmal einfacher, wenn das klappt kann man immer noch testen wie
> schnell man die Übertragung noch hochkitzeln kann.

Sorry, hatte den Beitrag editiert, somit ist das obige erste Bild 
obselet. Die Datenübertragung dauert jetzt 1,8 s.

Ich denke ich habe den Fehler in meiner µC-Controller-Software 
ausgemacht. Auf den SPI-MISO-Bus liegen 54 Datenpakete a 900 Byte 
(gemessen mit meinem LA). Mit dem Oszi habe ich auf der USART-Seite 
gemessen, Dort gibt es Verzögerungen zwischen den Datenpaketen von ca 20 
ms. Ich könnte sogar mit der Baudrate runtergehen.

Aber mit Deiner Hilfe bin ich einen sehr gutes Stück weitergekommen. 
Danke Dir erstmal. Ich halte euch auf den Laufenden.

: Bearbeitet durch User
von Jim M. (turboj)


Lesenswert?

Daniel V. schrieb:
> Mit dem Oszi habe ich auf der USART-Seite
> gemessen, Dort gibt es Verzögerungen zwischen den Datenpaketen von ca 20
> ms. Ich könnte sogar mit der Baudrate runtergehen.

Bau lieber Flusskontrolle (RTS/CTS) ein. Damit gehen auch bei hohen 
Baudraten keine Bytes Richung PC verloren - wenn Matlab das unterstützt.

von Daniel V. (voda) Benutzerseite


Lesenswert?

kurzes Update:

Es lag an meiner Firmware auf dem STM32F4:

Dieser Routine holt die Pixeldaten vom ADNS3090 aus dem 
Frame_Capture_Register (0x13) und sendet diesen direkt auf die USART. 
Vorher habe ich noch eine for-Schleife erstellt, d.h. diese Routine 
unten und in der main ebenfalls

Als Baudrate habe ich jetzt 912600. Ich kann definitiv runter gehen.

Hier die Routine auf dem STM32:
1
void adns3090_Pixel_Burst(uint8_t *image)
2
{
3
 adns3090_FrameCapure_Config(); 
4
 ADNS3090_NSS_LOW;
5
 adns3090_Read(SPI2, ADNS3090_PIXEL_BURST);
6
 delay_us(50);
7
  
8
  for (i=0; i<900;)
9
  {
10
    register_val = adns3090_Read(SPI2,0x00); /* Dummybyte */
11
    delay_us(10);
12
     if(is_first_pixel == false)
13
     {
14
       if (register_val&0x40)/*Makierungsframe = 0b01000000*/
15
       {
16
        is_first_pixel = true;
17
       }
18
       else
19
       {
20
        TimeOut++;
21
          if(TimeOut==100)
22
          {
23
           adns3090_RESET();
24
           break; 
25
          }  
26
       }
27
     }
28
     if(is_first_pixel==true)
29
     {
30
      image[i++] = (register_val<<2);
31
      USART_SendData(USART3, *image); /*HIER!!!*/
32
     }
33
  }
34
   ADNS3090_NSS_HIGH;
35
   delay_us(14);
36
}

Diese wird in der Main (Funktion in meiner Bib adns3090.c bzw .h) 
aufgerufen:
1
uint8_t picture[1536];
2
3
int main (void)
4
{
5
  adns3090_Pixel_Burst(picture);
6
}

Dieser Matlabcode ist soweit funktionsfähig:
1
clc; clear all, close all;
2
3
% Prüft ob die serielle Schnittstelle vorhanden und belegt ist
4
% Ist diese belegt, schließe diese.
5
6
if ~isempty(instrfind)
7
   fclose(instrfind); 
8
end
9
10
% USART-Schnittstellendaten
11
adns3090_data = serial ('COM28', 'Baudrate',921600);
12
adns3090_data.InputBufferSize = 900;
13
%set(adns3090_data,'Timeout', 15000);
14
fopen(adns3090_data);
15
16
% Schreibe in Matrix
17
horizontal_pixel = 30;
18
vertical_pixel   = 30;
19
20
Picture = fread(adns3090_data,[horizontal_pixel,vertical_pixel],'uint8');
21
fclose(adns3090_data);
22
disp('erfolgreich');
23
24
colormap(gray(256));
25
image(Picture);

Danke und Gruß
Daniel

: Bearbeitet durch User
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.