Erste Schritte mit TWI

Gast #3368394
Lesenswert?

Guten Abend,

ich bin gerade dabei einen "Termalscanner" zu bauen, der ein Wärmebild 
von einem Bereich erzeugt. Die Sensorsteuerung ist soweit fertig.
Irgendwie komme ich mit dem Infrarotsensor aber nicht weiter. Ich hoffe, 
ihr könnt mir da weiter helfen. Es handelt sich um den MLX90614.
Vielleicht hat jemand sogar schon mit dem Sensor gearbeitet.
Zwar findet man jede menge Quellcode zu dem Sensor, aber ich kann nichts 
davon 1zu1 adaptieren, da meine Zielplattform kein Arduino ist.
Nutzen kann ich diese library:
https://github.com/ethersex/ethersex/blob/master/hardware/i2c/master/i2c_master.c
https://github.com/ethersex/ethersex/blob/master/hardware/i2c/master/i2c_master.h
https://github.com/ethersex/ethersex/blob/master/hardware/i2c/master/i2c_generic.c
https://github.com/ethersex/ethersex/blob/master/hardware/i2c/master/i2c_generic.h
1
#define ADDRESS    0x5A
2

3
int16_t i2c_MLX90614_read_temperature() 
4
{
5
  int16_t data = 0;
6
  uint8_t data_4lsb, data_4msb;
7
  
8
  // Start
9
  if (!i2c_master_select(ADDRESS, TW_WRITE))  { return 0x00; }
10
  
11
  // Wait // ? hier nötig?
12
  if (i2c_master_transmit_with_ack() != TW_MT_DATA_ACK)  { return 0x00; }
13
  
14

15
  // Write
16
  TWDR = 0x07;
17
  if (i2c_master_transmit_with_ack() != TW_MR_DATA_ACK) { return 0x00; }
18
  
19

20
  /* select the slave in read mode */
21
  TWDR = (chipaddress << 1) | TW_READ;
22
  
23
  // Rep Start
24
  if (i2c_master_start() != TW_REP_START) { return 0x00; }
25
  if (i2c_master_transmit_with_ack() != TW_MR_DATA_ACK)  { return 0x00; }
26
  
27
  data_4lsb = TWDR; // least significant bit
28

29
  if (i2c_master_transmit() != TW_MR_DATA_NACK) { return 0x00; }
30
  
31
  data_4msb = TWDR; // most significant bit
32
  if (i2c_master_transmit() != TW_MR_DATA_NACK) { return 0x00; }
33
  
34
  data |= data_4msb;
35
  data |= data << 8;
36
  data |= data_4lsb;
37
  
38
  i2c_master_stop();
39
  return data;
40
}

PS: Ich würde mein Projekt auch hier vorstellen, wenn interesse besteht 
:)
(Firma: matzetronics) #3368465
Lesenswert?

Du solltest dir etwas bessere Fehlercodes ausdenken, so das du auch 
mitkriegst, wo es hakt. Im Moment wirst du wahrscheinlich nur ne 0x00 
zurückkriegen und rätseln, was denn nun schiefläuft. Nützlich ist z.B. 
ein globales Errorbyte, indem du eine Fehlernummer speicherst. Sollte 
deine Routine also Null zurückgeben, lässt du dir die Fehlernummer 
zeigen. Das kann auch für andere Unterroutinen praktisch werden.

Ich kenne den Sensor nicht, könnte mir aber vorstellen, das er 
kalibriert werden muss, bevor es sinnvolle Daten gibt.
Gast #3369053
Lesenswert?

Ich habe mir mal dein Tipp zu Herzen genommen.

Zuerst einmal:
Der Sensor wir schonmal gefunden:
1
i2c detect
2
detected at: 0x0 (0)
3
detected at: 0x5a (90)


Ich poste erstmal den ersten Teil des Codes, welcher schon nicht richtig 
arbeitet:
1
  uint8_t data_4lsb, data_4msb, data_crc;
2
  int8_t data;
3

4
  uint8_t address = 0x5A;
5

6
  
7
  #ifdef DEBUG_I2C
8
    debug_printf("I2C::MLX90614 start\n");
9
  #endif
10
  
11
  /////////////////////////
12
  // Start Condition
13
  /////////////////////////
14
  if (!i2c_master_select(address, TW_WRITE))
15
  {
16
    #ifdef DEBUG_I2C
17
      debug_printf("I2C::MLX90614 address(%d) not selectable\n", address);
18
    #endif
19

20
    goto end;
21
  }
22
  
23
  if (i2c_master_transmit_with_ack() != TW_MT_SLA_ACK || i2c_master_transmit_with_ack() != TW_MT_DATA_ACK)
24
  {
25
    #ifdef DEBUG_I2C
26
      debug_printf("I2C::MLX90614 address selected, no sla_ack\n");
27
    #endif
28

29
    //goto end;
30
  }
31
  
32
  // Read out
33
  TWDR = 0x07;
34
  
35
  if (i2c_master_transmit_with_ack() != TW_MT_SLA_ACK || i2c_master_transmit_with_ack() != TW_MT_DATA_ACK)
36
  {
37
    #ifdef DEBUG_I2C
38
      debug_printf("I2C::MLX90614 command, no data_ack\n");
39
    #endif
40

41
    goto end;
42
  }

Als Ausgabe bekomme ich:
1
D: I2C::MLX90614 start
2
D: i2c master select adr+mode 0xB4
3
D: I2C::MLX90614 address selected, no sla_ack
4
D: I2C::MLX90614 command, no data_ack

Laut Datenblatt sollte ich 2 Acks bekommen. Diese bleiben aber aus.
Wundert euch nicht, warum ich nach SLA und DATA ACK abfrage. Ich wollte 
nur auf Nummer sicher gehen.
Hat da jemand eine idee?
Gast #3370439
Lesenswert?

Ich nehme mal an, dass du etwas schreiben (TW_WRITE) und nicht lesen 
(TW_READ) willst.

Mach aus jedem
1
if (i2c_master_transmit_with_ack() != TW_MT_SLA_ACK || i2c_master_transmit_with_ack() != TW_MT_DATA_ACK)
ein
1
if (i2c_master_transmit_with_ack() != TW_MT_DATA_ACK)
bzw.
1
ret = i2c_master_transmit_with_ack();
2
if (ret != TW_MT_DATA_ACK)
TW_MT_SLA_ACK ist hier nicht nötig (siehe weiter unten).

---
1
if (i2c_master_transmit_with_ack() != TW_MT_SLA_ACK || i2c_master_transmit_with_ack() != TW_MT_DATA_ACK)
2
  {
3
    #ifdef DEBUG_I2C
4
      debug_printf("I2C::MLX90614 address selected, no sla_ack\n");
5
    #endif
6

7
    //goto end;
8
  }
Dieser Part ist falsch. Es steht zu diesem Zeitpunkt nichts (sinnvolles) 
im TWDR Register.
Auf TW_MT_SLA_ACK wird bereits in i2c_master_select geprüft:

https://github.com/ethersex/ethersex/blob/master/hardware/i2c/master/i2c_master.c#L94

Zur Vollständigkeit: Bei
1
end:
sollte stehen:
1
i2c_master_stop();

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