mikrocontroller.net

Forum: Compiler & IDEs das ewige Leid mit dem SPI


Autor: loki81 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hey,

Ich versuche einen 10bit ADW mit meinem MCU über den SPI auszulesen. Ich 
weiß, dass ich ihm erst 8bit schicken muss damit er wandelt. Dann kann 
ich mit nem schreiben einer 0 auf das SPDR die ersten 8bits abholen und 
mit einem erneuten schreiben einer 0 auf SPDR die 2. 8 bits. So weit so 
gut, denn das Ding zeigt mir immer nur 11111111  11111111 an.

Das kann garnicht sein denn im Datenblatt heisst es: Das Ergebnis kommt 
mit einer "leading zero".

Ich hab das ganze im AVR Studio noch mal simuliet und da ist mit 
aufgefallen, dass dach dem ich

SPDR=0;

gesetzt habe, das SPDR im nächsten Takt wieder den vorrangegangenen wert 
annimmt. Ist das normal? ist das der Fehler? oder kann mir jemand sagen 
wo hier der Fehler liegt??

Ich hänge hier noch mal meinen code dran....

int read_max(void)
{
  unsigned int ReHigh, ReLow, tot;
  spi_on(); ----------(/SS = 0)
  _delay_us(100);
  SPDR=0xae;-------(code für den AD: Kanal 4, eigener Takt)
  loop_until_bit_is_set(SPSR, SPIF);
  ReHigh=SPDR;
  _delay_ms(100);

  SPDR=0;

!!!! Nach diesem Befehl nimmt SPDR wieder den vorrangegangenen Wert 
an!!!

           loop_until_bit_is_set(SPSR, SPIF);
  ReHigh=SPDR;
  _delay_us(100);
  SPDR=0;
  loop_until_bit_is_set(SPSR, SPIF);
  ReLow=SPDR;
  _delay_us(100);
  spi_off();
  tot=(unsigned int)((ReHigh*256+ReLow)/8);
  return tot;
}

Wäre super wenn mir jemand helfen könnt ich bin hier am verzweifeln!!

MfG
loki

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> das SPDR im nächsten Takt wieder den vorrangegangenen wert
> annimmt.

SPDR Lesen und SPDR Schreiben sind zwei völlig verschiedene Dinge.

Bist du dir sicher, dass du den korrekten SPI-Mode benutzt?  Es gibt
4 verschiedene Varianten, wie man das Ruhepotenzial von SCK und
die Taktflanken miteinander kombinieren kann.

Autor: loki81 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn die Flanken des Taktes CPOL sind dann sind die schon vom ADW 
vorgegeben. Im Datenblatt steht drin wie ich die einstellen muss.

Wie ist das genau mit diesen 4 verschiedenen Einstellunge? Hab keinen 
Plan davon.

Ich weiß dass ich schreibe mit SPDR=0x00 und lese mit ReLow=SPDR. ist 
denn das so richtig?

Ich bin so frustriert gerade und MAN ich muss das Ding bis morgen fertig 
haben und es will nicht.

Für Hilfe wäre ich mehr als dankbar

loki

Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Register weiss ich gerade net aus dem Kopf, aber die beiden Bits weiss 
ich noch.

?? |= (1<<CPHA) | (1<<CPOL)

Schau mal ins Datenblatt zum AVR. In dem Db stehen alle 4 Modis mit 
Timing Model.

Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hatte durch Zufall noch einen Code fuer einen SPI AD Wandler hier, 
vielleicht hilft der weiter:
#include <avr/io.h>

// Mega16 Pinout
#define MOSI  4
#define MISO  6
#define SCLK  7
#define SS    4



unsigned int get_adc(unsigned char adata)
{
  static unsigned int temp=0;
  
  PORTB &= ~(1<<SS);                  // set cs on low to activied the adc
                                      // maybe here a little delay
  SPDR = adata;                        // put the data into send register
  while(!(SPSR & (1<<SPIF)));          // send 1 Byte over HW SPI and wait for tx complete int  
  temp = SPDR;                        // put the received data to a static temp variable
  temp = temp << 8;                    // shift the temp variable 8 steps left
  SPDR = adata;                        // put the data into send register
  while(!(SPSR & (1<<SPIF)));          // send 1 Byte over HW SPI and wait for tx complete int    
  temp |= SPDR;                        // put the received data to a static temp variable
  PORTB |= (1<<SS);                    // set cs on high to disable the adc
  return temp;                        // return the adc value
}



void spim_init(void)
{
  // SET the Ports to output 
  DDRB |= (1<<MOSI) | (1<<SCLK) | (1<<SS);
  // SET MISO to input
  DDRB &= ~(1<<MISO); 
  // SPI Enable, SPI Master, SPI CLK XTAL/16, LSB First
  SPCR |= (1<<SPE)|(1<<MSTR)|(1<<SPR0);    
  PORTB |= (1<<SS);    // CS High because the SPI ADC is low active
}

int main (void)
{
  static unsigned int adc_value=0;  // uint variable
  
  spim_init();                       // Init HW SPI Master
  adc_value = get_adc(0xFF);        // Get data from SPI ADC send anything to generate the clock

  for(;;){}
}

  
  


Autor: loki81 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Super.....

Danke für den Code ich versuch ihn mal.

Die 2 Bits (CPHA und CPOL) sollen laut Datenblatt vom ADW (Max147) auf 
low liegen. Was das bewirkt keinen Plan aber ich denk mal wenn das da so 
drin steht dann mach ich das doch mal so..... Ach man das mit dem Timing 
und dem Clock ding ist do was wie chinesisch für mich´.

So ich schau mal was dein Code macht und meld mich dann noch mal.

Danke noch mal

loki

Autor: loki81 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dieser ADW ist ein bescheidenes DING!!

Man der funst einfach nicht. Ich bekomme immer noch nur 11111111 
11111111 Mehr will der einfach nicht ausspucken.
Ich frag mich nur warum der nur einser ausspuckt! Da muss es doch nen 
Grund für geben.

Noch ne Frage:

Was ist das denn mit dem Buffer? Und woher weiß der MCU dass ich sein 
SPDR ausgelesen habe und er jetzt bitte das Verzeichniss löscht und was 
neues rein schreiben soll? Hat der da irgendein Register für? Oder wie 
kann ich denn den Puffer löschen?

Mein Problem ist denke ich mal dass immer wenn ich ne neue 1 in den ADW 
reintackte dieser wieder neu wandelt und im ersten Byte bekanntlich nur 
Mist ausgibt.

Ich steh grad voll auf dem Schlauch!! und irgendwie ist alles was mal so 
klar war in nem Wust untergegangen!!!

Loki

Autor: Patrick K (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nur einsen 11111111 oder 0xFF bekommt ich am SPI auch wenn die 
verdahtung nicht stimmt. nimm mal ein oszi zur hand und schau was genau 
am ADC kommt. oder haeng den ADC mal ab und leg die MISO leitung auf 
ground. dann muesstest du 0x00 empfangen. somit kannst du wenigstens den 
fehler etwas weiter eingrenzen.

Autor: Benjamin Klimmek (benjaminklimmek)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Zusammen,

vielleicht ist das nicht relevant, aber wenn ich die aller ersten 
Codesequenz nachvollziehe, dann hast du zwei Delayzeiten eingebaut...
.....
_delay_us(100)
....
...
_delay_ms(100)


Ich bin mir gerade nicht ganz sicher, aber wenn Du die Standard 
_delay_xx Funktion von AVR-Studio genommen hast, dann kann es sein, dass 
Deine Zeiten nicht stimmen. Denn ich meine man kann nur eine delay-Zeit 
bis 32ms definieren.

Falls Du den Code von Dirk einfach so genommen hast, ohne die Zeiten 
einzubringen und der AD-W ist ein bißchen langsamer, dann ist er mit er 
Wandlung noch nicht fertig.

Probiers das mal!!

Gruß
Benjamin

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.