Forum: Mikrocontroller und Digitale Elektronik STM8 I2C Busy Bit bleibt immer gesetzt


von µC8051 (Gast)


Lesenswert?

Hallo,

ich arbeite mit dem STM8S105K6 und habe hier schon mehrer Beispiele von 
ST ausprobiert. SDA und SCL haben einen 4,7K Pull up. Die Leitung ist 
aktuell nur mit einem Oszi verbunden.

Manuell kann ich die entsprechenden Pins toggeln lassen aber with I2C 
bleiben die Pins bei 3,3V.

Nach längerem Debuggen bemerkte ich dann das bei allen Beispielen das 
Busy Bit immer durchgehend gesetzt ist.

Da ich den Fehler nicht finden kann würde ich mich über hilfe sehr 
freuen.

Hier ein kleines Beispiel meiner Meinung, müsste ich am Oszi die 
gesendete Adresse sehen können.
1
int main(void){
2
  I2C_Init();
3
  while(1){
4
  I2C_7BitAdresse();
5
  }
6
7
 void I2C_Init(){
8
  CLK->CKDIVR = 0x01;
9
  I2C->CR2 |=1 <<7; 
10
  I2C->CR2 ^=1 <<7;                //Reset periphial clock
11
  GPIOB->ODR |= 0x30;             //define SDA, SCL outputs, HiZ, Open drain, Fast
12
  GPIOB->DDR |= 0x30;              //Bits 4 und 5 als Output,20MHz
13
  GPIOB->CR2 |= 0x30;
14
15
  #ifdef FAST_I2C_MODE
16
    I2C->FREQR = 16;               // input clock to I2C - 16MHz 
17
    I2C->CCRL = 15;                // 900/62.5= 15, (SCLhi must be at least 600+300=900ns!)
18
    I2C->CCRH = 0x80;              // fast mode, duty 2/1 (bus speed 62.5*3*15~356kHz)
19
    I2C->TRISER = 5;               // 300/62.5 + 1= 5  (maximum 300ns)
20
  #else
21
    I2C->FREQR = 8;                // input clock to I2C - 8MHz
22
    I2C->CCRL = 40;                // CCR= 40 - (SCLhi must be at least 4000+1000=5000ns!)
23
    I2C->CCRH = 0;                 // standard mode, duty 1/1 bus speed 100kHz
24
    I2C->TRISER = 9;               // 1000ns/(125ns) + 1  (maximum 1000ns)
25
  #endif
26
    I2C->OARL = 0xA0;              // own address A0;
27
    I2C->OARH |= 0x40;
28
    //I2C->ITR = 1;                // enable error interrupts
29
    I2C->CR2 |= 0x04;              // ACK=1, Ack enable
30
    I2C->CR1 |= 0x01;              // PE=1
31
}
32
33
 void I2C_7BitAdresse(){
34
   while(I2C->SR3 &1 <<1){ //Busy Bit pollen
35
    I2C->CR2 |= 2;                              // STOP=1, generate stop
36
    while((I2C->CR2 & 2));                      // wait until stop is performed
37
  }
38
   I2C->SR1 |=1;  //Start Sequenz
39
   while(!(I2C->SR1 &1));  //warten bis Start Sequenz vorbei
40
   while(!(I2C->SR1 &1<<7));  
41
   I2C->DR = (uint8_t)(SlaveAdress << 1); // Adresse Senden
42
   while(!(I2C->SR1 & 2)); 
43
 }
44
}

von 12 (Gast)


Lesenswert?

Sorry, nur oberflächlich: Hast du auch alle beteiligten Module 
(mindestens aber das I2c-Modul) mit "Takt" versorgt? (Stichwort: 
CLK->PCKENR1 oder peripheral clock gating)? In deinem Code fehlt das.

von public (Gast)


Lesenswert?

ST stellt doch massig Bibliotheken zur Verfügung, eine Initialisierung 
des I2C sollte doch auch enthalten sein...

beste grüße

von proethel (Gast)


Lesenswert?

Errata sheet "STM8S005xx and STM8S105xx device limitations" und die 
AN3281
(STM8 optimized I2C examples) helfen weiter.

von µC8051 (Gast)


Lesenswert?

public schrieb:
> ST stellt doch massig Bibliotheken zur Verfügung, eine Initialisierung
> des I2C sollte doch auch enthalten sein...
>
> beste grüße

Hallo,

Die init aus meinem ersten Post ist dem Beispiel von ST zum I2C 
entnommen und wurde auf meinen µC angepasst.

Natürlich gibt es Bibliotheken von ST. Habe das auch ausprobiert aber 
bin auch zu keinem Ergbeniss gekommen.


Hier z.B das Programm mit den Inits aus den i2C lib das läuft zwar glatt 
durch aber am Ausgnag passiert nichts. Schaut man sich dann die Register 
an sieht man auch hier, dass das Busy Bit durchgehend auf 1 ist.
1
#include "stm8s.h"
2
#include "main.h"
3
#include "stm8s_eval_i2c_ee.h"
4
5
int main(void){
6
  GPIOB->ODR |= 0x30;             //define SDA, SCL outputs, HiZ, Open drain, Fast
7
  GPIOB->DDR |= 0x30;              //Bits 4 und 5 als Output,20MHz
8
  GPIOB->CR2 |= 0x30;
9
  I2C_SoftwareResetCmd(ENABLE);
10
  I2C_SoftwareResetCmd(DISABLE);
11
  I2C_DeInit();
12
  CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C,ENABLE);
13
  I2C_Init(400000, 0x0000, I2C_DUTYCYCLE_2, I2C_ACK_NONE, I2C_ADDMODE_7BIT , 16);
14
  I2C->SR3 &=0xFD;
15
  I2C_Cmd(ENABLE);
16
  while(1){
17
    I2C_GenerateSTART(ENABLE);
18
    I2C_Send7bitAddress(0x04, I2C_DIRECTION_TX);
19
    I2C_SendData(0x70);
20
    I2C_GenerateSTOP(ENABLE);
21
  }
22
}


Wäre über hilfe sehr dankbar sitze schon einige Tage an dem Problem und 
komme nicht weiter.

von proethel (Gast)


Lesenswert?

Die Standard Library hilft dir nicht weiter. Schau dir die AN3281 (pdf 
und zip) an und verwende die dort beschriebenen Funktionen. Die richtige 
Reihenfolge bei der Initialisierung ist z.B. SEHR wichtig.

von µC8051 (Gast)


Lesenswert?

proethel schrieb:
> Die Standard Library hilft dir nicht weiter. Schau dir die AN3281 (pdf
> und zip) an und verwende die dort beschriebenen Funktionen. Die richtige
> Reihenfolge bei der Initialisierung ist z.B. SEHR wichtig.

Danke für den Tip die habe ich auch schon gefunden und ausprobiert. Mein 
erster Versuch ist auch von diesen abgeleitet. Aber auch wenn ich driekt 
das Beispiel aus AN3281 verwende und halt den Port entsprechend zu 
meinem µC anpasse bleibt er in der Abfrage vom Bussy Bit hängen und 
springt letztendlich in einen Fehler.

von proethel (Gast)


Lesenswert?

Dann schau die deine Initialisierung an, besonders die Clock (und in dem 
Zusammenhang auch die Option Bytes). Anhand deines Codes gehe ich davon 
aus das du den internen Oszillator (HSI) mit 16Mhz verwenden möchtest, 
der STM8 startet aber mit stanardmäßig 2MHz.

von µC8051 (Gast)


Lesenswert?

proethel schrieb:
> Dann schau die deine Initialisierung an, besonders die Clock (und in dem
> Zusammenhang auch die Option Bytes). Anhand deines Codes gehe ich davon
> aus das du den internen Oszillator (HSI) mit 16Mhz verwenden möchtest,
> der STM8 startet aber mit stanardmäßig 2MHz.


Ok Ausgehend von dem Code aus Beispiel AN3281.
Ich bin alle Register nochmal durch gegangen und bin der Meinung das 
diese passen. Nur bei der Configurierung der Pins SDA/SCL in der Init 
bin ich mir nicht sicher (Über Rückmeldung würde ich mich freuen).

Es ist immernoch das gleiche Problem in der erste While schleife von 
I2C_WriteRegister bleibt das Programm hängen weil das Busy Bit gesetzt 
bleibt.

1
/*Main*/
2
#include "stm8s.h"
3
#include "i2c_master_poll.h"
4
#include <string.h>
5
6
const u8 DUMMY_INIT[MAX_DUMMY]= { 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0 };
7
8
u8 Dummy[MAX_DUMMY];
9
volatile u8 err_save;
10
volatile u16 TIM4_tout;
11
u16 loop_count;
12
13
#ifndef FAST_I2C_MODE
14
  #define FAST_I2C_MODE
15
#endif
16
17
void main (void) { 
18
  CLK_FastHaltWakeUpCmd(ENABLE);
19
  /* peripheral initialization */  
20
  #ifdef FAST_I2C_MODE
21
  CLK->CKDIVR = 0x00;             // sys clock / 1
22
  #else
23
  CLK->CKDIVR = 0x01;             // sys clock / 2
24
  #endif
25
  
26
  // initialize timer 4 mandatory for timout and tick measurement 
27
  TIM4_Init();                    
28
  
29
  // Initialize I2C for communication
30
  I2C_Init();                     
31
  
32
  // initialization of dummy field for test purpose    
33
  memcpy(Dummy, DUMMY_INIT, MAX_DUMMY);
34
35
  enableInterrupts();
36
/* main test loop */
37
  while(1) {
38
    set_tout_ms(10);
39
    I2C_WriteRegister(8, 1, &Dummy[8]);
40
}
41
42
43
/*I2C_Master_poll.c*/
44
45
/* flag clearing sequence - uncoment next for peripheral clock under 2MHz */
46
#define dead_time() { /* _asm("nop"); _asm("nop"); */ }
47
#define delay(a)          { TIM4_tout= a; while(TIM4_tout); }
48
#define tout()            (TIM4_tout)
49
#define set_tout_ms(a)    { TIM4_tout= a; }
50
extern u16 TIM4_tout;
51
52
53
54
void I2C_Init(void) {
55
  GPIOB->ODR |= 0x30;             //define SDA, SCL outputs, HiZ, Open drain, Fast
56
  GPIOB->DDR |= 0x30;              //Bits 4 und 5 als Output,20MHz
57
  GPIOB->CR2 |= 0x30;
58
59
#ifdef FAST_I2C_MODE
60
  I2C->FREQR = 16;               // input clock to I2C - 16MHz 
61
  I2C->CCRL = 15;                // 900/62.5= 15, (SCLhi must be at least 600+300=900ns!)
62
  I2C->CCRH = 0x80;              // fast mode, duty 2/1 (bus speed 62.5*3*15~356kHz)
63
  I2C->TRISER = 5;               // 300/62.5 + 1= 5  (maximum 300ns)
64
#else
65
  I2C->FREQR = 8;                // input clock to I2C - 8MHz
66
  I2C->CCRL = 40;                // CCR= 40 - (SCLhi must be at least 4000+1000=5000ns!)
67
  I2C->CCRH = 0;                 // standard mode, duty 1/1 bus speed 100kHz
68
  I2C->TRISER = 9;               // 1000ns/(125ns) + 1  (maximum 1000ns)
69
#endif
70
  I2C->OARL = 0xA0;              // own address A0;
71
  I2C->OARH |= 0x40;
72
  I2C->ITR = 1;                  // enable error interrupts
73
  I2C->CR2 |= 0x04;              // ACK=1, Ack enable
74
  I2C->CR1 |= 0x01;              // PE=1
75
}
76
77
78
79
void I2C_WriteRegister(u8 u8_regAddr, u8 u8_NumByteToWrite, u8 *u8_DataBuffer)
80
{
81
  while((I2C->SR3 & 2))                         // Wait while the bus is busy
82
  {
83
    I2C->CR2 |= 2;                                        // STOP=1, generate stop
84
    while((I2C->CR2 & 2) && tout());                      // wait until stop is performed
85
  }
86
  
87
  I2C->CR2 |= 1;                                          // START=1, generate start
88
  while(((I2C->SR1 & 1)==0) && tout());                   // Wait for start bit detection (SB)
89
  dead_time();                                            // SB clearing sequence
90
  if(tout())
91
  {
92
    #ifdef TEN_BITS_ADDRESS                                // TEN_BIT_ADDRESS decalred in I2c_master_poll.h
93
      I2C->DR = (u8)(((SLAVE_ADDRESS >> 7) & 6) | 0xF0);  // Send header of 10-bit device address (R/W = 0)
94
      while(!(I2C->SR1 & 8) &&  tout());                  // Wait for header ack (ADD10)
95
      if(tout())
96
      {
97
        I2C->DR = (u8)(SLAVE_ADDRESS);                    // Send lower 8-bit device address & Write 
98
      }
99
    #else
100
      I2C->DR = (u8)(SLAVE_ADDRESS << 1);                 // Send 7-bit device address & Write (R/W = 0)
101
    #endif
102
  }
103
  while(!(I2C->SR1 & 2) && tout());                       // Wait for address ack (ADDR)
104
  dead_time();                                            // ADDR clearing sequence
105
  I2C->SR3;
106
  while(!(I2C->SR1 & 0x80) && tout());                    // Wait for TxE
107
  if(tout())
108
  {
109
    I2C->DR = u8_regAddr;                                 // send Offset command
110
  }
111
  if(u8_NumByteToWrite)
112
  {
113
    while(u8_NumByteToWrite--)                            
114
    {                                                      // write data loop start
115
      while(!(I2C->SR1 & 0x80) && tout());                  // test EV8 - wait for TxE
116
      I2C->DR = *u8_DataBuffer++;                           // send next data byte
117
    }                                                      // write data loop end
118
  }
119
  while(((I2C->SR1 & 0x84) != 0x84) && tout());           // Wait for TxE & BTF
120
  dead_time();                                            // clearing sequence
121
  
122
  I2C->CR2 |= 2;                                          // generate stop here (STOP=1)
123
  while((I2C->CR2 & 2) && tout());                        // wait until stop is performed  
124
}

von proethel (Gast)


Angehängte Dateien:

Lesenswert?

Ich hab mal die Initialisierungssqequenz und die I2C-Funktionen 
angehangen die ich auf einem STM8S-DISCOVERY verwende. Bei dir vermisse 
ich die Initialisierung des Clock Controllers (CLK_ClockSwitchConfig()) 
um von der langsamen Startfrequenz auf die 16MHz zu schalten.

von µC8051 (Gast)


Lesenswert?

proethel schrieb:
> Ich hab mal die Initialisierungssqequenz und die I2C-Funktionen
> angehangen die ich auf einem STM8S-DISCOVERY verwende. Bei dir vermisse
> ich die Initialisierung des Clock Controllers (CLK_ClockSwitchConfig())
> um von der langsamen Startfrequenz auf die 16MHz zu schalten.

Vielen Dank für deine Lösung. Ich habe jetzt außer deine Init alles was 
für den I2C wichtig ist raus genommen und in meine Init geschrieben.
Leider tritt auch hier wieder der gleiche Fehler auf, das er in der 
Abfrage vom Busy Bit hängen bleibt und dann in den Fehler springt.

1
void INIT_Reset(void){
2
  GPIO_Init(GPIOB, GPIO_PIN_4, GPIO_MODE_OUT_OD_HIZ_FAST);
3
  GPIO_Init(GPIOB, GPIO_PIN_5, GPIO_MODE_OUT_OD_HIZ_FAST);
4
  
5
  CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO,
6
                        CLK_SOURCE_HSE,
7
                        DISABLE,
8
                        CLK_CURRENTCLOCKSTATE_DISABLE);
9
10
   // High speed internal clock prescaler: 1
11
   // CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);
12
  while((CLK->SWCR & CLK_SWCR_SWIF) == 0);
13
  
14
  I2C_DeInit();
15
   I2C_Init(100000,                                                              // uint32_t OutputClockFrequencyHz,
16
            0xA0,                                                                // uint16_t OwnAddress,
17
            I2C_DUTYCYCLE_2,                                                     // I2C_DutyCycle_TypeDef I2C_DutyCycle,
18
            I2C_ACK_NEXT,                                                        // I2C_Ack_TypeDef Ack,
19
            I2C_ADDMODE_7BIT,                                                    // I2C_AddMode_TypeDef AddMode,
20
            16);                                                                 // uint8_t InputClockFrequencyMHz
21
22
   I2C_ITConfig(I2C_IT_EVT, DISABLE);
23
   I2C_ITConfig(I2C_IT_BUF, DISABLE);
24
   
25
   enableInterrupts();
26
27
   I2C_Cmd(ENABLE);
28
}

von µC8051 (Gast)


Lesenswert?

Sollte natürlich "aus" deiner Init heißen

von proethel (Gast)


Lesenswert?

Ich verwende den externen Quarz auf dem Discovery-Board (HSE). Wenn du 
den internen Takt (HSI) verwendest (ich gehe weiterhin davon aus) ist 
die Funktion CLK_ClockSwitchConfig() anzupassen, also mindestens 
CLK_SOURCE_HSE wäre dann falsch. Schau dir mal den Abschnitt "9.2 Master 
clock switching, Figure 23. Clock switching flowchart (manual mode 
example)" im Reference Manual an. Ich habe im Augenblick wenig Zeit, 
aber ich werde mich heute abend wieder melden.

von proethel (Gast)


Lesenswert?

Versuch doch einfach mal

I2C_Init(1000,
         0xA0,
I2C_DUTYCYCLE_2, 
I2C_ACK_NEXT, 
I2C_ADDMODE_7BIT,
2);

von proethel (Gast)


Lesenswert?

(Mist, unbeabsichtigt abgedrückt)
Dann sollte I2C testweise auch mit 2MHz funktionieren.

von µC8051 (Gast)


Lesenswert?

proethel schrieb:
> Versuch doch einfach mal
>
> I2C_Init(1000,
>          0xA0,
> I2C_DUTYCYCLE_2,
> I2C_ACK_NEXT,
> I2C_ADDMODE_7BIT,
> 2);

Hallo,

das habe ich auch schon probiert. Gleicher Fehler Busy Bit bleibt 
gesetzt.

Prinzipiell ist es mir ertmal egal ob der µC mit derm Internen oder dem 
externen Tackt läuft. Habe jetzt aber auch mal den Teil des Manuals 
bezüglich des CLK angeschaut. Meiner Ansicht nach muss man eben nur 
CLK_SOURCE_HSE zu CLK_SOURCE_HSI wechseln. Damit er mit dem interenn 
Clock läuft dann bleibt er allerdings in der Schleife
1
 while((CLK->SWCR & CLK_SWCR_SWIF) == 0);
 hängen da wohl das "Switch done" bit nicht kommt.

Ich saß gestern auch schon 3h mit meinem µC Proffessor dran aber auch 
der konnte mir nicht helfen.

von µC8051 (Gast)


Lesenswert?

Hab das Problem gelöst.

Werde morgen kurz die Lösung Posten.

Dank an alle die Versucht haben mir zu helfen.

von µC8051 (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

etwas verspätet aber hier die Lösung meines Problems.

Einfach im Programm ST Visual Develop Tools-Programmer und dort die 
"Option Bytes" für I2C aktievieren (Siehe Bild1). Anschließend müssen 
die OPtion Bytes noch Programmiert werden (Siehe Bild2).

von Michael K. (Gast)


Lesenswert?

proethel schrieb:
> Dann schau die deine Initialisierung an, besonders die Clock (und in dem
> Zusammenhang auch die Option Bytes)

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.