AD5292 mit SPI des ATmega32 ansteuern

OP #3711268
Lesenswert?

Hallo,

Für ein Projekt muss ich über einen digitalen Potentiometer AD5292 
mittels eines ATmega32 ansteuern. Der ATmega32 beherrscht ja SPI, also 
sollte das theoretisch möglich sein. Nur ich bekomme es einfach nicht 
hin.

Zu meiner Entwicklungsumgebung für den ATmega32 gehört das Atmel 
Evaluluationsboard V2.0.1. Dabei habe ich an dem Board alles unverändert 
gelassen (auch Jumper drin gelassen), sodass ich die Ausgänge über JP4 
rausführe. Programmieren tue ich mit Atmel Studio 6 sowie einen 
ISP-Programmer mit STK500.

Die Entwicklungsumgebung funktioniert auch soweit, da ich dies schon mit 
anderen Projekten erfolgreich getestet habe. Mir macht einfach die 
Ansteuerung des AD5292 Kopfzerbrechen. Im Netz habe ich auch speziell zu 
dieser Konfiguration nichts gefunden.

Mein Code sieht folgendermaßen aus:
1
#include <avr/io.h>
2

3
#define DDR_SPI      DDRB
4
#define DD_MOSI      DDB5
5
#define DD_SCK      DDB7
6
#define DD_SS      DDB4
7

8
void SPI_INIT (void)
9
{
10
  DDR_SPI |= (1<<DD_MOSI) | (1<<DD_SCK) | (1<<DD_SS);       // Set MOSI , SCK , and SS output
11
  SPCR = ( (1<<SPE)|(1<<MSTR) | (1<<SPR1) |(1<<SPR0));  // Enable SPI, Master, set clock rate fck/128
12
}
13

14
void SPI_DATA (char data)
15
{
16
  SPDR = data;                                                         // Send data
17
  while(!(SPSR & (1<<SPIF))){;                                         // Wait
18
    
19
  }
20
}
21

22
int main(void)
23
{
24
  
25
  SPI_INIT();
26
  PORTB = PORTB & 0b11101111;      // SS low
27
  SPI_DATA (0b00011000);             // Command #6
28
  SPI_DATA (0b00000011);
29
  SPI_DATA (0b00000110);           // Command #1
30
  SPI_DATA (0b00000000);
31
  PORTB = PORTB | 0b00010000;     // SS high
32
  
33
    while(1)
34
    {
35

36
    }
37
}

Also über SS, MOSI und SCK werden auf jeden Fall Signale rausgesendet. 
Nur am Widerstand des Potentiometers ändert sich nichts. Eigentlich 
müsste ich auch alles richtig verdrahtet haben.

Da ich das Projekt recht zügig fertigkriegen muss, wäre ich über jede 
erdenkliche Hilfestellung sehr dankbar. Eventuell haben auch andere 
Leute dasselbe Problem.

Vielen Dank im Vorraus!

Mit freundlichen Grüßen,

Cheng L.
Gast #3717963
Lesenswert?

Hey,

schon Mal probiert die <spi.h> einzubinden?
Dann würde ich gern wissen wollen, woher du weißt, dass auch die 
richtigen Bits zur richtigen Zeit ankommen? Hast du ein Oszi da?
Lad´ mal bitte der Einfachheit halber den Schaltplan µC-DigPoti hoch.


MfG
guest111
OP #3718026
Lesenswert?

Hallo,

Danke für deine hilfreiche Antwort!

Ich habe den Teil µC-DigPoti als Bild hochgeladen. Im Schaltplan steht 
noch Mega8, weil ich das später mal verwenden möchte. Eigentlich sollte 
ja richtig angeschlossen sein:

PB2 (SS) --> SYNC
PB4 (MISO) --> DIN
PB (SCK) --> SCLK

Ich werde das mal mit der <spi.h> ausprobieren.

Ansonsten weiss ich, dass ISP und SPI sich behindern, jedoch habe ich 
zuerst das DigiPoti nicht angeschlossen, um per ISP das Programm in den 
µC zu laden. Anschließend erst die SPI Pins belegt.

Gibt es zu dieser Konfiguration irgendwelche fertigen Code Beispiele?

Auf weitere hilfreiche Antworten würde ich mich sehr freuen.

Viele Grüße,

Cheng L.
Angehängte Dateien:
OP #3718173
Lesenswert?

Also ich habe es mit spi.h und Reset des AD5292 auf low versucht. Leider 
klappt das immer noch nicht.

Hier der Code für spi.h, was ich gefunden habe:
1
#ifndef _SPI_H_
2
#define _SPI_H_
3

4
#include <avr/io.h>
5

6

7
extern void spi_init();
8
extern void spi_transfer_sync (uint8_t * dataout, uint8_t * datain, uint8_t len);
9
extern void spi_transmit_sync (uint8_t * dataout, uint8_t len);
10
extern uint8_t spi_fast_shift (uint8_t data);
11

12

13
#endif /* _SPI_H_ */

Und hier nun mein neues Programm:
1
#include <avr/io.h>
2
#include "spi.h"
3
#include <avr/interrupt.h>
4

5
#define PORT_SPI    PORTB
6
#define DDR_SPI     DDRB
7
#define DD_MISO     DDB6
8
#define DD_MOSI     DDB5
9
#define DD_SS       DDB4
10
#define DD_SCK      DDB7
11

12
void spi_init()
13
// Initialize pins for spi communication
14
{
15
  DDR_SPI &= ~((1<<DD_MOSI)|(1<<DD_MISO)|(1<<DD_SS)|(1<<DD_SCK));
16
  // Define the following pins as output
17
  DDR_SPI |= ((1<<DD_MOSI)|(1<<DD_SS)|(1<<DD_SCK));
18

19
  SPCR = ((1<<SPE)|               // SPI Enable
20
          (0<<SPIE)|              // SPI Interupt Enable
21
          (0<<DORD)|              // Data Order (0:MSB first / 1:LSB first)
22
          (1<<MSTR)|              // Master/Slave select
23
          (0<<SPR1)|(1<<SPR0)|    // SPI Clock Rate
24
          (0<<CPOL)|              // Clock Polarity (0:SCK low / 1:SCK hi when idle)
25
          (0<<CPHA));             // Clock Phase (0:leading / 1:trailing edge sampling)
26

27
  SPSR = (1<<SPI2X);              // Double Clock Rate
28
}
29
 
30
void spi_transfer_sync (uint8_t * dataout, uint8_t * datain, uint8_t len)
31
// Shift full array through target device
32
{
33
  uint8_t i;
34
  for (i = 0; i < len; i++) {
35
    SPDR = dataout[i];
36
    while((SPSR & (1<<SPIF))==0);
37
    datain[i] = SPDR;
38
  }
39
}
40
 
41
void spi_transmit_sync (uint8_t * dataout, uint8_t len)
42
// Shift full array to target device without receiving any byte
43
{
44
  uint8_t i;
45
  for (i = 0; i < len; i++) {
46
    SPDR = dataout[i];
47
    while((SPSR & (1<<SPIF))==0);
48
  }
49
}
50

51
uint8_t spi_fast_shift (uint8_t data)
52
// Clocks only one byte to target device and returns the received one
53
{
54
  SPDR = data;
55
  while((SPSR & (1<<SPIF))==0);
56
  return SPDR;
57
}
58

59
int main(void)
60
{
61
  
62
  // Allocate buffer array
63
  uint8_t data_buf[1];
64
  // Initialize SPI
65
  spi_init();
66
  // SS low
67
  PORTB = PORTB & 0b11101111;
68
  
69
  // Command #6
70
  data_buf[0] = 0b00011000;
71
  spi_transmit_sync(data_buf,1);
72
  data_buf[0] = 0b00000011;
73
  spi_transmit_sync(data_buf,1);
74
  
75
  // Command #1
76
  data_buf[0] = 0b00000110;
77
  spi_transmit_sync(data_buf,1);
78
  data_buf[0] = 0b00000000;
79
  spi_transmit_sync(data_buf,1);
80
  
81
  // SS high  
82
  PORTB = PORTB | 0b00010000;
83
}

Was mache ich bloss falsch?
Gast #3719410
Lesenswert?

Also deine Schaltung kann man ja echt vergessen. Dort kann ich nix 
erkennen, weil A) alle Leiterzüge kreuz und quer gehen
und  B) nur ein Teil der Schaltung zu erkennen ist.

Nichtsdestotrotz...warum übergibst du der Funktion spi_transmit_sync() 
denn die Datenlänge 1Bit?? Du willst doch 1Byte haben also 8Bit.
Schau dir bitte noch mal genau Seite 9 und Seite 22 an. Auf Seite 9 ist 
auch ein schönes Beispiel, wie man Daten schreibt (Figure 3). Dazu musst 
du das RESET Pin eigentlich nicht beachten, weil das nur für das Löschen 
des RDAC Registers genutzt wird. Aber du kannst es auch einfach 
überschreiben.
Ach...und wenn du den Widerstand des Potis ändern möchtest, musst du 
nach Zeile 2 der Tabelle 11 auf Seite 22 vorgehen.

Nur so nebenbei PORTB = PORTB & 11... ist vom Stil her Quatsch. Eher 
PORTB=11...

MfG
guest111
OP #3720071
Lesenswert?

guest111 schrieb:
> Also deine Schaltung kann man ja echt vergessen. Dort kann ich nix
> erkennen, weil A) alle Leiterzüge kreuz und quer gehen
> und  B) nur ein Teil der Schaltung zu erkennen ist.
>
> Nichtsdestotrotz...warum übergibst du der Funktion spi_transmit_sync()
> denn die Datenlänge 1Bit?? Du willst doch 1Byte haben also 8Bit.
> Schau dir bitte noch mal genau Seite 9 und Seite 22 an. Auf Seite 9 ist
> auch ein schönes Beispiel, wie man Daten schreibt (Figure 3). Dazu musst
> du das RESET Pin eigentlich nicht beachten, weil das nur für das Löschen
> des RDAC Registers genutzt wird. Aber du kannst es auch einfach
> überschreiben.
> Ach...und wenn du den Widerstand des Potis ändern möchtest, musst du
> nach Zeile 2 der Tabelle 11 auf Seite 22 vorgehen.
>
> Nur so nebenbei PORTB = PORTB & 11... ist vom Stil her Quatsch. Eher
> PORTB=11...
>
> MfG
> guest111

Ja, du hast recht, dass meine Schaltung ziemlich unübersichtlich ist. Es 
hat aber auch Gründe, deshalb gebe ich eben nur den relevanten Teil 
preis. Generell sollte ich alles richtig angeschlossen haben:

SS (PB4) beim Atmega32 --> Pin 13 auf J4 des Eva-Boards --> SYNC (Pin 
12) beim AD5292

MOSI (PB5) beim Atmega32 --> Pin 14 auf J4 des Eva-Boards --> DIN (Pin 
10) beim AD5292

SCK (PB7) beim Atmega32 --> Pin 16 auf J4 des Eva-Boards --> SCLK (Pin 
11) beim AD5292

Mein C Code habe ich auch etwas abgeändert. Dabei habe ich mir das 
Timing Diagram von Seite 9 genauer angeschaut. Anfangs braucht man wohl 
eine fallende Flanke beim SYNC, um den Datentransfer zu aktivieren. Auf 
Seite 23 gibt es eine kleine Tabelle, die besagt, dass zuerst 0x1803 
geschrieben werden muss, damit der Chip überhaupt die Wiper-Position 
updaten kann. Anschließend habe ich kann ich erst Befehle #1 von Seite 
22 einschleusen (ich habe beispielsweise 0x0500 geschrieben. Jedoch 
klappt es weiterhin nicht, per DMM messe ich immer noch 10 KOhm, also 
der Wiper befindet sich immer noch in der Mitte.

Hier mein C Code:
1
#include <avr/io.h>
2
#include "spi.h"
3
#include <avr/interrupt.h>
4

5
#define PORT_SPI    PORTB
6
#define DDR_SPI     DDRB
7
#define DD_MISO     DDB6
8
#define DD_MOSI     DDB5
9
#define DD_SS       DDB4
10
#define DD_SCK      DDB7
11

12
void spi_init()
13
// Initialize pins for spi communication
14
{
15
  DDR_SPI &= ~((1<<DD_MOSI)|(1<<DD_MISO)|(1<<DD_SS)|(1<<DD_SCK));
16
  // Define the following pins as output
17
  DDR_SPI |= ((1<<DD_MOSI)|(1<<DD_SS)|(1<<DD_SCK));
18

19
  SPCR = ((1<<SPE)|               // SPI Enable
20
          (0<<SPIE)|              // SPI Interupt Enable
21
          (0<<DORD)|              // Data Order (0:MSB first / 1:LSB first)
22
          (1<<MSTR)|              // Master/Slave select
23
          (0<<SPR1)|(1<<SPR0)|    // SPI Clock Rate
24
          (0<<CPOL)|              // Clock Polarity (0:SCK low / 1:SCK hi when idle)
25
          (0<<CPHA));             // Clock Phase (0:leading / 1:trailing edge sampling)
26

27
  SPSR = (1<<SPI2X);              // Double Clock Rate
28
}
29
 
30
void spi_transmit_sync (uint8_t dataout)
31
// Shift full array to target device without receiving any byte
32
{
33
  SPDR = dataout;
34
  while((SPSR & (1<<SPIF))==0);
35
}
36

37
int main(void)
38
{  
39
  // Allocate variable
40
  uint8_t data_buf;
41
  // Initialize SPI
42
  spi_init();
43
  
44
  // SS high
45
  PORTB = 0b00001000;
46
  // SS low --> falling edge
47
  PORTB = 0b00000000;
48
  // Command #6 --> enable update of wiper position through digital interface
49
  data_buf = 0x18;
50
  spi_transmit_sync(data_buf);
51
  data_buf = 0x03;
52
  spi_transmit_sync(data_buf);
53
  // SS high
54
  PORTB = 0b00001000;
55
  
56
  // SS high
57
  PORTB = 0b00001000;
58
  // SS low --> falling edge
59
  PORTB = 0b00000000;
60
  // Command #1 --> wiper moves to 1/4 full-scale position
61
  data_buf = 0x50;
62
  spi_transmit_sync(data_buf);
63
  data_buf = 0x00;
64
  spi_transmit_sync(data_buf);
65
  // SS high  
66
  PORTB = 0b00001000;
67
}

Ich bin teilweise echt am verzweifeln. Über jeglichen Ratschlag und 
Hilfe wäre ich sehr dankbar!
Gast #3720529
Lesenswert?

Hast du denn nicht mal die Möglichkeit deine Bits zu überprüfen? Das 
macht es doch alles einfacher! Erst, wenn du sicher weist, dass die Bits 
an der richtigen Stelle ankommmen, kannst du verzweifeln :)

MfG
guest111

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren