www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik AT91SAM7 I2C multiple write


Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich implementiere gerade das TWI I2C Interface
int I2C_WriteBytes(const AT91PS_TWI pTwi,
                   unsigned int     uiSlaveAddr,
                   char             *data,
                   unsigned int     uiNumOfBytes)
{
  unsigned int end = 0, status, error=0, Count;
  unsigned int iBusy = 0;

  /* Enable Master Mode */
  pTwi->TWI_CR = AT91C_TWI_MSEN;

  /* Wait until TXRDY is high to transmit */
  status = AT91C_BASE_TWI->TWI_SR;
  while (!(status & AT91C_TWI_TXRDY))
    status = AT91C_BASE_TWI->TWI_SR;

  /* Set the TWI Master Mode Register */
  pTwi->TWI_MMR =  (uiSlaveAddr << 16) & ~AT91C_TWI_MREAD;

  /* Send the data */
  for ( Count=0; Count < uiNumOfBytes ;Count++ )
  {
    end = 0;
    iBusy = 0;
    /* Write the data to send into THR. Start conditionn DADDR and R/W bit
       are sent automatically */
    AT91C_BASE_TWI->TWI_THR = *data++;

    /* NACK errata handling */
    /* Do not poll the TWI_SR */
    /* Wait 3 x 9 TWCK pulse (max) before reading TWI_SR */
    /* From 400Khz down to 1Khz, the time to wait will be in µs range.*/
    I2C_WaitMicroSecond (40) ;

    while (!end)
    {
      iBusy++;
      status = AT91C_BASE_TWI->TWI_SR;
      if ((status & AT91C_TWI_NACK) == AT91C_TWI_NACK)
      {
        error++;
        end=1;
      }
      /*  Wait for the Transmit ready is set */
      if ((status & AT91C_TWI_TXRDY) == AT91C_TWI_TXRDY)
        end=1;
          
      if (iBusy > 100000)
        return 9;
    }
  }

  /* Wait for the Transmit complete is set */
  status = AT91C_BASE_TWI->TWI_SR;
  while (!(status & AT91C_TWI_TXCOMP))
    status = AT91C_BASE_TWI->TWI_SR;

  return error;
}

Ich möchte jetzt den multiple write mode nutzen. Also START condition, 
Addressbyte, und n-Datenbytes und abschließend die Stop condition. Mein 
Problem ist jetzt, dass jedes einzelne Datenbyte mit der START- und STOP 
condition übertragen wird.
Habe ich noch einen Fehler im Code???

Danke

Autor: gerhard (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo,
anbei das examples von atmel, vielleicht hilft das mal.

p.s.: das twi interface des at91sam7s ist etwas "buggy", unbedingt das 
errate im datenblatt ansehen.

gruss
gerhard

Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Gerhard,

danke, jetzt funzt es.

Gruss

Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich nutze den oben verlinkten Workaround für das I2C TWI-Interface.
Der Schreibvorgang funktioniert ohne Probleme. Jetzt habe ich aber das 
Problem, dass ich vom I2C Slave lesen möchte. Das funktioniert leider 
nicht. Am Oszi erkennt man, dass das I2C Interface in einer Endlosloop 
ist und permant versucht(I2C-Takt clockt dauerhaft) vom Slave zu lesen.

Anbei male mein Quellcode.
Ist da noch ein Fehler???
void I2C_Init(void)
{
  // Configure TWI PIOs
  AT91F_TWI_CfgPIO ();
  
  // Configure PMC by enabling TWI clock
  AT91F_TWI_CfgPMC ();
 
  // Configure TWI in master mode
  AT91F_TWI_Configure (AT91C_BASE_TWI);
 
  // Set TWI Clock Waveform Generator Register
  I2C_SetClock();
  
  //TWI NACK Bug workaround
  AT91F_AIC_ConfigureIt (     AT91C_BASE_AIC,
                              AT91C_ID_TWI,
                              7,
                              AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE,
                              dummy_irq);
  *AT91C_TWI_IER = (1<<0);
  
  *AT91C_TWI_CR = AT91C_TWI_MSEN;
}

unsigned char I2C_read(unsigned char dev_adr,                                   // slave address
                       unsigned char mem_adr,                                   // internal memory address
                       unsigned char *data,                                     // datapointer for the return data
                       unsigned int n_byte){                                   // count of bytes to read
  unsigned int timeout = 0;
  unsigned char counter;
  unsigned int  uiByteCounter = 0;
  timeout = 0;
  
  *AT91C_TWI_CR = AT91C_TWI_MSEN;                                                 //Enable the TWI Master Mode
  *AT91C_TWI_IADR = mem_adr;                                                    //Set the TWI Slave memory address
  *AT91C_TWI_MMR = ((dev_adr<<16)                                               //Slave address
                    | AT91C_TWI_MREAD);                                           //Master read mode
                    //| AT91C_TWI_IADRSZ_1_BYTE);                                 //Slave internal addtess site 1 byte
  *AT91C_TWI_CR = AT91C_TWI_START;                                              //Send the start condition slave address and set read mode
  while(!(*AT91C_AIC_IPR & (1<<AT91C_ID_TWI)))                                  //TX Complete TWI irq polling
  {                                 
    timeout++;
    if(timeout >= 10000000){
      I2C_stop();
      return TWI_TXTIMEOUT;                                                     //Exit on TXCOMP timeout
    }
  }
  I2C_nack_wait();
  if(*AT91C_TWI_SR & AT91C_TWI_NACK){                                           //Slave exist and send ACK?
    I2C_stop();
    return TWI_NACK;                                                            //Exit on NACK
  }
  counter = 0;
  
  while(uiByteCounter != n_byte)
  {                                                               //Recive
    timeout = 0;
    while((!(*AT91C_TWI_SR & AT91C_TWI_RXRDY))){                                //Wait for data redady
      timeout++;
      if(timeout>=1000000){
        I2C_stop();
        return TWI_TXTIMEOUT_READ;                                              //Exit on RXRDY timeout
      }
    }
    data[uiByteCounter++] = AT91C_BASE_TWI->TWI_RHR;//(unsigned char) *AT91C_TWI_RHR;                                       //Read data
    uiByteCounter++;
  }
  
  I2C_stop();
  
  return 0;
}

static void dummy_irq(void)
{
  volatile unsigned int uiStatus     = 0;
  volatile unsigned int uiDelay      = 0;

  // signal start of Interrupt Service Routine
  uiStatus = AT91C_BASE_AIC->AIC_IVR;
  uiStatus = uiStatus;

  
  
  // signal end of Interrupt Service Routine
  uiStatus = AT91C_BASE_AIC->AIC_EOICR;
  uiStatus = uiStatus;
}

Danke und Gruss

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.