Forum: Mikrocontroller und Digitale Elektronik STM32F10x mit Atmega8 über i2c funktioniert nicht?


von Julian S. (yusa)


Angehängte Dateien:

Lesenswert?

Hallo liebe µC Gemeinde,

hänge hier seit mehreren Tagen an einem Problem:

Auf einem Atmega8 läuft eine i2c EEPROM Emulation als Slave. Diese 
sollte auch wunderbar funktionieren, da ich das mit einem Arduino 
bereits erfolgreich testen konnte!

Für mein Projekt will ich aber keinen Arduino sondern das STM32F10X 
Discovery Board verwenden. Also musste ein Master für den STM32 her.

Ich benutze dafür die Stdperiph stm32 lib.

In der Funktion I2C_start() bleibt er in der Zeile hängen:
1
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); // Here it hangs...

Slave hat die Adresse 0x50. Vor der Übergabe wird diese noch eins nach 
links geshiftet.

Hardwaretechnisch habe ich 4,7k Pullups auf 5V! Eigentlich arbeitet der 
STM32 ja mit 3,3V. Atmega8 arbeitet mit 5V. Das dürfte jedoch kein 
Problem am i2c Bus sein, oder??

SCL hab ich jetzt auf 50kHz, da der Atmega8 nur mit internen 1MHz 
arbeitet.

Ich muss sagen, das ist mein erstes Projekt mit einem ARM Controller. 
Habe ich evtl bei der Initialisierung etwas falsch gemacht?

Als zip hängt noch mein komplettes Projekt an!

Gruß Julian


Hier meine wichtigsten Files:

main.c
1
//  STM32 Discovery I2C Sample
2
3
4
#include "stm32f10x.h"
5
#include "i2c.h"
6
7
#define STACK_TOP 0x20002000-4                    // init Stackpointer
8
9
void nmi_handler(void);                        
10
void hardfault_handler(void);
11
    
12
unsigned char temp = 0;
13
unsigned char temp2 = 0;
14
15
16
17
int main(void);
18
19
/* vector table */
20
21
unsigned int * myvectors[4] 
22
__attribute__ ((section("vectors")))= {
23
    (unsigned int *)  STACK_TOP,         
24
    (unsigned int *)   main,              
25
    (unsigned int *)  nmi_handler,       
26
    (unsigned int *)  hardfault_handler,
27
28
};
29
30
int main(void){  
31
32
  int SLAVE_ADDR = 0x50;
33
34
  /* Enable the GPIOA (bit 2) and GPIOC (bit 8) */
35
  RCC->APB2ENR |= 0x10 | 0x04;
36
37
  /* Set GPIOC Pin 8 and Pin 9 to outputs */
38
  GPIOC->CRH = 0x11;
39
40
  /* Set GPIOA Pin 0 to input floating */
41
  GPIOA->CRL = 0x04;
42
  
43
  /*
44
  GPIOC->BSRR = 1<<8;   //Switch on blue
45
  GPIOC->BSRR = 1<<24;  //Switch off blue
46
  GPIOC->BSRR = 1<<9 ;  //Switch green on
47
  GPIOC->BSRR = 1<<25;  //Switch green off
48
  */
49
50
  char buf[20];
51
  int off = 0;
52
  int len = 1;
53
  buf[0] = 'H';
54
  buf[1] = 'a';
55
  buf[2] = 'l';
56
57
58
  InitI2C();
59
  I2C_start(I2C1, SLAVE_ADDR << 1, I2C_Direction_Transmitter);
60
61
  I2C_write(I2C1, 0x00);    //Set internal Slave register
62
  I2C_write(I2C1, buf[0]);
63
  I2C_write(I2C1, buf[1]);
64
  I2C_write(I2C1, buf[2]);
65
  
66
  I2C_stop(I2C1);
67
68
69
  buf[0] = 0;
70
  buf[1] = 0;
71
  buf[2] = 0;
72
73
74
  I2C_start(I2C1, SLAVE_ADDR << 1 , I2C_Direction_Transmitter);
75
  I2C_write(I2C1, 0x00);
76
  I2C_restart(I2C1, SLAVE_ADDR << 1 , I2C_Direction_Receiver);
77
  buf[0] = I2C_read_ack(I2C1);
78
  buf[1] = I2C_read_ack(I2C1);
79
  buf[2] = I2C_read_nack(I2C1);
80
 
81
  I2C_stop(I2C1);
82
83
84
  if (buf[0] == 'H') {
85
    //Yipieea it works!
86
87
    GPIOC->BSRR = 1<<9 ;  //Switch green on
88
    GPIOC->BSRR = 1<<24;  //Switch off blue
89
  } else {
90
    GPIOC->BSRR = 1<<8;   //Switch on blue
91
    GPIOC->BSRR = 1<<25;  //Switch off green
92
  }
93
94
  while(1) ;
95
96
97
  return 0;
98
}
99
100
void nmi_handler(void)
101
{
102
    return ;
103
}
104
105
void hardfault_handler(void)
106
{
107
    return ;
108
}

i2c.c
1
#include "i2c.h"
2
3
void InitI2C()
4
{
5
    I2C_InitTypeDef I2C_InitStructure;
6
    GPIO_InitTypeDef GPIO_InitStructure;
7
8
    SystemInit();
9
10
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
11
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
12
 
13
    /* Reset I2Cx IP */
14
    RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE);
15
 
16
    /* Release reset signal of I2Cx IP */
17
    RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, DISABLE);
18
 
19
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
20
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
21
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // Open Drain, I2C bus pulled high externally
22
    GPIO_Init(GPIOB, &GPIO_InitStructure);
23
24
25
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
26
    //I2C_InitStructure.I2C_OwnAddress1 = 0x00;        //Eigene Adresse für Slave oder Multimaster betrieb, ansonsten irrelevant
27
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
28
    I2C_InitStructure.I2C_Ack = I2C_Ack_Disable;
29
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;   //Adress-Modus, normalerweise 7-Bit
30
    I2C_InitStructure.I2C_ClockSpeed = 50000;        //Taktgeschwindigkeit von SCL, hier 50kHz
31
 
32
    I2C_Init(I2C1, &I2C_InitStructure);
33
 
34
    I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF, DISABLE);  //Keine Interrupts
35
 
36
    I2C_Cmd(I2C1, ENABLE);
37
}
38
39
void I2C_start(I2C_TypeDef* I2Cx, uint8_t address, uint8_t direction){
40
  // wait until I2C1 is not busy any more
41
  while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));
42
 
43
  // Send I2C1 START condition
44
  I2C_GenerateSTART(I2Cx, ENABLE);
45
 
46
  // wait for I2C1 EV5 --> Slave has acknowledged start condition
47
  while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
48
 
49
  // Send slave Address for write
50
  I2C_Send7bitAddress(I2Cx, address, direction);
51
 
52
  /* wait for I2Cx EV6, check if
53
   * either Slave has acknowledged Master transmitter or
54
   * Master receiver mode, depending on the transmission
55
   * direction
56
   */
57
  if(direction == I2C_Direction_Transmitter){
58
    GPIOC->BSRR = 1<<8;   //Switch on blue
59
    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); // Here it hangs...
60
    GPIOC->BSRR = 1<<9 ;  //Switch green on
61
  }
62
  else if(direction == I2C_Direction_Receiver){
63
    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
64
  }
65
}
66
67
void I2C_restart(I2C_TypeDef * I2Cx, uint8_t address, uint8_t direction)
68
{
69
    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTING));
70
    I2Cx->CR1 |= I2C_CR1_START;
71
 
72
    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
73
    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
74
 
75
  // Send slave Address for write
76
  I2C_Send7bitAddress(I2Cx, address, direction);
77
 
78
  /* wait for I2Cx EV6, check if
79
   * either Slave has acknowledged Master transmitter or
80
   * Master receiver mode, depending on the transmission
81
   * direction
82
   */
83
  if(direction == I2C_Direction_Transmitter){
84
    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
85
  }
86
  else if(direction == I2C_Direction_Receiver){
87
    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
88
  }
89
}
90
91
void I2C_write(I2C_TypeDef* I2Cx, uint8_t data)
92
{
93
  // wait for I2C1 EV8 --> last byte is still being transmitted (last byte in SR, buffer empty), next byte can already be written
94
  while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTING));
95
  I2C_SendData(I2Cx, data);
96
}
97
98
99
uint8_t I2C_read_ack(I2C_TypeDef* I2Cx){
100
  // enable acknowledge of received data
101
  I2C_AcknowledgeConfig(I2Cx, ENABLE);
102
  // wait until one byte has been received
103
  while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) );
104
  // read data from I2C data register and return data byte
105
  uint8_t data = I2C_ReceiveData(I2Cx);
106
  return data;
107
}
108
109
110
uint8_t I2C_read_nack(I2C_TypeDef* I2Cx){
111
  // disable acknowledge of received data
112
  // nack also generates stop condition after last byte received
113
  // see reference manual for more info
114
  I2C_AcknowledgeConfig(I2Cx, DISABLE);
115
  I2C_GenerateSTOP(I2Cx, ENABLE);
116
  // wait until one byte has been received
117
  while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) );
118
  // read data from I2C data register and return data byte
119
  uint8_t data = I2C_ReceiveData(I2Cx);
120
  return data;
121
}
122
123
124
void I2C_stop(I2C_TypeDef* I2Cx){
125
    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
126
  // Send I2C1 STOP Condition after last byte has been transmitted
127
  I2C_GenerateSTOP(I2Cx, ENABLE);
128
  // wait for I2C1 EV8_2 --> byte has been transmitted
129
  while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
130
}

von Walter T. (nicolas)


Lesenswert?

Hallo Julian,

ich bin in einem Parallelthread ( 
Beitrag "STM32F10x : Fehler bei I2C" ) bei einer ähnlichen 
Fragestellung, allerdings mit einem echten 24C02.

Ein paar Punkte kann ich schon ergänzen:

Julian S. schrieb:
> Hardwaretechnisch habe ich 4,7k Pullups auf 5V! Eigentlich arbeitet der
> STM32 ja mit 3,3V. Atmega8 arbeitet mit 5V. Das dürfte jedoch kein
> Problem am i2c Bus sein, oder??

Das ist kein Problem, da genau diese Pins 5V-tolerant sind.

In die markierte Zeile gehört ein Timeout. Wenn der Slave kein "Ack" 
sendet, wartet der Master sonst ewig.

Viele Grüße
W.T.

von Julian S. (yusa)


Lesenswert?

Hallo Walter,

jap, danke für den Hinweiß, habe jetzt überall timeouts mit reingebaut. 
Macht die Sache an sich aber nicht besser ;)

Antwortet hier der Slave bereits aktiv?
1
  // wait for I2C1 EV5 --> Slave has acknowledged start condition
2
  while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));

Wenn ja, frage ich mich warum es dann bei der Funktion
1
  // Send slave Address for write
2
  I2C_Send7bitAddress(I2Cx, address, direction);
nicht mehr klappt.!?

Liegt es an der Addresse? Shifte ich falsch oder unnötig?

Grüße Julian

von Walter T. (nicolas)


Lesenswert?

Julian S. schrieb:
> Antwortet hier der Slave bereits aktiv?  // wait for I2C1 EV5 --> Slave
> has acknowledged start condition
>   while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));

Nein. Hier wird nur die STM32-interne State-Machine abgefragt.

Julian S. schrieb:
> Wenn ja, frage ich mich warum es dann bei der Funktion  // Send slave
> Address for write
>   I2C_Send7bitAddress(I2Cx, address, direction);
> nicht mehr klappt.!?

Hier ist die erste Stelle, wo der Slave etwas machen sollte.

Hast Du ein Oszilloskop?

von Julian S. (yusa)


Lesenswert?

Oszilloskop habe ich leider nicht zur Stelle, da müsste ich bis nächste 
Woche warten, dann kann ich eines in der Uni benutzen..

Ich trau mich ja fast wetten, dass ich irrgentetwas in InitI2C() falsch 
initialisiert habe.

Aber der Fehler kann natürlich auch wo ganz anders liegen :O

Gruß Julian

von Walter T. (nicolas)


Lesenswert?

Julian S. schrieb:
> Ich trau mich ja fast wetten, dass ich irrgentetwas in InitI2C() falsch
> initialisiert habe.
1
/* Initialisierung eines der beiden I2Cs auf den Default-Pins                           */
2
/* Remap wird nicht unterstuetzt
3
 */
4
uint_fast8_t
5
I2C_init(I2C_TypeDef* I2Cx)
6
{
7
8
  GPIO_InitTypeDef GPIO_InitStruct;
9
  I2C_InitTypeDef I2C_InitStruct;
10
11
  I2C_DeInit(I2Cx);
12
13
  if(I2Cx==I2C1) {
14
15
    // enable APB1 peripheral clock for I2C1, SCL and SDA pins
16
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
17
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);
18
19
    // Setup SCL und SDA pins
20
    GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_6 | GPIO_Pin_7;
21
    GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF_OD;
22
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
23
    GPIO_Init(GPIOB, &GPIO_InitStruct);
24
25
    GPIO_PinRemapConfig(GPIO_Remap_I2C1,DISABLE);
26
27
    /* Enable and release I2C1 reset state */
28
    RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE);
29
    RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, DISABLE);
30
31
  }
32
  else if(I2Cx==I2C2) {
33
    // enable APB1 peripheral clock for I2C2, SCL and SDA pins
34
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);
35
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);
36
37
    // Setup SCL und SDA pins
38
    GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_10 | GPIO_Pin_11;
39
    GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF_OD;
40
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
41
    GPIO_Init(GPIOB, &GPIO_InitStruct);
42
43
    // I2C2 laesst sich nicht remappen
44
45
    /* Enable and release I2C1 reset state */
46
    RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C2, ENABLE);
47
    RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C2, DISABLE);
48
  }
49
  else {
50
    return i2c_off;
51
  }
52
53
  // configure I2Cx
54
  if(I2Cx==I2C1)
55
    I2C_InitStruct.I2C_ClockSpeed = I2C1_CLOCK;     // Hz
56
  else if(I2Cx==I2C2)
57
    I2C_InitStruct.I2C_ClockSpeed = I2C2_CLOCK;     // Hz
58
59
  I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
60
    #if I2C_DUTY_CYCLE
61
      I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_16_9;
62
    #else
63
      I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;
64
    #endif
65
66
  I2C_InitStruct.I2C_OwnAddress1 = 0x00;
67
  I2C_InitStruct.I2C_Ack = I2C_Ack_Disable;
68
  I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
69
  I2C_Init(I2Cx, &I2C_InitStruct);
70
71
  return i2c_ok;
72
}
Die ist getestet. Müßten evtl. die Pinnummern angepaßt werden.

von Julian S. (yusa)


Lesenswert?

Dankeschön, ok, dann können wir ausschließen, dass die Init Funktion 
irrgentwas dummes macht..

Funktioniert leider immer noch nicht.
Brauche ich den Aufruf der Funktion
1
SystemInit();

Ich bin mir nicht ganz im klaren was sie tut..

Gruß Julian

von Julian S. (yusa)


Lesenswert?

Hallo Community,

also mein Problem hat sich seit ein paar tagen gelöst.

Problem war, dass die Frequenz zu hoch eingestellt war.

Obwohl dem struct 50000 (Hz) übergeben wurde, war am Ausgang eine 
Frequenz von 680kHz zu messen. Warum auch immmer. (Externer Quarz 
16MHz??)

Das war aber viel zu hoch für den Atmega8.

Nachdem ich der init routine 5000 für die Frequenz übergeben habe, hat 
es dann geklappt (Am Ausgang ca 78kHz).

Gruß Julian

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.