Forum: Mikrocontroller und Digitale Elektronik ESP8266 Software-I2C mag nicht so wie ich will


von Max M. (maxmicr)


Angehängte Dateien:

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

: Bearbeitet durch User
von Magnus Müller (Gast)


Lesenswert?

Wie sieht es mit Hardware I2C aus??

von Peter D. (peda)


Lesenswert?

Keine Ahnung, was gpio_output_set macht, aber SDA darf nicht auf high 
gesetzt werden, sondern auf tristate. Das high macht dann der 
Pullup-Widerstand.

von TK (Gast)


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

von TK (Gast)


Lesenswert?

Korrektur (wohl noch zu früh am Morgen)
ich hatte keine START-Sequenz am Anfang gesehen (gehe aber mal davon 
aus, dass die Flanke wohl im Diagramm untergegangen ist).

TK

von Stefan F. (Gast)


Lesenswert?

Magnus Müller schrieb:
> Wie sieht es mit Hardware I2C aus??

Hat der ESP8266 nicht

von Stefan F. (Gast)


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?

von Peter D. (peda)


Lesenswert?

Bei read_byte fehlen die Delays.

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.