PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : SD Karte! Ich weiss die Frage kam schon zum 100mal



hunni
24.04.2008, 22:12
Hallo zusammen,
ich habe mal eine Frage und zwar...
Wie kann ich mit dem Atmel etwas auf einer SD Karte speichern.
Bevor wieder irgendwelche blöden Sprüche kommen wie "Die ganze Welt ist ein einziges Google" kann ich schon mal gleich sagen:
JA ich habe bei Google gesucht.
JA ich habe sogar etwas herausgefunden
JA ich habe die Suchfunktion von Roboternetz benutzt
Ja ich weiss in ungefähr, dass man die SD KArte am SPI Bus chließen muss
JA ich habe AVR Dos gefunden und muss sagen das ich dafür kein Geld ausgeben möchte

ABER: Ich komme mit der Programmierung nicht klar. Könntet ihr mir einfach mal ein kleines Beispiel geben?
Vielen Dank,
Hunni

HansHans
24.04.2008, 23:10
JA ich habe AVR Dos gefunden und muss sagen das ich dafür kein Geld ausgeben möchte


Ist AVR Dos nicht inzwischen in der Bascom Vollversion enthalten ,
und für die nicht Kommerzielle Nutzung „Freeware“ ?

Gruß HH

python_rocks
24.04.2008, 23:34
Ist AVR Dos nicht inzwischen in der Bascom Vollversion enthalten , und für die nicht Kommerzielle Nutzung „Freeware“ ?
Hallo!

Ja, AVR-Dos ist in der Bascom-Vollversion mit dabei. Man kann es auch direkt von der AVR-Dos-Homepage herunterladen. Und für "Nicht Kommerzielle Nutzung" ist AVR-Dos gratis.

Allerdings braucht man **mindestens** einen ATmega32, besser einen ATmega128, dafür. Und wenn man auf das FAT-Dateisystem verzichten kann und einfach nur Daten, wie bei einem EEPROM, auf die Karte schreiben möchte, dann kann man auf AVR-Dos verzichten und sogar mit einem ATmega8 arbeiten.

- http://www.mcselec.com/index.php?option=com_content&task=view&id=20&Itemid=41
- http://members.aon.at/voegel/
- http://www.mcselec.com/index.php?option=com_content&task=view&id=87&Itemid=57
- http://www.ulrichradig.de/home/index.php/avr/mmc-sd
- http://staff.ltam.lu/feljc/electronics/bascom/Speicherkarten_Low_Level.pdf

mfg
Gerold
:-)

hunni
04.05.2008, 12:05
Hallo nochmal,
tut mir leid das ich so lange nich geschrieben habe. Ich finde die "free download" version nicht. Da steht zwar oben drüber, dass das Kostenlos ist, aber ich man kann nur die 19,99€ oder 99,99€.
Könnt ihr mir vielleicht ein link geben, wo ich das herbekomme?
Warscheinlich bin ich einfach nur zu dumm dahin zu finden.

Gento
04.05.2008, 16:30
Soweit ich das ersehen kann liegt es einer gekauften Version bei.

In der Demo Version ,beschränkt auf 4 K , ist das meiner Meinung nach eh sinnlos.

Gento

hunni
04.05.2008, 20:14
ach so!
Nah dann kann ich das ja auch gleich ganz vergessen mit der SD Karte, da ich mit den anderen "No Fat System" nichklar komme.
Hunni

for_ro
04.05.2008, 21:47
Dann versuch es doch mal mit der einfachen Version, ohne AVR-DOS.
Ich weiß nicht, wieviel dein sonstiger Code ausmacht, aber der hier inklusive Lesen und Schreiben von 1000 Sektoren und Ausgabe auf den UART belegt gerade mal 1492 Byte, also noch viel Platz bis 4K.

$regfile = "M128def.dat"
$crystal = 16000000

$baud1 = 115200
Open "Com2:" As Binary As #1
Enable Interrupts

Dim Mmc_error As Byte
Dim In_ptr As Word ' Address-Pointer for read
Dim In_sect As Long
Dim In_buffer As String * 512
Print #1 , "Wait for Drive"
$include "Config_MMC.bas"
'Hier werden als Test die ersten 1000 Sektoren der Karte eingelesen und auf den UART ausgegeben und dann wieder auf die SD geschrieben.
In_ptr = Varptr(in_buffer)
If Gbdriveerror = 0 Then
Mmc_error = Driveinit()
If Mmc_error = 0 Then
Print #1 , "Driveinit Ok. "
For In_sect = 0 To 1000
Mmc_error = Drivereadsector(in_ptr , In_sect)
If Mmc_error = 0 Then
Print #1 , "ReadSector(" ; In_sect ; ") ok." 'Zum Inhalt drucken, Kommentare entfernen !!!!!!!!!!
Print #1 , In_buffer 'Dann wird es aber langsamer, 115200 baud beim übertragen
Mmc_error = Drivewritesector(in_ptr , In_sect)
Else
Print #1 , "Error during ReadSector(" ; In_sect ; ") : " ; Mmc_error
End If
Next In_sect
Else
Print #1 , "Error during Driveinit(): " ; Mmc_error
End If
End If

End
Hierbei werden die Sektoren direkt geschrieben. Das reicht für die Ein- und Ausgabe im µC.
Wenn du eine Datei in Windows sehen willst, legst du vorher eine dummy-Datei der benötigten Größe an und schreibst dann deren Sektoren.

Gruß

Rolf

hunni
05.05.2008, 16:53
aber ich dachte immer der atmega8 hat nur ein Com, oder liege ich da falsch?
Auch hatte ich gedacht, dass man die SD karte am SPI Bus anscließen muss und nich am Comport.
Ich glaube, ich habe mitleerweile eine andere Lösung gefunden. Ich kann einen USB Stick am Com anschließen und dann mit "Print" befehle auf den USB abspeichern (hoffe ich). Wenn das auch falsch ist, dann lass ich das mit dem Abspeichern, da ich nicht den Quelltext so recht verstehe. :-s
Hunni :-k

for_ro
05.05.2008, 20:30
Natürlich hat der nur einen COM. Ist halt für meinen Mega128.
Also hier noch mal für deinen Mega8. Ich dachte das könntest du alleine.

$regfile = "M8def.dat"
$crystal = 16000000

$baud = 115200
Enable Interrupts

Dim Mmc_error As Byte
Dim In_ptr As Word ' Address-Pointer for read
Dim In_sect As Long
Dim In_buffer As String * 512
Print "Wait for Drive"
$include "Config_MMC.bas"
'Hier werden als Test die ersten 1000 Sektoren der Karte eingelesen und auf den UART ausgegeben und dann wieder auf die SD geschrieben.
In_ptr = Varptr(in_buffer)
If Gbdriveerror = 0 Then
Mmc_error = Driveinit()
If Mmc_error = 0 Then
Print "Driveinit Ok. "
For In_sect = 0 To 1000
Mmc_error = Drivereadsector(in_ptr , In_sect)
If Mmc_error = 0 Then
Print "ReadSector(" ; In_sect ; ") ok." 'Zum Inhalt drucken, Kommentare entfernen !!!!!!!!!!
Print In_buffer 'Dann wird es aber langsamer, 115200 baud beim übertragen
Mmc_error = Drivewritesector(in_ptr , In_sect)
Else
Print "Error during ReadSector(" ; In_sect ; ") : " ; Mmc_error
End If
Next In_sect
Else
Print "Error during Driveinit(): " ; Mmc_error
End If
End If
End

Auf die Karte wird nicht über den Com-Port geschrieben, sondern mit der Funktion DriveWriteSector() über SPI. Die Belegung der Anschlüsse ist in der Datei "Config_MMC.bas". Schau es dir mal an. Printen doch nur um das gelesene auch mal zu sehen.

Gruß

Rolf

hunni
06.05.2008, 16:14
AHH, ich habe die erleuchtung. jetzt hab ich es verstanden.
Vielen Dank für eure hilfe. Is mir n bissle peinlich wegen atmega 128 und atmega 8. Das hät ich eigentlich auch so sehen können. Jetzt glaub ich weiss ich wie es funktioniert.
Ich hoffe ich kann jetzt auch mal anderen Helfen, da ich noch nich so erfahren bin. Wie gesagt habe ich bisjetzt nur Commodore 64 und QBasic programmiert und wollte jetzt entlich auch mal Atmels proggen.
Vielen Dank noch einmal, die versucht (und auch geschafft) haben mir dies zu erklären.
Hunni

p.s. aber das mit dem USB stick is doch auch garkeine schlechte Idee oder?

stefan_Z
06.05.2008, 18:13
Einen USB-Stick ansprechen ist eine völlig andere Sportart!
Dafür braucht es einen USB-Host (halt den PC) - der müsste vom AVR emuliert werden - das kannste knicken.
FTDI hat allerdings einen Chip und auch so Module, die genau das leisten können. http://www.vinculum.com/prd_vmusic1.html

Duesentrieb
28.08.2010, 19:03
Hallo,

ich möchte eine SD Karte mit Messwerten beschreiben und diese am PC auslesen.
Da ich nur einen M32 benutze kann ich kein AVR Dos nutzen.
In einem älteren Beitrag habe ich folgenden Artikel gefunden:



Dann versuch es doch mal mit der einfachen Version, ohne AVR-DOS.
Ich weiß nicht, wieviel dein sonstiger Code ausmacht, aber der hier inklusive Lesen und Schreiben von 1000 Sektoren und Ausgabe auf den UART belegt gerade mal 1492 Byte, also noch viel Platz bis 4K.

$regfile = "M128def.dat"
$crystal = 16000000

$baud1 = 115200
Open "Com2:" As Binary As #1
Enable Interrupts

Dim Mmc_error As Byte
Dim In_ptr As Word ' Address-Pointer for read
Dim In_sect As Long
Dim In_buffer As String * 512
Print #1 , "Wait for Drive"
$include "Config_MMC.bas"
'Hier werden als Test die ersten 1000 Sektoren der Karte eingelesen und auf den UART ausgegeben und dann wieder auf die SD geschrieben.
In_ptr = Varptr(in_buffer)
If Gbdriveerror = 0 Then
Mmc_error = Driveinit()
If Mmc_error = 0 Then
Print #1 , "Driveinit Ok. "
For In_sect = 0 To 1000
Mmc_error = Drivereadsector(in_ptr , In_sect)
If Mmc_error = 0 Then
Print #1 , "ReadSector(" ; In_sect ; ") ok." 'Zum Inhalt drucken, Kommentare entfernen !!!!!!!!!!
Print #1 , In_buffer 'Dann wird es aber langsamer, 115200 baud beim übertragen
Mmc_error = Drivewritesector(in_ptr , In_sect)
Else
Print #1 , "Error during ReadSector(" ; In_sect ; ") : " ; Mmc_error
End If
Next In_sect
Else
Print #1 , "Error during Driveinit(): " ; Mmc_error
End If
End If

End
Hierbei werden die Sektoren direkt geschrieben. Das reicht für die Ein- und Ausgabe im µC.
Wenn du eine Datei in Windows sehen willst, legst du vorher eine dummy-Datei der benötigten Größe an und schreibst dann deren Sektoren.

Gruß

Rolf

Jetzt die Frage:
Wie und welche Datei muss ich anlegen, und wie weis ich auf welchen Sektoren sie liegt?

for_ro
28.08.2010, 20:24
Hi Duesentrieb,
ich habe das so gemacht:
Mit dem Editor eine Datei öffnen, Name z.B. Log01.txt, ist für den ATMEGA aber egal.
In die erste Zeile einen Text einfügen, der im normalen Betrieb nicht auftauchen kann. Ich habe da 510 Zeichen reingeschrieben
*12345678901234567890...123456789
Am Ende der Zeile ein Return fügt dann noch 2 Zeichen ein, nämlich <CR> und <LF>. Eine Zeile enthält dann 512 Zeichen, ist also genau einen Sektor lang.
Die Zeile habe ich dann im Editor kopiert bis die Datei 50MB groß war, also 100.000 Zeilen hatte.

Die SD Karte habe ich formatiert, sodass nichts auf der Karte steht.
Dann habe ich die Datei 20 mal auf die SD kopiert und jedesmal die Zahl im Namen erhöht. Die Dateien hießen also Log01.txt, Log02.txt, ..., Log20.txt. Insgesamt sind dies knapp 1GB.
Auf der SD stehen die Dateien dann direkt hintereinander, ohne Zwischenraum.

Wenn du nun immer sektorweise schreibst, füllst du eine Datei nach der anderen. Auf dem PC kannst du die Dateien weiterhin mit dem Editor öffnen, solange du immer 512 Zeichen pro Sektor hast und am End immer ein <CR> und ein <LF> steht.
Nachdem ich alles geschrieben hatte, habe ich die SD mit dem ATMEGA gelesen, und zwar die Sektoren von 0 an.
Wenn dann das erste Mal die Zeichenfolge *1234567890... gelesen wurde, hast du den Anfang der ersten Datei gefunden. Bei meiner 2GB Karte ist das der Sektor 768.

Durch den Trick mit der festen Zeichefolge brauche ich die aktuelle Sektornummer nicht zu speichern, sondern kann sie sehr schnell finden.
Du kannst dazu die "Binäre Suche" verwenden, da die Sektoren praktisch in zwei Bereiche geteilt sind: Die, die schon beschrieben wurden, und die, die noch frei sind (bei denen ist "*" das erste zeichen im Sektor).
Für meine 2.000.000 Sektoren muss ich dazu beim Programmstart nur 21 Sektoren lesen und habe den zuletzt geschriebenen Sektor gefunden.

Duesentrieb
28.08.2010, 20:41
Hallo for_ro,

danke für die schnelle Antwort.
Die Logik habe ich, denke ich, soweit verstanden.
Die erstellten txt-Datein sind dann von Anfang bis Ende mit der Zahlenfolge beschrieben.
Wenn der Atmega dort nun etwas hinschreibt, überschreibt er doch nur den text der so groß ist wie den der er schreibt, der Rest der urspr. Zahlenfolge bleibt doch bestehen, oder?


Edit:
Muss gleich nochne Frage stellen:
Mit "Drivewritesector" schreibe ich in den Sektor. Wie aber?
Die Hilfe hilft mir überhaupt nicht. Sieht so aus als ob da das wesentlich fehlt.
Kann mir jemand dazu den Syntax geben?

for_ro
28.08.2010, 22:26
Mit "Drivewritesector" schreibe ich in den Sektor. Wie aber?
Die Hilfe hilft mir überhaupt nicht. Sieht so aus als ob da das wesentlich fehlt.
Kann mir jemand dazu den Syntax geben?
Hier ein Auszug aus dem Code oben:

Dim In_ptr As Word ' Address-Pointer for read
Dim In_sect As Long 'Nr. des Sektors, der gelesen oder geschrieben werden soll
Dim In_buffer As String * 512 'der Ein- und Ausgabe Puffer, kann auch vom Typ Byte sein, oder 256 Word oder 128 Long Werte

In_ptr = Varptr(in_buffer) 'hier wird die Adresse des Puffers geholt
Mmc_error = Drivewritesector(in_ptr , In_sect) 'SektorNummer und Adresse werden übergeben

Es wird also in einen frei wählbaren Sektor geschrieben, und zwar 512 Byte, die im SRAM ab der Adresse In_ptr stehen. Auch wenn du in den In-Buffer weniger geschrieben hast, werden trotzdem 512 Byte auf die SD übertragen.

Duesentrieb
28.08.2010, 22:34
Sorry, ich habs immer noch nicht verstanden.
Angenommen ich möchte den Text "hallo Test" in Sektor 5 schreiben.
Wie müsste ich dies im Programm einbauen?

for_ro
28.08.2010, 22:37
In_buffer = "hallo Test"
In_sect = 5
Drivewritesector(in_ptr , In_sect)

Duesentrieb
28.08.2010, 22:45
es ist wie verhext.

So "einfach" habe ich das heute Abend sicher auch schon einmal versucht.
Hmm, hab mich wohl irgent wo vertippt. Egal - jetzt hats geklappt

Vielen Dank!

for_ro
28.08.2010, 22:52
Noch eins: Schreib lieber nicht in die Sektoren unterhalb des ersten Sektors der Datei. Dort hält Windows seine Tabellen. Wenn du dort schreibst, wird Windows die Karte nicht mehr lesen können.

Duesentrieb
28.08.2010, 23:17
o.k. Danke für den Hinweis!

Duesentrieb
29.08.2010, 00:28
Jetzt muss ich noch mal nerven.

InBuffer darf eine Länge von 512 Zeichen haben.
Ich möchte darin Datum, Zeit und einen Wert ablegen.

Die Frage hat weniger was mit der SD Karte zu tun als velmehr mit dem Thema der Variablen.

Wenn ich nun schreibe
InBuffer = Time$ ; " "; Date$ ; " " ; Wert
nimmt er diese nicht obwohl der Wert als String * 4 und Date$ und Time$ auch nur max. 16 Zeichen lang sind

Wie kann ich das machen?

for_ro
29.08.2010, 01:00
Jetzt muss ich noch mal nerven.
InBuffer = Time$ ; " "; Date$ ; " " ; Wert

Das Semikolon ist nur für die Ausgabe per Print oder auf das LCD gedacht.
Wenn du einen String aus einzelnen Strings zusammensetzen willst, mahst du das über +, also so
InBuffer = Time$ + " "+ Date$ + " " + Wert

Duesentrieb
29.08.2010, 10:16
Danke für die späte Antwort!