Forum: Mikrocontroller und Digitale Elektronik MircoSD per SPI


von Axel L. (ligonap)


Lesenswert?

Ich habe große Probleme eine MircoSD-Karte per SPI anzusprechen, um fünf 
wav-Dateien (22050Hz, 8-Bit unsigned, Mono) abzuspielen.

Für die Audioausgabe ist ein ATMega644A über Pin PB3 (OC0A) an einem 
LM386 (Gain20) verbunden. Ein Test der Audioausgabe mit einer 
synthetischen Tonleiter war erfolgreich.

Für das Auslesen der wav-Dateien, habe ich ein MicroSD Breakout Board+ 
von adafruit (http://www.adafruit.com/products/254) wie folgt 
angeschlossen:

Pin PB4 (SS) an CS
Pin PB5 (MOSI) an DI
Pin PB6 (MISO) an DO
Pin PB7 (SCK) an CLK
GND an GND
5V an 5V

Vergleichbar mit: 
http://circuitfun.files.wordpress.com/2009/02/spi-to-usd.jpg?w=497&h=345

Wenn ich den MyWavePlayer-Code von Holger Klabunde 
(Beitrag "Re: Sprachausgabe mit AVR") verwende und an 
den ATMeag644 anpasse, passiert nichts.
Alle Versuche den Timer0 (Fast-PWM) an PB3 zu aktivieren schlugen fehl.

1
#define SAMPLE_RATE        22050
2
#define TIMER0_OCR_VALUE    ((F_CPU / 8) / SAMPLE_RATE) - 1
3
4
5
void StartTimer(void)
6
{
7
 TCCR0A = (1<<COM0A1) | (0<<COM0A0) | (1<<WGM01) | (1<<WGM00); 
8
 TCCR0B |= (0<<CS02) | (0<<CS01) | (1 << CS00) | (1 << WGM02); 
9
 OCR0A = TIMER0_OCR_VALUE;
10
 DDRB |= (1<<PB3); 
11
 TIMSK0 |= (1<<OCIE0A);  
12
 TIFR0  |= (1<<OCF0A); 
13
}
14
15
16
17
void StopTimer(void)
18
{
19
   TIMSK0 &= ~(1 << OCIE0A);
20
}

Weiß jemand rat?
Wie überprüfe ich überhaupt die Funktionalität der MicroSD ohne eine 
Ausgabe per Terminal?

von Axel L. (ligonap)


Lesenswert?

Mit dem Code von Holger Klabunde kam ich nicht zurecht und bin auf die 
SPI/FAT-Lib von Daniel R. 
(http://www.mikrocontroller.net/articles/AVR_FAT32) gewechselt.

Leider bekomme ich immer noch keinen Ton aus dem µC.
Sowohl der Timer, als auch die korrekte Anbindung der MircoSD scheint 
schwierig. Die SPI-Lib benutzt nicht den SPI_SS aber ich schon, dafür 
MMC_Chip_Select, aber ich nicht. Kann man einfach beiden den gleich Port 
zuweisen?

Statt einer UART-Ausgabe verwende ich LEDs zur Statusanzeige. Da alle 
drei LEDs leuchten, gehe ich mal davon aus, dass ein Zugriff auf die 
MicroSD besteht.

Wenn der Timer korrekt eingestellt ist, dürfte die Abspielfunktion 
falsch sein.

1
#include <avr/io.h>
2
#include <avr/iom644.h>
3
#include <avr/interrupt.h>
4
  
5
#include "config.h"
6
#include "file.h"
7
#include "fat.h"
8
#include "mmc.h"
9
#include <string.h>  
10
#include <stdlib.h>
11
12
void PlayWave(char *name);
13
void StartTimer(void);
14
void StopTimer(void);
15
16
17
void PlayWave(char *name)
18
{
19
20
// Datei existiert also lesen. 
21
if(MMC_FILE_EXISTS == ffopen(name))
22
 {
23
24
  unsigned long int seek=file.length; // setzen einer Variable und dann runterzaehlen geht am schnellsten !
25
  
26
  StartTimer(); // start playing
27
28
  do{
29
    OCR0A = ffread();
30
    }while(--seek);
31
32
  StopTimer(); // stop playing
33
34
  ffclose();
35
  }
36
}
37
38
39
40
41
// Timer0 für die Audioausgabe
42
void StartTimer(void)
43
{
44
 TCCR0A = (1<<COM0A1) | (1<<COM0A0) | (1<<WGM01) | (1<<WGM00); // Mode 3: Fast PWM top=0xFF
45
 TCCR0B = (1<<CS00); // Fast PWM (mode 3), no prescaler 
46
47
 OCR0A = ((F_CPU / 8) / 22050) - 1; // Set interval timer (sampling period)  
48
49
 DDRB |= (1<<PB3); // OC0A
50
51
 TIMSK0 |= (1<<OCIE0A); //Start
52
 TIFR0  |= (1<<OCF0A); 
53
}
54
55
56
// Stoppt Timer0 für die Audioausgabe
57
void StopTimer(void)
58
{
59
 TIMSK0 &= ~(1<<OCIE0A); 
60
}
61
62
63
64
// Hauptprogramm */
65
int main(void)
66
{
67
68
// Als Ausgänge für die LEDs sind definiert:
69
DDRA = 0b11111111;
70
DDRC = 0b11111111;
71
72
PORTA |= (1<<PA7) ; //  ein -> System Ready!
73
74
75
// Versuch Karte zu Initialisieren, bis es klappt.
76
while (FALSE==mmc_init())
77
{
78
  nop();
79
  PORTA |= (1<<PA1) ; //  ein -> Karte gefunden!!
80
}
81
82
// Fat initialisieren.
83
while (FALSE==fat_loadFatData())
84
{
85
  //nop();
86
    PORTA |= (1<<PA4) ; // ein -> Init OK. Jetzt kann man lesen
87
}
88
89
90
PlayWave("ton_musi.wav"); // 22050Hz, 8-bit, Mono
91
92
93
94
while(1);
95
}

von Axel L. (ligonap)


Lesenswert?

Ich habe mich ausgiebig mit dem Datenblatt vom ATMega644A beschäftigt 
und dabei kam folgende Timer-Konfiguration heraus:

1
void StartTimer(void)
2
3
{
4
 // Set fast PWM mode 3, Timer0
5
 TCCR0A |= _BV(WGM01) | _BV(WGM00);
6
 TCCR0B &= ~_BV(WGM02);
7
8
 // Do non-inverting PWM on pin OC0A 
9
 TCCR0A = (TCCR0A | _BV(COM0A1)) & ~_BV(COM0A0);
10
 TCCR0A &= ~(_BV(COM0B1) | _BV(COM0B0));
11
12
 // No prescaling
13
 TCCR0B = (TCCR0B & ~(_BV(CS02) | _BV(CS01))) | _BV(CS00);
14
 
15
 
16
 // Set up Timer 1 to send a sample every interrupt.
17
18
 cli();
19
20
 // CTC Mode 4, Clkio/8 -> 2MHz at 16MHz F_CPU Timer 1
21
 TCCR1A &= ~(_BV(WGM11) | _BV(WGM10));
22
 TCCR1B = (TCCR1B & ~(_BV(WGM13) | _BV(CS12) | _BV(CS10))) | _BV(WGM12) | _BV(CS11);
23
24
 // Set the compare register (OCR1A).
25
 // OCR1A is a 16-bit register, so we have to do this with
26
 // interrupts disabled to be safe.
27
 OCR1A = TIMER1_OCR_VALUE;
28
29
 // Enable interrupt when TCNT1 == OCR1A 
30
 TIMSK1 |= (1<<OCIE1A); 
31
 
32
 //enable interrupts
33
 sei();
34
35
}

Zum Test der Audioausgabe über OCR0A (ISR Timer1), wurde mit Hilfe von 
wav2c eine sounddata.h generiert und erfolgreich getestet.


Zur Einbindung der MicroSD kämpfe ich immer noch mit der SPI/FAT-Lib von 
Klabunde. Folgender Code sollte eigentlich gehen:
1
PORTA |= (1<<PA7) ; // LED A ein -> System Start!
2
3
 MMC_IO_Init();
4
5
6
 if(GetDriveInformation()!=F_OK) // get drive parameters
7
  {
8
   PORTA |= (1<<PA4) ; // LED D ein -> No Flash!!
9
   while(1);
10
  }
11
 else
12
  { 
13
   PORTA |= (1<<PA1) ; // LED G ein -> Karte gefunden!!
14
  }

Beim Start des µC ohne MicroSD leuchten die LEDs A und D. Mit 
MicroSD-Karte leuchtet nur die LED A und nichts geschieht weiter.
Ein Abspielen der Sounddateien findet auch nicht statt.

Was könnte die Ursache sein??

von holger (Gast)


Lesenswert?

>Was könnte die Ursache sein??

Nur mal so nebenbei:
Der Originalcode benutzt Timer1 für die Samplerate
und Timer2 mit FastPwm für die Ausgabe an PD7.

Warum versuchst du es nicht erst einmal mit
dem Originalcode?

von Axel L. (ligonap)


Lesenswert?

holger schrieb:
>>Was könnte die Ursache sein??
>
> Nur mal so nebenbei:
> Der Originalcode benutzt Timer1 für die Samplerate
> und Timer2 mit FastPwm für die Ausgabe an PD7.
>
> Warum versuchst du es nicht erst einmal mit
> dem Originalcode?

Der µC ist auf einer vom mir entworfenen Platine gelötet und Änderungen 
sind nur sehr eingeschränkt möglich.

Der Audioausgang befindet sind am Pin PB3 (OC0A), so dass nur Timer 0 
für den Fast PWM mode in Frage kommt. Timer 1 übernimmt den CTC Mode. 
Timer 2 dient einem anderen Zweck, welcher bereits läuft und später mit 
der Audioausgabe gekoppelt werden soll.

Mal abgesehen davon, zum Aufruf der Funktion "void StartTimer(void)" 
kommt es erst gar nicht, weil die Bedingung 
"if(GetDriveInformation()!=F_OK)" weder die LED D noch die LED G 
leuchten lässt.

Scheinbar ein vorzeitiger Stopp.

von holger (Gast)


Lesenswert?

>Mal abgesehen davon, zum Aufruf der Funktion "void StartTimer(void)"
>kommt es erst gar nicht, weil die Bedingung
>"if(GetDriveInformation()!=F_OK)" weder die LED D noch die LED G
>leuchten lässt.
>
>Scheinbar ein vorzeitiger Stopp.

Das würde ich auch so sehen;)

Dein Board benutzt Spannungsteiler als Levelkonverter.
Das ist schon mal ziemlicher Schrott.

Abgesehen davon dürfte das Programm nicht hängen bleiben. Benutzt
du den SS Pin als Ausgang? Oder hast du da auch
dran rumgefummelt?

von holger (Gast)


Lesenswert?

So, aus dem Originalcode

> // CTC Mode, Clkio/8 -> 2MHz at 16MHz F_CPU
> TCCR1A = (0<<COM1A1) | (0<<COM1A0) | (0<<WGM11) | (0<<WGM10);
> TCCR1B = (0<<WGM13) | (1<<WGM12) | (0<<CS12) | (1<<CS11) | (0<<CS10);

Ok, etwas kürzer

 TCCR1A = 0;
 TCCR1B = (1<<WGM12) | (1<<CS11);


Und was machst du? Bullshit.

 // CTC Mode 4, Clkio/8 -> 2MHz at 16MHz F_CPU Timer 1
 TCCR1A &= ~(_BV(WGM11) | _BV(WGM10));
 TCCR1B = (TCCR1B & ~(_BV(WGM13) | _BV(CS12) | _BV(CS10))) | _BV(WGM12) 
| _BV(CS11);

von Axel L. (ligonap)


Lesenswert?

holger schrieb:
> Abgesehen davon dürfte das Programm nicht hängen bleiben. Benutzt
> du den SS Pin als Ausgang? Oder hast du da auch
> dran rumgefummelt?

holger schrieb:
> Und was machst du? Bullshit.

Bitte hier im Forum nicht ausfallend werden, sondern sachlich bleiben. 
So ist keinem gedient.
Dieses Forum dient dazu bei Problemen mit µC zu helfen.


Wie bereits oben erwähnt, ist der µC wie folgt angeschlossen:
Pin PB4 (SS) an CS
Pin PB5 (MOSI) an DI
Pin PB6 (MISO) an DO
Pin PB7 (SCK) an CLK
GND an GND
5V an 5V

Zwischen µC und SD-Karte selber ist ein 4050D Pegelwandler, sowie eine 
4,7k/10K-GND Spannungsteilung auf den Leitungen MOSI, SS und SCK.

Letzter kann entfernt werden, so dass der µC direkt an den 4050D 
angeschlossen ist.

von Axel L. (ligonap)


Lesenswert?

Nachtrag:
Nach Durchsicht des Datenblattes zum 4050D, habe ich die drei 4,7K 
entfernt, aber die drei 10K belassen. Folge: Es kann auf die MicroSD 
zugegriffen werden. Somit war die Spannungsteilung die Ursache, was ich 
ein wenig komisch finde.

Danke für den Tipp.

von maveric00 (Gast)


Lesenswert?

Hallo,

SPI ist bei MikroSD optional, unterstützt Deine Karte SPI?

Schöne Grüße,
Martin

von maveric00 (Gast)


Lesenswert?

Hallo,

aus irgend einem Grund haben sich unsere Antworten überschnitten - die 
Antwort lautet also Ja ;-)

Schöme Grüße,
Martin

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.