Forum: Compiler & IDEs Frage zur TWI Lib des ATXmega


von Malte _. (malte) Benutzerseite


Lesenswert?

Hallo,
ich verwende die TWI Lib von Atmel um einen I2C EEProm anzusprechen.
Leider bekomme ich bei einem Lesezugriff nach einem Schreibzugriff 
zunächst die vorherigen Daten geliefert. Erst ein zweiter Lesezugriff 
liefert dann die korrekten Daten. Mit einem Ozi habe ich mir den ersten 
Lesezugriff auf dem I2C Bus angesehen. Hier werden bereits die korrekten 
neuen Daten übertragen. Wo liegt der Fehler?
Die TWI Lib gibt es hier:
http://www.atmel.com/dyn/resources/prod_documents/AVR1308.zip
1
#include <avr/io.h>
2
3
#include "i2ceeprom.h"
4
#include "main.h"
5
#include "twi_master_driver.h"
6
#include "rs232.h"
7
8
#define TWI_PWRSAVEREG PR_PRPE
9
#define TWI_PWRSAVEBIT PR_TWI_bm
10
#define TWI TWIE
11
#define TWI_IO PORTE
12
#define TWI_DATA_PIN PIN1CTRL
13
#define TWI_CLK_PIN PIN0CTRL
14
15
//eeprom allows maximum 100kHz at 1.7V
16
#define TWI_BAUDRATE 80000
17
#define TWI_BAUDSETTING TWI_BAUD(F_CPU, TWI_BAUDRATE)
18
//fixed 1010 + A2 = VCC, A1, A0 = GND -> 1010100 -> 0x54
19
#define TWI_SLAVE_ADDRESS 0x54
20
21
TWI_Master_t g_twiMaster;
22
23
uint8_t i2ceep_init(void) {
24
  TWI_PWRSAVEREG &= ~PR_TWI_bm;
25
  TWI_IO.TWI_DATA_PIN = PORT_OPC_PULLUP_gc;
26
  TWI_IO.TWI_CLK_PIN = PORT_OPC_PULLUP_gc;
27
  TWI_MasterInit(&g_twiMaster, &TWI, TWI_MASTER_INTLVL_LO_gc, TWI_BAUDSETTING);
28
  PMIC.CTRL |= PMIC_LOLVLEN_bm;
29
30
  while (TWI_MasterReady(&g_twiMaster) != TWIM_STATUS_READY);
31
  uint8_t buffer[3];
32
  buffer[0] = 0x0;
33
  buffer[1] = 0x0;
34
  buffer[2] = 0x0F;
35
  TWI_MasterWrite(&g_twiMaster, TWI_SLAVE_ADDRESS, buffer, 3);
36
  while (TWI_MasterReady(&g_twiMaster) != TWIM_STATUS_READY);
37
  buffer[2] = 0;
38
39
40
  TWI_MasterWriteRead(&g_twiMaster, TWI_SLAVE_ADDRESS, buffer, 2, 1);
41
  while (TWI_MasterReady(&g_twiMaster) != TWIM_STATUS_READY);
42
  if (g_twiMaster.readData[0] == 0x0F) {
43
    return 0;
44
  }
45
  return 1;
46
}
47
48
uint8_t i2ceep_writebyte(uint16_t address, uint8_t value) {
49
  uint8_t buffer[3];
50
  buffer[0] = address>>8;
51
  buffer[1] = (uint8_t)address;
52
  buffer[2] = value;
53
  while (TWI_MasterReady(&g_twiMaster) != TWIM_STATUS_READY);
54
  TWI_MasterWrite(&g_twiMaster, TWI_SLAVE_ADDRESS, buffer, 3);
55
  return 0;
56
}
57
58
uint8_t i2ceep_readbyte(uint16_t address) {
59
  uint8_t buffer[3];
60
  buffer[0] = address>>8;
61
  buffer[1] = (uint8_t)address;
62
  while (TWI_MasterReady(&g_twiMaster) != TWIM_STATUS_READY);
63
  TWI_MasterWriteRead(&g_twiMaster, TWI_SLAVE_ADDRESS, buffer, 2, 1);
64
  while (TWI_MasterReady(&g_twiMaster) != TWIM_STATUS_READY);
65
  rs232_puthex(g_twiMaster.readData[0]); //debug only
66
  return g_twiMaster.readData[0];
67
}
68
69
void i2ceep_test(uint8_t data) {
70
  //while (TWI_MasterReady(&g_twiMaster) != TWIM_STATUS_READY);
71
  TWI_MasterWrite(&g_twiMaster, TWI_SLAVE_ADDRESS, &data, 1);
72
}
73
74
void i2ceep_disable(void) {
75
  TWI_PWRSAVEREG |= PR_TWI_bm;
76
}
77
78
ISR(TWIE_TWIM_vect) {
79
  TWI_MasterInterruptHandler(&g_twiMaster);
80
}

von Malte _. (malte) Benutzerseite


Lesenswert?

Also einen Fehler in der Lib habe ich gefunden:
1
#define TWIM_STATUS_READY              0
2
#define TWIM_STATUS_BUSY               1
3
4
bool TWI_MasterReady(TWI_Master_t *twi)
5
{
6
  bool twi_status = (twi->status & TWIM_STATUS_READY);
7
  return twi_status;
8
}
ist natürlich immer gleich 0. Und somit äquivalent zu TWIM_STATUS_READY. 
D.h. es wurde nie auf den Master gewartet und dementsprechend der 
vorherige Wert aus dem Buffer gelesen.
Die Lib in
1
bool TWI_MasterReady(TWI_Master_t *twi)
2
{
3
  if (twi->status == TWIM_STATUS_READY) {
4
    return true;
5
  }
6
  return false;
7
}
ändern hilft. Außerdem fehlt noch irgendwo ein Waitstate, da lesen 
direkt folgend auf schreiben keine Daten liefert (außer man wartet 
dazwischen).
Aber so funktioniert das Lesen + Schreiben (einfach noch mal lesen wenn 
es nicht geklappt hat, anstelle des Wartens):
1
uint8_t i2ceep_init(void) {
2
  TWI_PWRSAVEREG &= ~PR_TWI_bm;
3
  TWI_IO.TWI_DATA_PIN = PORT_OPC_PULLUP_gc;
4
  TWI_IO.TWI_CLK_PIN = PORT_OPC_PULLUP_gc;
5
  TWI_MasterInit(&g_twiMaster, &TWI, TWI_MASTER_INTLVL_LO_gc, TWI_BAUDSETTING);
6
  PMIC.CTRL |= PMIC_LOLVLEN_bm;
7
  i2ceep_writebyte(0, 0xA);
8
  uint8_t value = i2ceep_readbyte(0);
9
  if (value == 0x0A) {
10
    return 0;
11
  }
12
  return 1;
13
}
14
15
uint8_t i2ceep_writebyte(uint16_t address, uint8_t value) {
16
  uint8_t buffer[3];
17
  buffer[0] = address>>8;
18
  buffer[1] = (uint8_t)address;
19
  buffer[2] = value;
20
  while (!TWI_MasterReady(&g_twiMaster));
21
  TWI_MasterWrite(&g_twiMaster, TWI_SLAVE_ADDRESS, buffer, 3);
22
  return 0;
23
}
24
25
uint8_t i2ceep_readbyte(uint16_t address) {
26
  uint8_t buffer[2];
27
  buffer[0] = address>>8;
28
  buffer[1] = (uint8_t)address;
29
  while (!TWI_MasterReady(&g_twiMaster));
30
  do {
31
    TWI_MasterWriteRead(&g_twiMaster, TWI_SLAVE_ADDRESS, buffer, 2, 1);
32
    while (!TWI_MasterReady(&g_twiMaster));
33
  } while (g_twiMaster.bytesRead < 1);
34
  return g_twiMaster.readData[0];
35
}

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.