mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik STM32 IIC Datenübertragung?


Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe einen STM32F103 und möchte über Interrupt die IIC Kommunikation 
herstellen.

Konkret geht es um einen Chip, der hat eine 7-Bit Chip-Adresse, 16 Bit 
Adresse und immer 16 Bit Daten. Der STM32 ist der Master.

Das Schreiben von diesen 5 Bytes geht ohne Probleme.

Mit dem Lesen hab ich noch Schwierigkeiten, da erhalte ich immer andere 
Interrupts.

Also das Lesen:
- Senden der Chip-Kennung, 7 Bit
- Senden der Adresse, 16 Bit
- Erneut Start-Bit
- Senden der Chip-Kennung, 7 Bit, Lese-Bit
- Dann möchte ich die 16 Bit Lesen

Dem Oszi nach kommen die auch an, aber der STM32 generiert 18 
Clock-Signale ohne dazwischen einen Interrupt zu generieren, somit kann 
ich dem beim letzten Lese-Byte nicht sagen, dass der ein Stop generieren 
soll.
Jetzt hängt der Chip endlos in IIC-Interrupts, CLK ist Hi, DAT ist LOW.

Die Demos von STM haben auch nur ein Schreiben vom serielen EEPROM, aber 
wie geht das mit dem Lesen richtig?

Vielen Dank für eure Unterstützung, anbei mein Code.

//**************************************************************************************************************************
// Definitionen von globalen Variablen
//**************************************************************************************************************************

u8  IIC_DevAddr; // IIC-Device Adresse
u16 IIC_Addr;    // Register-Adresse
u16 IIC_Data;    // Daten Wort
u8  IIC_Mode;    // Modus: 0=kein, 1=schreiben, 2=lesen
u8  IIC_Stat;    // Status: 0=in Arbeit, 1=Fertig

s16  IIC_Count;

// Initialiseren IIC Bus
void IICInit(char bRefresh)
{
  if (!bRefresh)
  {
    IIC_DevAddr = 0x58;
    IIC_Addr = 0;
    IIC_Data = 0;
    IIC_Mode = 0;
    IIC_Stat = 1;
    IIC_Count = 0;
    I2C_DeInit(I2C2);
  }
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);

  /* Configure I2C2 pins: SCL and SDA ----------------------------------------*/
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

  I2C_Cmd(I2C2, ENABLE);

  /* I2C2 configuration ------------------------------------------------------*/
  I2C_InitTypeDef  I2C_InitSt;
  I2C_InitSt.I2C_Mode = I2C_Mode_I2C;
  I2C_InitSt.I2C_DutyCycle = I2C_DutyCycle_2;
  I2C_InitSt.I2C_OwnAddress1 = IIC_DevAddr;
  I2C_InitSt.I2C_Ack = I2C_Ack_Enable;
  I2C_InitSt.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
  I2C_InitSt.I2C_ClockSpeed = 40000;
  I2C_Init(I2C2, &I2C_InitSt);

    /* Configure and enable I2C2 interrupt -------------------------------------*/
  NVIC_InitTypeDef NVIC_InitSt;
  NVIC_InitSt.NVIC_IRQChannel = I2C2_EV_IRQChannel;
  NVIC_InitSt.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitSt.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitSt.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitSt);

  I2C_ITConfig(I2C2, I2C_IT_EVT | I2C_IT_BUF, ENABLE);
}

// IIC Übertragung abgeschlossen
u8 IIC_Ready(void)
{
  return IIC_Stat;
}

// Schreibe Daten
void IIC_Write(u16 Addr, u16 Data)
{
  if (!IIC_Stat) return; // Doppelte Befehle gehen nicht!
  IIC_Addr = Addr;
  IIC_Data = Data;
  IIC_Mode = 1;
  IIC_Stat = 0;
  IIC_Count = 0;
  //I2C_GenerateSTOP(I2C2, DISABLE);
  I2C_GenerateSTART(I2C2, ENABLE);
}

// Leseanforderung Daten starten
void IIC_ReadStart(u16 Addr)
{
  IICInit(0); // *DEBUG für Test
  if (!IIC_Stat) return; // Doppelte Befehle gehen nicht!
  IIC_Addr = Addr;
  IIC_Data = 0;
  IIC_Mode = 2;
  IIC_Stat = 0;
  IIC_Count = 0;
  //I2C_GenerateSTOP(I2C2, DISABLE);
  I2C_GenerateSTART(I2C2, ENABLE);
}

// Daten der Leseanforderung
u16 IIC_ReadData(void)
{
  if (!IIC_Stat) return 0; // Nicht fertig
  return IIC_Data;
}

// Interrupt
void IIC_ISR(void)
{
  u32 i = I2C_GetLastEvent(I2C2);
  switch (i)
  {
      /* Test on I2C2 EV5 and clear it */
  case I2C_EVENT_MASTER_MODE_SELECT:
    /* Send I2C2 slave Address for write */
    if (IIC_Mode <= 2)
      I2C_Send7bitAddress(I2C2, IIC_DevAddr, I2C_Direction_Transmitter);
    else if (IIC_Mode == 3)
      I2C_AcknowledgeConfig(I2C2, ENABLE);
//      I2C_Send7bitAddress(I2C2, IIC_DevAddr, I2C_Direction_Receiver);
    break;

    /* Test on I2C2 EV6 and first EV8 and clear them */
  case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED:
    /* I2C2 and I2C2 PEC Transmission Enable */
    I2C_CalculatePEC(I2C2, ENABLE);
    /* Send the first data */
    I2C_SendData(I2C2, (u8)((u16)(IIC_Addr >> 8) & 0xFF));  //EV8 just after EV6
    IIC_Count++;
    break;

  case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED:
    break;

  case I2C_EVENT_MASTER_BYTE_RECEIVED:
    switch (IIC_Count)
    {
    case 4:
      I2C_AcknowledgeConfig(I2C2, DISABLE);
      IIC_Data = ((u16)I2C_ReceiveData(I2C2)) << 8;
      break;
    case 5:
      I2C_GenerateSTOP(I2C2, ENABLE);
      IIC_Data |= ((u16)I2C_ReceiveData(I2C2));
      I2C_AcknowledgeConfig(I2C2, ENABLE);
      IIC_Stat = 1;
      break;
    }
    IIC_Count++;
    break;
  case 196611:
    I2C_AcknowledgeConfig(I2C2, DISABLE);
//    I2C_AcknowledgeConfig(I2C2, ENABLE);
    //IIC_Data = ((u16)I2C_ReceiveData(I2C2)) << 8;
    //IIC_Data |= ((u16)I2C_ReceiveData(I2C2));
    //IIC_Stat = 1;
    break;
  case 196677:
    I2C_GenerateSTOP(I2C2, ENABLE);
    //IIC_Data |= ((u16)I2C_ReceiveData(I2C2));
    break;

    /* Test on I2C2 EV8 and clear it */
  case I2C_EVENT_MASTER_BYTE_TRANSMITTED:
    if (I2C2->SR1 & 0x04000) // NACK Returned!
    {
      I2C_GenerateSTOP(I2C2, ENABLE);
      IIC_Stat = 1;
      return;
    }
    switch (IIC_Count)
    {
    case 1:
      I2C_SendData(I2C2, IIC_Addr & 0xFF);
      break;
    case 2:
      if (IIC_Mode == 2)
      {
        //I2C_GenerateSTOP(I2C2, ENABLE);
        I2C_GenerateSTART(I2C2, ENABLE); // Start-Bit für nächstes Lesen
        IIC_Mode = 3;
      } else I2C_SendData(I2C2, (u8)((u16)(IIC_Data >> 8) & 0xFF));
      break;
    case 3:
      if (IIC_Mode == 3)
      {
        //I2C_GenerateSTOP(I2C2, ENABLE);
        I2C_AcknowledgeConfig(I2C2, DISABLE);
        I2C_Send7bitAddress(I2C2, IIC_DevAddr, I2C_Direction_Receiver);
      } else {
        I2C_SendData(I2C2, IIC_Data & 0xFF);
        IIC_Stat = 1;
      }
      break;
    case 4:
      I2C_GenerateSTOP(I2C2, ENABLE);
      IIC_Stat = 1;
      break;
    default:
      I2C_TransmitPEC(I2C2, ENABLE);
      break;
    }
    IIC_Count++;
    break;

  case I2C_EVENT_SLAVE_ACK_FAILURE:
    I2C_GenerateSTOP(I2C2, ENABLE);
    IIC_Stat = 1;
    break;

    default:
      break;
  }
}

Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hat keine eine Idee dazu?

Autor: Reinhard B. (brainstorm)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Im Reference Manual von ST (RM0008) steht dazu was auf Seite 588. Unter 
den Punkten "Master receiver" und "Closing the Communication".

Und bei den Support Files von ST gibts auch noch die FWLib, in der alle 
Peripherieeinheiten implementiert sind. Die I2C Routinen von dort können 
mit Sicherheit auch Lesen.

mfg

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
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.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.