ESP8266 Software-I2C mag nicht so wie ich will

OP #5827612
Lesenswert?
• ▲
▼
Ich versuche gerade die ID des BMP280 mittels Software-I2C auszulesen, 
mein bisheriger Code sieht so aus:
1
void BMP280::read_reg(uint8_t reg_addr, uint8_t amount, uint8_t reg_data[]) {
2
    const uint8_t last_index = amount - 1;
3
    i2c.start();
4

5
    if(i2c.send_byte(SLAVE_WRITE)) {
6
        if(i2c.send_byte(reg_addr)) {
7
            i2c.repeated_start();
8
            if(i2c.send_byte(SLAVE_READ)) {
9
                for(uint8_t i = 0; i < amount; i++) {
10
                    uint8_t data = i2c.read_byte();
11
                    if(i == last_index)
12
                        i2c.master_nack();
13
                    else
14
                        i2c.master_ack();
15
                    reg_data[i] = data;
16
                }
17
            }
18
        }
19
    }
20

21
    i2c.stop();
22
}

Die entsprechenden Funktionen, die aufgerufen werden:
1
bool ICACHE_FLASH_ATTR I2C::send_byte(uint8_t byte) {
2
    for(uint8_t i = 0; i < 8; i++) {
3
        if(byte & (1 << 7 - i))
4
            set_SDA_high();
5
        else
6
            set_SDA_low();
7
        set_SCL_high();
8
        os_delay_us(DELAY);
9
        set_SCL_low();
10
    }
11
    
12
    set_SDA_high();
13

14
    /* 9th clock for slave to ack transmitted byte */
15
    set_SCL_high();
16
    os_delay_us(DELAY);
17
    uint8_t ack = read_SDA();
18
    os_delay_us(DELAY);
19
    set_SCL_low();
20

21
    return ack == 0;
22
}
23
/****************************************************/
24
uint8_t ICACHE_FLASH_ATTR I2C::read_byte(void) {
25
    uint8_t result = 0x00;
26
    for(uint8_t i = 0; i < 8; i++) {
27
        set_SCL_high();
28
        if(read_SDA())
29
            result |= (1 << 7 - i);
30
        set_SCL_low();
31
    }
32
    return result;
33
}
34
/****************************************************/
35
void ICACHE_FLASH_ATTR I2C::repeated_start(void) {
36
    set_SDA_high();
37
    os_delay_us(DELAY);
38
    set_SCL_high();
39
    os_delay_us(DELAY);
40
    set_SDA_low();
41
    os_delay_us(DELAY);
42
    set_SCL_low();
43
}
44
/****************************************************/
45
void ICACHE_FLASH_ATTR I2C::master_ack(void) {
46
    set_SDA_low();
47
    os_delay_us(DELAY);
48
    set_SCL_high();
49
    os_delay_us(DELAY);
50
    set_SCL_low();
51
    os_delay_us(DELAY);
52
    set_SDA_high();
53
}
54
/****************************************************/
55
void ICACHE_FLASH_ATTR I2C::master_nack(void) {
56
    set_SCL_low();
57
    os_delay_us(DELAY);
58
    set_SCL_high();
59
    os_delay_us(DELAY);
60
    set_SCL_low();
61
}
62
/****************************************************/
63
void ICACHE_FLASH_ATTR I2C::start(void) {
64
    set_SDA_low();
65
    os_delay_us(DELAY);
66
    set_SCL_low();
67
}
68
/****************************************************/
69
void ICACHE_FLASH_ATTR I2C::stop(void) {
70
    set_SCL_high();
71
    os_delay_us(DELAY);
72
    set_SDA_high();
73
}
74
/****************************************************/
75
uint8_t ICACHE_FLASH_ATTR I2C::read_SDA(void) {
76
    return GPIO_INPUT_GET(I2C_MASTER_SDA_GPIO);
77
}
78
/****************************************************/
79
void ICACHE_FLASH_ATTR I2C::set_SDA_high(void) {
80
    gpio_output_set(1 << I2C_MASTER_SDA_GPIO, 0, 1 << I2C_MASTER_SDA_GPIO, 0);
81
}
82
/****************************************************/
83
void ICACHE_FLASH_ATTR I2C::set_SDA_low(void) {
84
    gpio_output_set(0, 1 << I2C_MASTER_SDA_GPIO, 1 << I2C_MASTER_SDA_GPIO, 0);
85
}
86
/****************************************************/
87
void ICACHE_FLASH_ATTR I2C::set_SCL_high(void) {
88
    gpio_output_set(1 << I2C_MASTER_SCL_GPIO, 0, 1 << I2C_MASTER_SCL_GPIO, 0);
89
}
90
/****************************************************/
91
void ICACHE_FLASH_ATTR I2C::set_SCL_low(void) {
92
    gpio_output_set(0, 1 << I2C_MASTER_SCL_GPIO, 1 << I2C_MASTER_SCL_GPIO, 0);
93
}

Nach Datenblatt sollte im Register 0x58 stehen, stattdessen lese ich 
allerdings 0x7F - hat jemand eine Idee, warum das so ist? Ich hab die 
Logic-Analyzer Aufnahme mit angehängt. Seltsamerweise sind die Zeiten 
unterschiedlich - scheint mir fast, als würde der ESP da was machen und 
daher kommt es zu unterschiedlichen Verzögerungen?

Edit: Das Bild ist etwas klein, hier die volle Auflösung:

https://pasteboard.co/IcIBjQR.png
Angehängte Dateien:
Gast #5828976
Lesenswert?
• ▲
▼
Hallo,

auf dem kleinen Bild sehe ich immer nur ein STOP als Beginn einer
Sequenz. Irgendwie fehlt es an einer START Sequenz!

Am Ende einer Sequenz sollte der Bus auch wieder auf IDLE H gehen.

Und wie peda schrieb, dürfen die H-Pegel NIE-NIE-NIE aktiv getrieben 
werden.

Gruß
TK
Gast #5829370
Lesenswert?
• ▲
▼
Beim Lesen fällt mir auf, dass das Timing nicht eindeutig ist. Da 
verändert sich die SDA Leitung in genau in dem Moment, wo SCL auf High 
geht, was nicht sein darf.

Was hast du denn für Pull-Up Widerstände verwendet? Ich komme mit 2,2k 
Ohm gut klar, mit 12k Ohm jedoch nicht.

In der Funktion read_byte() vermisse ich Delays. Ich würde es so machen:

1) SCL auf High setzen
2) Delay
3) Bit lesen
4) SCL auf Low setzen
5) Delay

dann mit dem nächsten Bit weiter machen. Wie lang sind eigentlich deine 
Delays?

Antwort schreiben

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.