PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Serialin Buffer



Red
05.11.2008, 09:03
Guten Morgen
Ich hab da mal eine Frage bezüglich des Buffers.
Gibt es eine möglichkeit den Serialen Buffer zuvergrößern?
Beim mitlesen einer Schnittstelle kommt es bei mir zu komplikationen da der größte Frame 260 Byte groß ist und keine CTS oder RTS benutzt werden.
Da das Programm noch anderweitig beschäftigt ist kann es passieren das nicht alle Daten gelesen werden.
Also kann man den Buffer vergrößern oder hat jemand eine Lösung?

Nur so neben bei. Wieso kann ich den dritten Serialen Buffer z.B eines Atmega2560 nur auf 254 Byte setzen. Normal müssten doch 255Byte gehen oder nicht?

MfG

PicNick
05.11.2008, 11:15
Bascom verwendet nur Bytes als Pointer für den ringbuffer. dadurch fällt mal alles darüber aus.
wegen den 254 muss ich annehmen, dass er bei seinen berechnungen sonst Probleme kriegt, das müßt' ich analysieren. Aber das eine Byte hülfe dir ja eh nix.

Ich fürchte, den RIngbuffer auf größer mußt du zu Fuß machen. Kommst du damit zurecht ?

Red
05.11.2008, 13:24
Das eine Byte hilft mir nicht da hast du recht. Mich interessierte es bloß weil er beim serialin und beim serialin3 aktzeptiert er die size von 255. Nur beim serialin1 und 2 meckert Bascom beim kompilieren.

Den Ringbuffer zu Fuß. :-k Da könnte ich einen anstoß gerbrauchen, arbeite noch nicht lange mit Bascom und meine Programmierwissen ist ein wenig eingerostet.

PicNick
05.11.2008, 15:04
Ein Anstoss:


Dim Base As Word
Dim Top As Word
Dim Wrpnt As Word
Dim Rdpnt As Word
Dim One_w As Byte
Dim One_r As Byte
Dim Buffer(260) As Byte


Buf_init:
Base = Varptr(buffer(1)) 'mem-adr von Buffer-base
Top = Base + 260 'mem adr von bufer top
Wrpnt = Base 'write pointer
Rdpnt = Base 'read pointer
Return

Buf_write:
One_w = Udr ' byte from UART
Out Wrpnt , One_w ' into buffer
Incr Wrpnt ' pointer + 1
If Wrpnt >= Top Then Wrpnt = Base ' wrap around
Return

Buf_read:
interrupts disable
If Rdpnt = Wrpnt Then
interrupts enable
One_r = 0 ' no data
Else
interrupts enable
One_r = Inp(rdpnt) ' read from pointer
Incr Rdpnt ' pointer + 1
If Rdpnt >= Top Then Rdpnt = Base ' wrap around
End If
Return

"Buf-write" passiert eigentlich in der Interrupt-routine

"Udr" wird bei dir anders heissen

Red
05.11.2008, 22:36
Cool danke.
Wenn ich das richtig verstanden habe müsste das in etwa wie folgt aussehen.


$regfile = "m2560def.dat"
$crystal = 14745600
$baud = 921600

Config Com3 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0

Enable Interrupts
Enable Urxc2

On Urxc2 Buf_write

Dim Base As Word
Dim Top As Word
Dim Wrpnt As Word
Dim Rdpnt As Word
Dim One_w As Byte
Dim One_r As Byte
Dim Buffer(260) As Byte


Buf_init:
Base = Varptr(buffer(1)) 'mem-adr von Buffer-base
Top = Base + 260 'mem adr von bufer top
Wrpnt = Base 'write pointer
Rdpnt = Base 'read pointer
Return

Do

'Main Programm

Loop


Buf_write:
One_w = Udr2 ' byte from UART
Out Wrpnt , One_w ' into buffer
Incr Wrpnt ' pointer + 1
If Wrpnt >= Top Then Wrpnt = Base ' wrap around
Return

Buf_read:
Disable Urxc2
If Rdpnt = Wrpnt Then
Enable Urxc2
One_r = 0 ' no data
Else
Enable Urxc2
One_r = Inp(rdpnt) ' read from pointer
Incr Rdpnt ' pointer + 1
If Rdpnt >= Top Then Rdpnt = Base ' wrap around
End If
Return




Mir schwebt grad noch eine Funktion in form des Ischarwaiting vor (bzw. ein FlagBit). Das sollte allerdings kein Problem sein.

Danke nochmal für deine Hilfe.

MfG

PicNick
06.11.2008, 11:15
Dem "Ischarwaiting" entspricht dieser Vergleich:
If Rdpnt = Wrpnt Then ..

Das interrupt-disablen ist, weil bei eine 2-byte vergleich ein Durcheinander rauskommen kann. Aber ich glaub, das wußtest du eh.

Btw: Wenn deine Frames ein definiertes Ende haben, würde ich den Check, ob das Frame komplett ist, in die ISR legen und dann einen speziellen Flag für das HauptProgramm setzen. Das wäre effizienter

Red
06.11.2008, 12:30
Ja stimmt das entspricht dem "Ischarwaiting".
Allerdings kann man im Hauptprogramm so noch nicht erkennen ob Daten vorliegen. Mir fehlte da einfach ein Flag. Bin ich gestern aber nicht so schnell drauf gekommen. Ausgeschlafen ging das einfach schnell.

Das mit den Interrupts war mir nicht ganz klar und ist es auch noch nicht ganz. Kurzer verweis oder erklärungen wären hilfreich.


Leider haben die Frames eine variable länge. Je nach Information.
Ersten beiden Bytes beinhalten die Länge letztes die CRC.
Habe dafür bisher eine eigene Routine geschrieben.
Muss mir halt noch überlegen ob man beides verbinden kann.

MfG

PicNick
06.11.2008, 12:57
Wenn er ein Word mit zwei Bytes vergleicht, vergleicht er ja erst das eine und dann das andere. Wenn aber genau da ein Interrupt dazwischen fährt und die ISR den "WrPnt" verändert, ist der Vergleich nicht koscher. Daher wird während des Vergleichs der interrupt disabled und gleich danach wieder aufgedreht.
Die ISR hat Zustände
1 Warten auf frame-start
2 lesen frame-länge
3 lesen daten
(4) Frame-crc OK ->Frame ready (oder nicht)

je nachdem läuft es etwas anders ab, den CRC rechnest du gleich mit, und wenn die Daten alle gelesen sind, muss ja dein nachberechneter CRC grad genau den Startwert haben.

? Ist das ein bekanntes frame-format ?
? welche art crc

Red
06.11.2008, 15:25
Ist es nicht etwas ungeschickt den "Frametest" in der ISR zu machen?
Man soll doch ISR kurz halten oder nicht?
Ich könnte mir vorstellen das wenn der Test zu lange dauert ein paar bytes verloren gehen. Oder die ISR neu Startet.

Meiner meinung nach würde der Frametest besser in den Buf_read passen.
Lasse mich gerne überzeugen das es auch im ISR geht. Vllt. denke ich einfach zu "langsam".

Den Test mache ich bereits in der Reihenfolge in einer eigenen Routine.
Das soll allerdings später noch besser zusammen gefasst werden.

Ob es ein bekanntes Format ist weiß ich nicht. Kenne mich da zu wenig aus.
Der Frame besteht aus Länge, einer Komplement der Länge, NxInformation und CRC
CRC = summe Informationsbytes modulo 256

MfG

PicNick
06.11.2008, 15:45
Naja, in epischer Breite soll eine ISR nicht sein. aber sooooo viel sind die paar checks ja auch nicht
Aber da will ich dir nix einreden.

Red
12.11.2008, 16:51
Hi
Den "Frametest" in der ISR probiere ich noch aus.
Hab aber immer noch probleme beim lesen der Uart.
Es lief schon mal wesentlich besser als ich den Buffer mit einer Uart ausprobiert hatte.
Nachdem ich ein paar änderungen und erweiterungen eingebracht habe läufts nicht mehr rund und ich finde den Grund einfach nicht.
Entweder ist es ein simpler fehler und ich hab Tomaten auf den Augen oder schlimmstenfalls ein Timing Problem.
Im Anhang mal ein Bild von einem Daten log.
Links original Daten. Rechts ausgabe aus dem Mikroproz.
An der markierten Stelle sieht man das Problem. Er überliest ein paar "0" bytes.
Hier noch der Code.



$regfile = "m2560def.dat"
$crystal = 14745600
$baud = 921600
$lib "i2c_TWI.LBX"

Config Timer1 = Timer , Prescale = 1024

Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
Config Com2 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
Config Com3 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
Config Com4 = 9600 , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0

'Config Serialin = Buffered , Size = 255
'Config Serialin1 = Buffered , Size = 40
'Config Serialin2 = Buffered , Size = 254
Config Serialin3 = Buffered , Size = 255

'Config Serialout = Buffered , Size = 40
'Config Serialout1 = Buffered , Size = 40
'Config Serialout2 = Buffered , Size = 40
Config Serialout3 = Buffered , Size = 40

Open "com1:" For Binary As #1
Open "Com2:" For Binary As #2
Open "Com3:" For Binary As #3
Open "Com4:" For Binary As #4

Declare Sub Frametest(bufin As Byte , Bufin_old As Byte)
'DECLARE FUNCTION Buf_read (ioport As Byte) As byte

Gosub Buf_init

Enable Interrupts
Enable Timer1
Enable Urxc
Enable Urxc2

On Urxc Buf1_write
On Urxc2 Buf3_write


'*****************************
'* Variablen deklaration *
'*****************************


Dim Lauf1 As Word 'Laufvariable beim schreiben der Uart
Dim Lauf2 As Word
Dim Lauf3 As Word
Dim Lauf(3) As Word 'Laufvariablen beim einlesen der Uart

Dim Kons As Bit 'Konsole auf TR1 (=0) TR2 (=1)
Dim Ioport As Byte 'Uarts einlesen durch eine Sub

Dim Base(3)as Word 'Basisadresse der Buffer (Anfang)
Dim Top(3) As Word 'Topadresse der Buffers (Ende)
Dim Wrpnt(3) As Word 'Pointer auf die Adressen des Buffers beim einlesen der Uart
Dim Rdpnt(3) As Word 'Pointer aud die Adressen des Buffers beim auslesen des Buffers
Dim Buf_size(3) As Word 'Menge der Daten im Buffer
Dim One_w(3) As Byte 'Zwischenspeicher beim einlesen der Uart
Dim One_r(3) As Byte 'Zwischenspeicher beim auslesen des Buffers
Dim Buf_wait(3) As Byte 'Flag Byte Daten im Buffer vorhanden
Dim Buffer1(300) As Byte 'Buffer der Uartdaten
Dim Buffer2(300) As Byte
Dim Buffer3(300) As Byte

Dim Compl As Byte 'Einer Komplement der Länge
Dim Framesize(3) As Word 'Länge des Datenrahmen
Dim Anfangflag(3) As Byte 'Zeichen das ein gültiger Frameanfang gefunden wurde
Dim Crc(3) As Byte 'enthält das Checksumergebnis zur überprüfung
Dim Dataflag(3) As Byte 'Zeichen dafür das gültige Daten im Uartarrygespeichert wurden 1=gültige Daten liegen vor 0=keine gültigen Daten vorhanden
Dim Buf As Byte , Buf_old As Byte 'Buffervariablen der eingelesenen Uart Bytes

Dim Uart1(300) As Byte 'zwischenspeicher Uartdaten
Dim Uart2(300) As Byte
Dim Uart3(300) As Byte
Dim Datapnt(3) As Word 'Pointer auf die Adresse eines Bytes von UartX(n) in der die Daten gespeichert werden sollen
Dim Database(3) As Word 'Adresse von UartX(1)

Dim K As Word 'Laufvariable CRC Schleife
Dim I As Word 'Laufvariable für For_Schleifen




'*****************************
'* Initialisierung *
'*****************************

Kons = 1

Database(1) = Varptr(uart1(1))
Database(2) = Varptr(uart2(1))
Database(3) = Varptr(uart3(1))
For K = 1 To 3
Dataflag(k) = 0
Anfangflag(k) = 0
Datapnt(k) = Database(k)
Crc(k) = 0
Next

I = 0

Shdn_max1 = 0 'ausgeschaltet Fehler im aufbau?
Shdn_max2 = 1
Shdn_max3 = 1
En_max1 = 0
En_max2 = 0
En_max3 = 0
'*****************************
'* Main *
'*****************************
Main:

Do
Ioport = 1
Gosub Uart_lesen

If Dataflag(ioport) = &HFF Then
Gosub Ctxd_schreiben
End If


Ioport = 3
Gosub Uart_lesen

If Kons = 1 And Dataflag(ioport) = &HFF Then
Gosub Crxdtr2_schreiben
End If


Loop

End

'*****************************
'* Uart lesen *
'*****************************
Uart_lesen: 'Daten der Konsole werden ausgeleden

Disable Interrupts
If Buf_size(ioport) <> 0 Then 'nur wenn Daten im Buffer vorhanden sind


Do
Enable Interrupts
Gosub Buf_read 'liest Byte aus Uartbuffer in One_r
'Call Buf_read(ioport)

Buf_old = Buf
'Buf= Buf_read(ioport)
Buf = One_r(ioport)
Call Frametest(buf , Buf_old) 'Prüfen auf gültigen Frame
Loop Until Dataflag(ioport) = &HFF Or Buf_size(ioport) = 0 'solange bis Buffer leer oder Frame gefunden

End If
Enable Interrupts

Return

'*****************************
'* Uart ausgabe *
'*****************************

Ctxd_schreiben:

Select Case Kons

Case 0 : 'Daten an Tr1

For Lauf1 = 1 To Framesize(ioport)
Put #2 , Uart1(lauf1)
Next



Case 1 : 'Daten an Tr2

For Lauf1 = 1 To Framesize(ioport)
Put #3 , Uart1(lauf1)
Next

End Select

Dataflag(ioport) = 0

Return



Crxdtr1_schreiben:

For Lauf2 = 1 To Framesize(ioport)
Put #1 , Uart2(lauf2)
Next

Dataflag(ioport) = 0

Return



Crxdtr2_schreiben:

For Lauf3 = 1 To Framesize(ioport)
Put #1 , Uart3(lauf3)
Next

Dataflag(ioport) = 0

Return

'*****************************
'* Frametest *
'*****************************


Sub Frametest(bufin As Byte , Bufin_old As Byte)

Compl = &HFF - Bufin_old

If Bufin = Compl And Anfangflag(ioport) = 0 And Bufin_old > &H01 Then

Anfangflag(ioport) = &HFF 'gültiger Anfang gefunden
Lauf(ioport) = 3 'Initialisierung
Crc(ioport) = 0

Out Datapnt(ioport) , Bufin_old 'Anfangsbyte (=Länge) an Arrayanfang schreiben
Incr Datapnt(ioport)

Out Datapnt(ioport) , Bufin '[Einerkomplement der Länge]
Incr Datapnt(ioport)

Framesize(ioport) = Inp(database(ioport)) 'Längen zwischenspeicher
Framesize(ioport) = Framesize(ioport) + 3 'Rahmensync.(2xLänge,CRC) gehört nicht zur länge -> +3


Elseif Anfangflag(ioport) = &HFF Then 'wenn anfang gefunden weiter einlesen bis Frameende

Out Datapnt(ioport) , Bufin
Incr Datapnt(ioport)

Disable Interrupts

If Lauf(ioport) = Framesize(ioport) Then 'Ende des Frames erreicht?

Enable Interrupts

If Bufin = Crc(ioport) Then 'gültige CRC?

Dataflag(ioport) = &HFF 'ja Flag für gültige Daten setzen (kein "Bitarray" möglich)
Anfangflag(ioport) = 0
Datapnt(ioport) = Database(ioport)

Else
'nein neuen Anfang suchen
Anfangflag(ioport) = 0
Datapnt(ioport) = Database(ioport)

End If

Else 'noch nicht am Ende des Frames dann

Enable Interrupts
Crc(ioport) = Crc(ioport) + Bufin 'Crc berechnen (CRC as Byte)
'CRC= Sum(Informationsbytes) mod 256
End If

Lauf(ioport) = Lauf(ioport) + 1 'Zähler um Ende zu finden

End If


End Sub

'*****************************
'* Buf_Init *
'*****************************

Buf_init:

'mem-adr von Buffer-base
Base(1) = Varptr(buffer1(1))
Base(2) = Varptr(buffer2(1))
Base(3) = Varptr(buffer3(1))
'mem adr von bufer top
Top(1) = Base(1) + 300
Top(2) = Base(2) + 300
Top(3) = Base(3) + 300
'write pointer
Wrpnt(1) = Base(1)
Wrpnt(2) = Base(2)
Wrpnt(3) = Base(3)
'read pointer
Rdpnt(1) = Base(1)
Rdpnt(2) = Base(2)
Rdpnt(3) = Base(3)
'Anzahl der Bytes im Buffer
Buf_size(1) = 0
Buf_size(2) = 0
Buf_size(3) = 0
Buf_wait(1) = 0
Buf_wait(2) = 0
Buf_wait(3) = 0

Return

'*****************************
'* Buf_read *
'*****************************


Buf_read:

'FUNCTION Buf_read (ioport As Byte) As byte

Disable Interrupts
If Rdpnt(ioport) = Wrpnt(ioport) Then
Enable Interrupts

Reset Buf_wait(ioport)
One_r(ioport) = 0 ' no data

Else
Enable Interrupts

One_r(ioport) = Inp(rdpnt(ioport)) ' read from pointer
'buf_read = One_r(ioport)

Incr Rdpnt(ioport) ' pointer + 1
Decr Buf_size(ioport)
End If


Disable Interrupts
If Rdpnt(ioport) >= Top(ioport) Then
Enable Interrupts
Rdpnt(ioport) = Base(ioport) ' wrap around

End If
Enable Interrupts

'End function
Return

'*****************************
'* Buf_write *
'*****************************


Buf1_write:

One_w(1) = Udr0 ' byte from UART
Out Wrpnt(1) , One_w(1) ' into buffer
Incr Wrpnt(1)
Incr Buf_size(1) ' pointer + 1
Buf_wait(1) = &HFF
If Wrpnt(1) >= Top(1) Then
Wrpnt(1) = Base(1) ' wrap around
End If

Return



Buf2_write:

One_w(2) = Udr1 ' byte from UART
Out Wrpnt(2) , One_w(2) ' into buffer
Incr Wrpnt(2)
Incr Buf_size(2) ' pointer + 1
Buf_wait(2) = &HFF
If Wrpnt(2) >= Top(2) Then
Wrpnt(2) = Base(2) ' wrap around
End If

Return



Buf3_write:

One_w(3) = Udr2 ' byte from UART
Out Wrpnt(3) , One_w(3) ' into buffer
Incr Wrpnt(3)
Incr Buf_size(3) ' pointer + 1
Buf_wait(3) = &HFF
If Wrpnt(3) >= Top(3) Then
Wrpnt(3) = Base(3) ' wrap around
End If


Return

Hoffe jemand kann mir helfen.
MfG

PicNick
12.11.2008, 19:27
Nun, ich beschäftige mich grad mit dem Programm.
Rückfrage:
Bei unserem "long Ringbuffer"-Port darfst du kein "config serialin" angeben, da sind wir uns ja einig ?

Von welchem Gerät kommt das Frame ? ich glaub' , ich hab das Format noch nicht ganz kapiert, vielleicht kann ich wo nachsehen

Red
12.11.2008, 22:15
Ja da sind wir uns einig. Die "config serialin" sind auskommentiert.
Hab mal ein Auszug der Spezi. im Anhang für das Format eingefügt. Sollte helfen das zu verstehen.
Prinzipiell ganz einfach.

MfG

PicNick
13.11.2008, 10:23
danke, das hilft.