TWI mehrfach Initialisierung

OP Persönliche Seite #5809963
Lesenswert?

Hi,

ich habe zwei Probleme, die unmittelbar zusammenhängen. Dabei bezieht 
sich meine Frage hier auf einen Workarround (2).

1. Ich habe eine Platine, die irgendwie beim bespeisen eines DC-Motors 
sehr sporalische Probelem mit dem Display hat (TWI-Seriell wandler.)

1.1
Ich hätte behauptet, dass durch die Rückinduktion der µC mittels 
BrownOut (1,8V) selbst abschaltet.
Ich war beim Kunden und er könnte mir dieses "Problem" leider bei keinen 
der 70 Platinen zeigen (Vorführeffekt) und in meiner Werkstatt habe ich 
es auch nie selbst gesehen :(

Er beschreibt es so:
"Display bekommt Sonderzeichen aber Programm im Hintergrund läuft 
weiter". (Läuft weiter heißt doch 1.1 ist ausgeschlossen!?!)
1.2
Diese Sonderzeichen, kenne ich nur, wenn der Bus schlecht verlötet ist 
und die Initialisierung nicht richtig klappt. Daher habe ich NACHLÖTEN 
empfohlen.

2.
Ich würde gerne probieren, ob ich einen Workarround hin bekomme, so das 
das Display selbst nach diesem Fehler wieder "sauber" wird.

Daher die eigentliche Frage: "Kann/darf ich den i2c_init() regelmäßig 
wiederholen und/oder kann dies andere Seiteneffekte haben?"

Folgendes verwende ich:
1
/*************************************************************************
2
* Title:    I2C master library using hardware TWI interface
3
* Author:   Peter Fleury <pfleury@gmx.ch>  http://jump.to/fleury
4
* File:     $Id: twimaster.c,v 1.3 2005/07/02 11:14:21 Peter Exp $
5
* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3
6
* Target:   any AVR device with hardware TWI 
7
* Usage:    API compatible with I2C Software Library i2cmaster.h
8
**************************************************************************/
9

10
#include <inttypes.h>
11
#include <compat/twi.h>
12
#include "i2cmaster.h"
13

14
/**
15
 * The standard clock (SCL) speed for I2C up to 100KHz. Philips do define faster speeds: Fast mode, which is up to 400KHz
16
 */
17
/* I2C clock in Hz */
18
#define SCL_CLOCK  100000L
19

20

21
/*************************************************************************
22
 Initialization of the I2C bus interface. Need to be called only once
23
*************************************************************************/
24
void i2c_init(void)
25
{
26
#if ((F_CPU/SCL_CLOCK)-16)/2 < 10
27
  #error TWBR to small
28
#endif
29

30
  /* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */
31
  
32
  TWSR = 0;                         /* no prescaler */
33
  TWBR = ((F_CPU/SCL_CLOCK)-16)/2;  /* must be > 10 for stable operation */
34

35

36
}/* i2c_init */
37
...

Verändert habe ich nur (da ich mit 8Mhz arbeite und sonst die Formel 
nicht auf geht):
1
//#define SCL_CLOCK  400000L
2
#define SCL_CLOCK  100000L


Dann selektiere ich noch:
1
uint8_t I2C_Detect(uint8_t addr)
2
// look for device at specified address; return 1=found, 0=not found
3
{
4
    return !i2c_start(addr); // return 0 if OK otherwise 1
5
}
6
uint8_t LCD_I2C_DEVICE = I2C_PCF8574;
7
void i2c_detectPCF8574() {
8
    bool i2cFound_PCF8574 = I2C_Detect(I2C_PCF8574);
9
    bool i2cFound_PCF8574A = I2C_Detect(I2C_PCF8574A);
10
    if (!i2cFound_PCF8574 && i2cFound_PCF8574A) {
11
        LCD_I2C_DEVICE = I2C_PCF8574A;
12
    }
13
}

und mache ein:
1
void lcd_init(void) {
2

3
    lcd_light(false);
4

5
    _delay_ms(15);                //-  Wait for more than 15ms after VDD rises to 4.5V
6
    lcd_write(CMD_D1 | CMD_D0);    //-  Set interface to 8-bit
7
    _delay_ms(5);                //-  Wait for more than 4.1ms
8
    lcd_write(CMD_D1 | CMD_D0);    //-  Set interface to 8-bit
9
    _delay_ms(1);                //-  Wait for more than 100us
10
    lcd_write(CMD_D1 | CMD_D0);    //-  Set interface to 8-bit
11
    lcd_write(CMD_D1);            //-  Set interface to 4-bit
12

13
    _delay_ms(50);
14
    //- From now on in 4-bit-Mode
15
    lcd_command(LCD_LINE_MODE | LCD_5X7);
16
    _delay_ms(50);
17
    lcd_command(LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKINGOFF);
18
    _delay_ms(50);
19
    lcd_command(LCD_INCREASE | LCD_DISPLAYSHIFTOFF);
20
    _delay_ms(50);
21
    lcd_command(LCD_CLEAR);
22
    _delay_ms(50);
23
}


Reihenfolge:
1
int main(void) {
2
    ioinit();
3
    timer2_init();
4
    timer1_pwm_init();
5

6
    i2c_init();
7
    i2c_detectPCF8574();
8
    lcd_init();
9
    //ADC_init();
10
    /** Interrupts (IRQs) global erlauben */
11
    sei();
12
    wait_10ms(1);
13

14
    readOldVariables();
15

16
    while (1) {
17
        sceduled_menue();
18
        if(section == RunRun){
19
            runningCoutdown();
20
        }
21
        sceduled_motor();
22
    }
23
}

Könnte es einen positiven Effekt haben
- i2c_init();
oder
lcd_init();

mehrfach. (z.B. in einer Schleife von 5Sek aufzurufen?
Wie gesagt, konnte ich den Fehler selbst nie sehen geschweigedenn 
reproduzieren, daher wäre ein "probier es doch aus" nicht so hilfreich 
;)

Alles anderen bezüglich Grundlagenwissen höre ich gerne und bin 
neugierig drauf.

Grüße David
#5810022
Lesenswert?

Hallo,

die Init kannst du so oft durchführen wie du willst.
Die Frage ist:
Wenn der Fehler auftritt wird das Display dann nach den falschen Zeichen 
überhaupt nicht mehr aktualisiert?
Wenn ja,
dann hängt wohl der Bus und das i2c_init sollte das beheben - es sei 
denn das Display oder der Wandler hat sich auch verhaspelt. Das sollte 
sich mit einer gewissen Anzahl an Clockpulsen beheben lassen. Den 
Zustand sollte der Controller feststellen können, da vom Display kein 
ACK mehr kommt.
Wenn nein,
dann hat sich evl. etwas an der Konfig des Displays verstellt, dann muss 
du auch das Display neu initialisieren und dann alles wieder ausgeben.

Sascha
OP Persönliche Seite #5810089
Lesenswert?

Sascha W. schrieb:
> denn das Display oder der Wandler hat sich auch verhaspelt. Das sollte
> sich mit einer gewissen Anzahl an Clockpulsen beheben lassen. Den
> Zustand sollte der Controller feststellen können, da vom Display kein
> ACK mehr kommt.

Meinst du die hiesige 1?
1
/*************************************************************************
2
  Send one byte to I2C device
3
  
4
  Input:    byte to be transfered
5
  Return:   0 write successful 
6
            1 write failed
7
*************************************************************************/
8
unsigned char i2c_write( unsigned char data )
9
{  
10
    uint8_t   twst;
11
    
12
  // send data to the previously addressed device
13
  TWDR = data;
14
  TWCR = (1<<TWINT) | (1<<TWEN);
15

16
  // wait until transmission completed
17
  while(!(TWCR & (1<<TWINT)));
18

19
  // check value of TWI Status Register. Mask prescaler bits
20
  twst = TW_STATUS & 0xF8;
21
  if( twst != TW_MT_DATA_ACK) return 1;
22
  return 0;
23

24
}/* i2c_write */

Die ich nicht verarbeite:
1
void lcd_write(uint8_t value) {
2
    uint8_t data_out = 0;
3

4
...
5

6
    // direct I2C access, write all three bytes in one cycle for faster operation
7
    i2c_start_wait(LCD_I2C_DEVICE + I2C_WRITE);
8
    i2c_write(data_out);                // setup data BEFORE E!   
9
    i2c_write(data_out | LCD_E);        // set E to high
10
    i2c_write(data_out);                // set E to low
11
    i2c_stop();
12
}
Gast #5810115
Lesenswert?

D a v i d K. schrieb:
> Das "[ c]" statt "[code]" fällt mir jetzt gerade erst auf.

Man kann im Preview überprüfen ob man alles richtig gemacht hat
1
/*************************************************************
2
  Send one byte to I2C device
3
  Input:    byte to be transfered
4
  Return:   0 write successful 
5
            1 write failed
6
*************************************************************/
7
unsigned char i2c_write( unsigned char data )
8
{  
9
  uint8_t   twst;
10
  bla blubb foo bar
11
  return 0;
12
}/* i2c_write */
#5810134
Lesenswert?

D a v i d K. schrieb:
> Sascha W. schrieb:
>> denn das Display oder der Wandler hat sich auch verhaspelt. Das sollte
>> sich mit einer gewissen Anzahl an Clockpulsen beheben lassen. Den
>> Zustand sollte der Controller feststellen können, da vom Display kein
>> ACK mehr kommt.
>
> Meinst du die hiesige 1?
ja, kannst aber auch die detect-funktion für den PCF verwenden. Wenn der 
Bus hängt dann sollte dort false zurückkommen.

Sascha
OP Persönliche Seite #5817331
Lesenswert?

Timmo H. schrieb:
> Wenn sich die State-Machine im Display durch komische Spikes völlig
> ver­rannt hat, hilft ofmals nur ein richtiger Reset falls das Display
> eine Reset-Leitung hat. Ansonsten Vcc vom Display schaltbar machen.

Ich kann leider keine ResetLeitung erkennen.

[VSS, VDO, VO, RS, RW, E, D0...D7, A, K]

Es scheint so, dass ich diese "Sonderzeichen" reproduziert bekomme, wenn 
ich SCL mehrmals vom PCF8574X hintereinander ab und anstöpsel.

Jedoch habe ich noch nicht den Dreh (Sofware) raus, diesen in einer 
10sec-Schleife wieder zu "entfernen".

In wiefern kann ich hiervon profitieren?

Manfred L. schrieb:
> void TWIS_Stop (void)
> {
>    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO)|(1<<TWEA)|(1<<TWIE);
> }
>
> ist Gold wert und hat nun jetzt auch bei mir auf Anhieb funktioniert.

Bzw. hiervon:
https://www.mikrocontroller.net/articles/AVR_TWI#Bekannte_Bugs


Grüße David

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