Forum: Compiler & IDEs das ewige Leid mit dem SPI


von loki81 (Gast)


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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von loki81 (Gast)


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

von Dirk (Gast)


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.

von Dirk (Gast)


Lesenswert?

Hatte durch Zufall noch einen Code fuer einen SPI AD Wandler hier, 
vielleicht hilft der weiter:
1
#include <avr/io.h>
2
3
// Mega16 Pinout
4
#define MOSI  4
5
#define MISO  6
6
#define SCLK  7
7
#define SS    4
8
9
10
11
unsigned int get_adc(unsigned char adata)
12
{
13
  static unsigned int temp=0;
14
  
15
  PORTB &= ~(1<<SS);                  // set cs on low to activied the adc
16
                                      // maybe here a little delay
17
  SPDR = adata;                        // put the data into send register
18
  while(!(SPSR & (1<<SPIF)));          // send 1 Byte over HW SPI and wait for tx complete int  
19
  temp = SPDR;                        // put the received data to a static temp variable
20
  temp = temp << 8;                    // shift the temp variable 8 steps left
21
  SPDR = adata;                        // put the data into send register
22
  while(!(SPSR & (1<<SPIF)));          // send 1 Byte over HW SPI and wait for tx complete int    
23
  temp |= SPDR;                        // put the received data to a static temp variable
24
  PORTB |= (1<<SS);                    // set cs on high to disable the adc
25
  return temp;                        // return the adc value
26
}
27
28
29
30
void spim_init(void)
31
{
32
  // SET the Ports to output 
33
  DDRB |= (1<<MOSI) | (1<<SCLK) | (1<<SS);
34
  // SET MISO to input
35
  DDRB &= ~(1<<MISO); 
36
  // SPI Enable, SPI Master, SPI CLK XTAL/16, LSB First
37
  SPCR |= (1<<SPE)|(1<<MSTR)|(1<<SPR0);    
38
  PORTB |= (1<<SS);    // CS High because the SPI ADC is low active
39
}
40
41
int main (void)
42
{
43
  static unsigned int adc_value=0;  // uint variable
44
  
45
  spim_init();                       // Init HW SPI Master
46
  adc_value = get_adc(0xFF);        // Get data from SPI ADC send anything to generate the clock
47
48
  for(;;){}
49
}

von loki81 (Gast)


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

von loki81 (Gast)


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

von Patrick K (Gast)


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.

von Benjamin K. (benjaminklimmek)


Lesenswert?

Hallo Zusammen,

vielleicht ist das nicht relevant, aber wenn ich die aller ersten 
Codesequenz nachvollziehe, dann hast du zwei Delayzeiten eingebaut...
1
.....
2
_delay_us(100)
3
....
4
...
5
_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

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.