Hallo, ich möchte einen Datenlogger mit einem Atmega88 und einem VNC1L Chip von Vinculum bauen. Der Atmega empfängt alle 10ms 10 Byte Daten über den USART und gibt diese über Soft-SPI an den Vinculumchip weiter. Auf dem VNC1L ist die neuste Firmaware aufgespielt und der Schaltplan ist genauso wie der im Vdrive von Vinculum. Der VNC1L arbeitet im short command mode. Beim Programmcode für den Atmel habe ich mich weitestgehend an der Application Note AN 102 (Data-Logging Using the Vinculum VNC1L) gehalten. Mein Vorgehen ist Folgendes: Jedes über den USART Empfangene Datenbyte löst einen Inerrupt aus und wird in einen Ringbuffer gespeichert. Nach dem die Schaltung mit Spannung versorgt wurde, schickt der Atmega zur synchronisation ein echo command an den VNC1L. Dieser antwortet wenn alles in Ordnung ist. Anschließend wird überprüft ob ein USB-Stick eingesteckt wurde, wenn ja wird eine Datei geöffnet. Wenn 64 Byte im Ringbuffer sind, werden diese in die Datei geschrieben Bei 512 Byte wird die Datei zur Aktualisierung geschlossen und anschießend gleich wieder geöffnet. Dies soll solange geschehen bis die Messung beendet ist und über den USART das Messungsendezeichen kommt. Nach jedem geschicktem Befehl zum VNC1L Frage ich das Promt ab was der VNC1L schickt. Das erste was ich festgestellt habe ist, das der VNC1L manchmal sehr lange braucht bis er das Promt-Zeichen schickt nachdem er die Daten empfangen hat, die er auf den Stick speichern soll. Dies geschieht nur relativ selten. Hat das vielleicht auch schon jemand beobachtet? Dadurch ist mein Ringbuffer übergelaufen was zu einem error geführt hat, durch vergrößern des Buffers habe ich dieses Problem aber gelöst. Jetzt habe ich das Problem das die Speicherung der Daten nach genau 622.592 Bytes nicht mehr weiter geht, jedenfalls ist die Datei auf dem Stick dann immer so groß. Das bedeutet ja das die Datei 1216 mal geöffnet und wieder geschlossen wurde. Kennt dafür jemand eine Erklärung? Gibt es vielleicht ein max. Größe von Dateien? Kann ich mir eigentlich nicht vorstellen. Hoffe mir kann jemand weiter helfen, gruß Martin.
Beitrag "Eure Erfahrungen zu Geschwindigkeit und Zuverlässigkeit von VDIP1, VNC1L, RS232, USB-Stick"
Der SPI-Mode hat so seine tücken. Hier einige Erfahrungen: Beitrag "USB-Stick am Mikrocontroller VNC1L" Pausen kommen gelegentlich vor. Meist wenn der USB-Stick mit sich selber zu tun hat oder der Receive-Buffer des VNC1L voll ist. Mit welchem SPI-Takt arbeitest Du? Du wertest hoffentlich das Status-Byte (RXF# Receive-Buffer voll) aus? Ohne dies klappt die Kommunikation nicht zuverlässig. Die alleinige Kontrolle des Status-Bits im SPI-Zyklus, ob das gesendete Byte akzeptiert wurde, reicht nicht aus.
Hallo Holger, danke für den Link. Hatte ich schon gelesen, hat mich aber leider nicht weitergebracht. Ich nutze den Chip im SPI Modus und nicht im UART Modus. Mitlerweile habe ich auch noch ein paar andere Dinge ausprobiert. z.B. senden eines Echo Commandos nach jeden schließen der Datei oder nach 5kByte in eine neue Datei schreiben. Aber leider keine Änderung. Der VNC1L macht sobald die Datei 622.592 Byte groß ist nichts mehr. Ich weiß auch nicht ob es an der Dateigröße liegt, was ich eigentlich nicht glaube da er ja auch nichts mehr macht wenn ich den Dateinamen ändere, oder an was anderem.
Hallo Matthias, erstmal danke, mit welchem SPI-Takt ich arbeite kann ich dir garnicht so genau sagen. Da der VNC1L ja mit 12Bit SPI arbeitet, muss ja leider ein Software SPI programmiert werden. Diesen habe ich aus der Application Note AN 102 von FTDI übernommen.
1 | int spiXfer(int spiDirection, char *pSpiData) |
2 | {
|
3 | unsigned char retData; |
4 | unsigned char bitData; |
5 | |
6 | // CS goes high to enable SPI communications
|
7 | CS_H; |
8 | |
9 | // Clock 1 - Start State
|
10 | SDI_H; |
11 | |
12 | spiDelay(); |
13 | SCLK_H; |
14 | spiDelay(); |
15 | SCLK_L; |
16 | |
17 | // Clock 2 - Direction
|
18 | SDI_L; |
19 | if (spiDirection) SDI_H; |
20 | //PORT_SDI = spiDirection;
|
21 | |
22 | spiDelay(); |
23 | SCLK_H; |
24 | spiDelay(); |
25 | SCLK_L;; |
26 | |
27 | // Clock 3 - Address
|
28 | SDI_L; |
29 | |
30 | spiDelay(); |
31 | SCLK_H; |
32 | spiDelay(); |
33 | SCLK_L; |
34 | |
35 | // Clocks 4..11 - Data Phase
|
36 | bitData = 0x80; |
37 | if (spiDirection) |
38 | {
|
39 | // read operation
|
40 | retData = 0; |
41 | |
42 | while (bitData) |
43 | {
|
44 | spiDelay(); |
45 | retData |= SDO_VNC?bitData:0; |
46 | SCLK_H; |
47 | spiDelay(); |
48 | SCLK_L; |
49 | bitData = bitData >> 1; |
50 | }
|
51 | |
52 | *pSpiData = retData; |
53 | }
|
54 | else
|
55 | {
|
56 | // write operation
|
57 | retData = *pSpiData; |
58 | |
59 | while (bitData) |
60 | {
|
61 | SDI_L; |
62 | if ((retData & bitData) > 0) SDI_H; |
63 | //((retData & bitData) < 0)?SDI_H:SDI_L;
|
64 | spiDelay(); |
65 | SCLK_H; |
66 | spiDelay(); |
67 | SCLK_L; |
68 | bitData = bitData >> 1; |
69 | }
|
70 | }
|
71 | |
72 | // Clock 12 - Status bit
|
73 | spiDelay(); |
74 | bitData = SDO_VNC; |
75 | SCLK_H; |
76 | spiDelay(); |
77 | SCLK_L; |
78 | |
79 | // CS goes high to enable SPI communications
|
80 | CS_L; |
81 | |
82 | // Clock 13 - CS low
|
83 | spiDelay(); |
84 | SCLK_H; |
85 | spiDelay(); |
86 | SCLK_L; |
87 | |
88 | return bitData; |
89 | }
|
Den Receive-Buffer werte ich bisher noch nicht aus. Habe ich das richtig verstanden, dass ich dafür die ersten drei Bit im SPI Zyklus eine 1 schicken muss und dann schauen was der VNC1L antwortet? Fragt man den Buffer jedes mal ab bevor man ein Byte an den VNC1L schickt?
Dein bitData ist nur das Status-Bit. Reicht zur sicheren Kommunikation nicht aus. Statusbyte auslesen vor jedem Schreibvorgang und Bit RXF# prüfen. SCLK Taktrate solltest Du kennen, im wesentlichen von µC und Quarz abhängig. Max.12 MHz möglich, habe auch schon mit 18 MHz probiert, ging, muss aber nicht. Hier ein Snap meiner Schreibroutinen:
1 | // ***********************************************************************
|
2 | // VNC1L - 13-Bit-SPI Senden eines Zeichens
|
3 | // SPI Mode
|
4 | // Übergabe: wr_byte : Auszugebendes Zeichen
|
5 | // Rückgabe: status : 0=Accept (ok) 1=Byte nicht vom VNC1L angenommen
|
6 | // ***********************************************************************
|
7 | unsigned char vnc_wr_spi(unsigned char wr_byte) { |
8 | unsigned char stelle, status, cnt; |
9 | cnt = TIMEOUT_SPI; // Anzahl der Schreib-Versuche bis Timeout |
10 | do { |
11 | CS_VNC_H; // SPI-Interface aktiv |
12 | SDI_H; // Startbit (immer 1) |
13 | SCLK_H; SCLK_L; // L/H Flanke |
14 | SDI_L; // RW-Bit (0=Write) |
15 | SCLK_H; SCLK_L; // L/H Flanke |
16 | SDI_L; // ADDR (0=Daten) |
17 | SCLK_H; SCLK_L; // L/H Flanke |
18 | // 8 Datenbits senden (MSB zuerst)
|
19 | for ( stelle = 0x80; stelle; stelle >>= 1 ) { |
20 | if (wr_byte & stelle) SDI_H; else SDI_L; |
21 | SCLK_H; SCLK_L; // L/H Flanke |
22 | }
|
23 | // Statusbit einlesen
|
24 | status = SDO_VNC; // Statusbit (0=Accept, 1=Reject) |
25 | SCLK_H; SCLK_L; // L/H Flanke |
26 | // End Sequenz
|
27 | CS_VNC_L; // SPI-Interface inaktiv |
28 | SCLK_H; SCLK_L; // L/H Flanke |
29 | // SDO = 1; // nur bei 8051: Datenlatch freigeben (8051-Spezifik)
|
30 | cnt--; |
31 | if (status) _delay_us(150); // Pause, wenn Byte nicht bestätigt wurde |
32 | } while (status && cnt); |
33 | #ifdef USART_MONITORING
|
34 | usart_send_byte(wr_byte); // gesendetes Zeichen seriell senden |
35 | #endif
|
36 | #ifdef LCD_MONITORING
|
37 | lcd_monitor_byte(wr_byte); // gesendetes Zeichen auf LCD anzeigen |
38 | #endif
|
39 | return status; |
40 | }
|
41 | |
42 | // ***********************************************************************
|
43 | // VNC1L - 13-Bit-SPI Empfangen eines Zeichens
|
44 | // SPI Mode
|
45 | // Übergabe: rd_fkt : Funktion (0=Datenbyte, 1=Statusbyte)
|
46 | // Datenbyte wird im Buffer vnc-Stukturvariable gespeichert
|
47 | // Rückgabe: status : 0=Neues Byte im Buffer (ok) 1=kein neues Byte vom VNC1L vorhanden
|
48 | // ***********************************************************************
|
49 | unsigned char vnc_rd_spi(unsigned char rd_fkt) { |
50 | unsigned char stelle, daten, status; |
51 | unsigned int cnt; |
52 | cnt = TIMEOUT_SPI; // Anzahl der Lese-Versuche bis Timeout |
53 | do { |
54 | daten = 0; |
55 | CS_VNC_H; // SPI-Interface aktiv |
56 | SDI_H; // Startbit (immer 1) |
57 | SCLK_H; SCLK_L; // L/H Flanke |
58 | SDI_H; // RW-Bit (1=Read) |
59 | SCLK_H; SCLK_L; // L/H Flanke |
60 | if (rd_fkt) SDI_H; else SDI_L; // ADDR (0=Daten, 1=SPI-Statusinformation) |
61 | SCLK_H; SCLK_L; // L/H Flanke |
62 | // 8 Datenbits empfangen (MSB zuerst)
|
63 | for ( stelle = 0x80; stelle; stelle >>= 1 ) { |
64 | if (SDO_VNC) daten |= stelle; // Datenbit speichern |
65 | SCLK_H; SCLK_L; // L/H Flanke |
66 | }
|
67 | // Statusbit einlesen
|
68 | status = SDO_VNC; // Statusbit (0=New Data, 1=Old Data) |
69 | SCLK_H; SCLK_L; // L/H Flanke |
70 | // End Sequenz
|
71 | CS_VNC_L; // SPI-Interface inaktiv |
72 | SCLK_H; SCLK_L; // L/H Flanke |
73 | if (!status) { |
74 | // empfangenes Zeichen ist ein neues Zeichen
|
75 | // Empfangsbuffer um eine Stelle verschieben
|
76 | for ( stelle = VNC_BUFFER_SIZE - 1; stelle; stelle-- ) vnc.rec_buffer[stelle] = vnc.rec_buffer[stelle - 1]; |
77 | vnc.rec_buffer[0] = daten; // neues Zeichen an 1. Stelle speichern |
78 | #ifdef USART_MONITORING
|
79 | if (!rd_fkt) { |
80 | usart_send_byte(vnc.rec_buffer[0]); // empfangenes Zeichen seriell senden |
81 | }
|
82 | #endif
|
83 | #ifdef LCD_MONITORING
|
84 | if (!rd_fkt) { |
85 | lcd_monitor_byte(vnc.rec_buffer[0]); // empfangenes Zeichen auf LCD anzeigen |
86 | }
|
87 | #endif
|
88 | }
|
89 | cnt--; |
90 | if (status) _delay_us(150); // Pause, wenn keine neues Byte vorliegt |
91 | } while (status && cnt); |
92 | return status; |
93 | }
|
94 | |
95 | // ***********************************************************************
|
96 | // VNC1L - Senden eines Zeichens
|
97 | // Übergabe: wr_byte : Auszugebendes Zeichen
|
98 | // Rückgabe: status : 0=Accept (ok) 1=Byte nicht vom VNC1L angenommen
|
99 | // ***********************************************************************
|
100 | unsigned char vnc_wr_byte(unsigned char wr_byte) { |
101 | unsigned char status; |
102 | unsigned int cnt; |
103 | cnt = TIMEOUT_READ_WRITE; // Anzahl der Sende-Versuche bis Timeout |
104 | do { |
105 | // VNC1L Status-Byte lesen
|
106 | if (vnc_rd_spi(1)) return 1; // Fehler, Byte wurde nicht angenommen |
107 | // Statusbyte liegt jetzt im Buffer
|
108 | status = vnc.rec_buffer[0] & 0x01; // Test auf VNC1L RECEIVE-BUFFER voll (RXF# Bit0=1) |
109 | cnt--; |
110 | if (status) _delay_us(150); // Pause, wenn RECEIVE-BUFFER voll (RXF#) |
111 | } while (status && cnt); |
112 | if (status || (!cnt)) return 1; // Fehler, Byte wurde nicht angenommen |
113 | // VNC1L ist jetzt empfangsbereit
|
114 | if (vnc_wr_spi(wr_byte)) return 1; // Fehler Byte wurde nicht angenommen |
115 | return 0; // Byte wurde gesendet |
116 | }
|
117 | |
118 | // ***********************************************************************
|
119 | // VNC1L - Empfangen eines Zeichens
|
120 | // Rückgabe: status : 0=Neues Byte im Buffer (ok) 1=kein neues Byte vom VNC1L vorhanden
|
121 | // ***********************************************************************
|
122 | unsigned char vnc_rd_byte(void) { |
123 | unsigned char status; |
124 | unsigned int cnt; |
125 | cnt = TIMEOUT_READ_WRITE; // Anzahl der Empfangs-Versuche bis Timeout |
126 | do { |
127 | // VNC1L Status-Byte lesen
|
128 | status = vnc_rd_spi(0); // Wenn Status=1 liegt kein neues Byte vor |
129 | // Prüfung auf TXE# im Status-Byte brachte keinen Vorteil
|
130 | cnt--; |
131 | if (status) _delay_us(150); // Pause, wenn kein neue Byte vorliegt |
132 | } while (status && cnt); |
133 | if (status || (!cnt)) return 1; // Fehler, kein Byte empfangen |
134 | return 0; // Byte wurde empfangen |
135 | }
|
Hallo, ich benutze einen Atmega88 mit einem 8MHz Quarz. SCLK von meiner SPI Übertragung habe ich mal gemessen. Ein Impuls SCLK_High/SCLK_Low dauert 250us. Das sollte nicht zu schnell sein. Die Abfrage des RXF# Bits habe ich in meinen Code eingebunden, leider hat es keine Verbesserung gebracht. Das Schreiben bricht immernoch nach der gleichen Anzahl von geschriebenen Bytes ab. Was ich auch noch festgestellt habe ist, dass wenn der USB Stick als FAT32 und nicht als FAT formatiert ist, die Speicherung der Daten sehr schnell abbricht. Es dauert dann meist nur deutlich unter einer Sekunde.
SCL 250us ist recht langsam, auch die anderen Timing-Sequenzen sind von Bedeutung. Fällt mir nicht mehr viel ein. Eventuell mal viele Delays einfügen und testen, ob dann wenigsten alles korrekt durchläuft. Anderen Stick hast Du sicher schon probiert. Eventuell versuchsweise auf UART umstellen, ob Problem bleibt.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.