Forum: Mikrocontroller und Digitale Elektronik MCP4728 I2C DAC und Atmega32: Problem beim auslesen


von Tony S. (tooony)


Angehängte Dateien:

Lesenswert?

Hallo Leute,

aktuell möchte ich einen MCP4728 DAC wie I2C an einem Atmega32 
betreiben. Der Atmega32 ist mit normaler Grundschaltung beschalten, der 
MCP4728 wie laut Datenblat (Siehe Anhang). Wobei LDAC und RDY/BSY 
aktuell nicht mit dem Atmega verdrahtet sind.

Folgende Werte:
R1 und R2: 4,7 KOhm
R3: 100KOhm
C1 (Kerko): 100n
C2 (Elko): 4,7µ

VDD: 5 Volt

Zum Auslesen des DAC nutze ich die I2C Lib von Peter Fleury. Der MCP4728 
ist in der Standardkonfiguration, d.h. hat dieser noch seine 
Standardadresse am I2C Bus. Zunächst wollte ich wie laut Datenblatt 
(http://ww1.microchip.com/downloads/en/DeviceDoc/22187E.pdf) nach Figur 
5-10 ein Single Write Command relaisieren um Channel A anzusprechen und 
die maximale Spannung einzustellen.

Folgende Parametrierung:

- Vref: intern (2.048 V)
- Power mode: normal
- Gain: 1 (Faktor 1)

Mein Code dazu sieht wie folgt aus:
1
#define F_CPU 8000000UL
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include "i2cmaster.h"
5
6
#define CMD_FCT_FIELDS_SINGLEWRITE  0b01011
7
#define ADDR (0b1100000 << 1)
8
9
int main(void) {
10
  
11
  i2c_init();
12
  
13
  uint8_t channel = 0;
14
  uint8_t udac = 0;
15
  
16
  // MCP4728 SingleWrite
17
  
18
  // device addressing
19
  i2c_start(ADDR + I2C_WRITE);
20
  
21
  // 2nd byte: single write cmd + channel select + udac
22
  i2c_write((CMD_FCT_FIELDS_SINGLEWRITE << 3) + (channel << 1) + udac);
23
  
24
  // 3rd byte: vref, pd1, pd0, gx, d11-d8
25
  i2c_write(0b10001111);
26
  
27
  // 4th byte: D7-D0
28
  i2c_write(0b11111111);
29
  i2c_stop;
30
  
31
}

Am Ausgang von Channel A tut sich jedoch nichts. Schreibe ich mir die 
einzelnen Zwischenschritte testweise mittels UART raus, sehe ich das er 
meistens bei i2c_start hängen bleibt...

Selbst wenn der i2c Teil durchläuft tut sich am Ausgang nix. Mit dem 
Multimeter messe ich eine Spannung von 0,6 Volt.

Hat jemand eine Idee? Handelt es sich hierbei umd eine fehlerhafte 
Umsetzung des Protokolls? Ist der IC defekt? Hat jemand schonmal 
intensiver mit dem Bauteil gearbeitet?

Danke schonmal für eure Hinweise!

von Bastian W. (jackfrost)


Lesenswert?

Bekommst du überhaupt ein ACK vom DAC ? Prüf das mal im Code. I2c_start 
gibt dir ja als Rückgabe 1 oder 0

Gruß JackFrost

von Tony S. (tooony)


Lesenswert?

Bastian W. schrieb:
> Bekommst du überhaupt ein ACK vom DAC ? Prüf das mal im Code. I2c_start
> gibt dir ja als Rückgabe 1 oder 0

Nein da kommt kein ACK zurück.

von Bastian W. (jackfrost)


Lesenswert?

Stimmt die Adresse ? Hast du ein Oszi oder einen LA ?
Sind die richtigen Ports in der Init bzw in der Headerdatei eingetragen 
?

Wie sind die Pegel ohne I2C Kommunikation wenn nur die init aufgerufen 
wurde aber der Rest nicht ?


Gruß JackFrost

von Tony S. (tooony)


Lesenswert?

Hallo Leute,

entschuldigt die späte Rückmeldung...

Also den MCP4728 kann ich nun ansteuern. Ich habe mir dazu eine Lib 
geschrieben, die ich dann auch gerne hier bereitstellen möchte, wenn 
Bedarf ist.

Jedoch bleibt noch eine Sache offen: Die Ansteuerung via General Calls 
und dem LDAC Pin, insbesondere in erster Linie das Lesen (und Schreiben) 
der I2C Adresse des MCP4728.

Das Protokoll dazu ist in der PDF auf Seite 33 (5.4.4) dargestellt.
http://ww1.microchip.com/downloads/en/DeviceDoc/22187E.pdf

In meinem Fall ist der LDAC Pin direkt mit dem Atmega32 PA0 Pin 
verbunden.

Für die I2C Kommunikation verwende ich die Lib von Peter Fleury.

Folgenden Code habe ich bisher erfolglos getestet:

Aus der MAIN:
1
...
2
3
DDRA |= (1 << PA0);
4
PORTA |= (1 << PA0);
5
i2c_init();
6
7
uint8_t addr = mcp4728_readAddr(PA0);
8
9
...

die Funktion mcp4728_read_addr:
1
uint8_t mcp4728_readAddr(uint8_t ldac_pin)
2
{
3
  PORTA |= (1 << ldac_pin);
4
  i2c_start(MCP4728_GENERAL_CALL);
5
  if(i2c_write_ldac(MCP4728_READADDRESS, ldac_pin) == 1) {
6
    i2c_stop();
7
          return 1;
8
  }
9
  
10
  if(i2c_start(MCP4728_RESTART) == 1) {
11
    i2c_stop();
12
    return 1;
13
  }
14
    
15
  //i2c_start_wait(MCP4728_RESTART);
16
  
17
  uint8_t addrByte = i2c_readAck();
18
  i2c_stop();
19
  
20
  return addrByte;  
21
}

Die Funktion i2c_write_ldac (um das Timeing des LDAC Pins zu erreichen:
1
unsigned char i2c_write_ldac( unsigned char data , uint8_t ldac)
2
{
3
  uint8_t   twst;
4
  
5
  // send data to the previously addressed device
6
  TWDR = data;
7
  TWCR = (1<<TWINT) | (1<<TWEN);
8
  
9
  _delay_us(86);
10
  PORTA &= ~(1 << ldac);
11
12
  // wait until transmission completed
13
  while(!(TWCR & (1<<TWINT)));
14
  
15
  // check value of TWI Status Register. Mask prescaler bits
16
  twst = TW_STATUS & 0xF8;
17
  if( twst != TW_MT_DATA_ACK) return 1;
18
  return 0;
19
20
  }/* i2c_write */

Um das Timeing für den LDAC Pin zu erreichen habe ich versucht nach dem 
Absenden der Daten mir mit einem Delay zu helfen, jedoch ohne Erfolg. Im 
Grunde ist das die gleiche i2c_write Funktion wie von Peter Fleury, nur 
eben mit dem delay.

Hat jemand einen Rat? Danke euch!

von Tony S. (tooony)


Lesenswert?

Kleiner Nachtrag: Das ACK kommt nach dem zweiten Byte, jedoch nicht nach 
dem dritten.

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.