Forum: Mikrocontroller und Digitale Elektronik I2C mit PIC18F4680 als Slave


von Philipp H. (phil1403)


Lesenswert?

Hallo Leute, ich versuche seit einigen Tagen das I2C im Master Slave 
Modus zu betreiben. Master = PIC18F4680 Nr.1 und Slave = PIC18F4680 
Nr.2. Den PIC als Master zu verwenden funktioniert! Aber der PIC als 
Slave -> funktioniert nur ansatzweise. Entweder kommt beim Daten 
einlesen kein BF (Buffer full) oder es wird kein SSPIF (Interrupt flag 
gesetzt) - obwohl meiner Meinung nach alle interrupts "enabled" sind. 
Kann mir da jemand helfen?! Wär echt super.

Hier die gesetzten Bits aus der main.c, auch wenn ich keine Interrupt 
Service Routine verwende. Die Flags müssten ja auch so auslesbar sein.
1
  RCONbits.IPEN = 1;        // for low and high priority interrupts
2
  INTCONbits.GIE = 1;       // Enables all high priority peripheral interrupts       
3
  INTCONbits.PEIE = 1;      // Enables all low priority peripheral interrupts
Hier mal meine I2C init Funktion:
1
#define SLAVE_ADDR   0x08    // Slave address
2
#define GENERAL_CALL 0x00    // Master can address all Slaves
3
4
void settingsI2C(void)
5
{
6
 /** \brief This function configure the I2C modul.                          \n
7
  *  For initialization of the I2C Port it is usefull to use the C18 Library function "OpenI2C()".   \n
8
  *  Furthermore you have to <b> pull up </b> the SDA and SCL pin, 2kOhm are sufficient! 
9
  */
10
  // Serial-PORTs ////////////////////////////////////////////////////////////////
11
  // begin: configuration according to Errata sheet ************//
12
  TRISCbits.TRISC3 = 0;        // set pins as Outputs
13
  TRISCbits.TRISC4 = 0;
14
  LATCbits.LATC3 = 0;          // force SDA and SCL low
15
  LATCbits.LATC4 = 0;
16
  // end: configuration according to Errata sheet ************//
17
18
  TRISCbits.TRISC3 = 1;        // Set SCL as input, the MSSP module will ensure that each pin is configured as an output when needed! (AppNote 989)
19
  TRISCbits.TRISC4 = 1;        // Set SDA as input  
20
21
  sync_mode = SLAVE_7;         // I2C slave mode, 7-bit address
22
  slew = SLEW_OFF;             // 100kHz 
23
  SSPADD = SLAVE_ADDR;         // in SLAVE mode = slave_x 7bit-address, x = 1...6 -> here Slave_1    
24
  OpenI2C(sync_mode,slew);     // initialize slave mode
25
  SSPCON1bits.SSPEN = 1;       // enables serial port pins SDA und SCL
26
  SSPCON1bits.CKP = 1;         // release clock
27
  SSPCON2bits.SEN = 1;         // clock stretch enable for slave transmit and receive mode
28
  SSPSTATbits.CKE = 0;         // SMBus specific inputs disabled = 0, enabled = 1
29
  PIE1bits.SSPIE = 1;          // Enable = 1 master synchronous serial port interrupt
30
  IPR1bits.SSPIP = 1;          // Set priority of interrupt to high = 1, low = 0
31
  SSPCON2bits.GCEN = 1;        // General call is enabled when = 1
32
//  IdleI2C();            // the NOTE1 in Datasheet, at page 199 give evidence to set the bus in idle state, but only the master have to do it so
33
}

Und hier die Funktion für das Einlesen der Daten:
1
unsigned char get_byte_I2C(void)
2
{
3
/** \brief This function read a byte from the I2C bus.            \n
4
 *  \var uint8 buffer transfer the value of SSPBUF-Register.        \n
5
 *  \return buffer is the returned value of SSPBUF.
6
 */
7
  uint8 buffer = 0;   
8
      
9
  if(!PIR1bits.SSPIF)              // When SSPIF = 0, interrupt still not occur
10
  {
11
      while (DataRdyI2C() = 0);    // wait until byte received, check the BF-bit (Buffer full),SSPSR is loaded into SSPBUF if BF = 1, receive complete (C18 Library function)
12
    buffer = SSPBUF;               // buffers the SSPBUF
13
  }      
14
return buffer;
15
}

Danke schon mal für eure Tipps, falls ihr welche habt. Irgendwo ist da 
noch ein Fehler drin.

von holger (Gast)


Lesenswert?

while (DataRdyI2C() == 0);    // wait until byte received, check the

von Philipp H. (phil1403)


Lesenswert?

Danke, hab ich glatt übersehen.

von Philipp H. (phil1403)


Angehängte Dateien:

Lesenswert?

So nun hab ich gleich noch ein nächstes Problem nachdem das erste gelöst 
wurde. ;) Ich poste mal den Code hierher, auch wenn es bißchen viel 
wird.
Ich möchte zwischen den beiden besagten PICs eine bidirektionale 
Kommunikation herstellen. Das heißt, der Master sendet dem Slave das 
Start Kommando, dann die Adresse mit WRITE, dann 3Byte und ein Stop 
Signal, Als nächstes wird erneut ein Start Signal gesendet und wieder 
die Adresse, allerdings mit READ, danach hört einfach der Takt auf und 
die angeforderten Daten vom Slave werden nicht übernommen. Dieses 
Phänomen kann ich mir grad nicht erklären. Wie kann ich den Takt des 
Masters wieder aktivieren?
-> Ein Oszibild ist anbei.

Die Hauptfunktionen des Slave: In der main.c wird innerhalb der while 
Schleife die requestI2C() aufgerufen.
1
void requestI2C(void)
2
{
3
 /** \brief This function decide according to its variable status which case receive/transmit will used. \n
4
  *  \var uint8 status Transfer the value from function scanRWI2C() - check R/W bit.       
5
  */
6
  unsigned char status = 0;
7
  unsigned char read = 0;
8
9
  status = scanRWI2C();       // Returns the "mode" - communication Master -> Slave
10
11
  switch(status)              // If the slave is selected through "General Call" or "Slave Address" than do ...
12
  {  // case 1 means Slave is not selected by address
13
    case 1: 
14
        break;
15
16
    // case 2 means Slave is selected by address and Write Bit is set
17
    case 2:  while(!SSPSTATbits.P)    // As long as the stop condition for I2C transmission does not occur
18
        {
19
          read = getByteI2C();        // Read new byte from bus
20
          receiveDataI2C(read);       // Read "Identifier" 
21
        }
22
        break;
23
24
    // case 3 means Slave is selected by address and Read Bit is set
25
    case 3:  while(!SSPSTATbits.P)    // As long as the stop condition for I2C transmission does not occur
26
        {
27
          transmitDataI2C();          // Send the states of "MOSFET-Test" to Master 
28
        }
29
        break;
30
  }
31
}
32
33
void clearFlagsI2C(void)
34
{
35
  SSPCON1bits.SSPOV = 0;        // after reading the SSPBUF, the SSPOV bit properly clear an overflow condition
36
  PIR1bits.SSPIF = 0;           // Clear interrupt flag, to continiue communication
37
  SSPCON1bits.CKP = 1;          // Release clock, when = 1
38
}
39
40
unsigned char getByteI2C(void)
41
{
42
 /** \brief This function read a byte from the I2C bus.              \n
43
  *  \var uint8 buffer transfer the value of SSPBUF-Register.        \n
44
  *  \return buffer is the returned value of SSPBUF.
45
  */  
46
  uint8 bufSSPBUF = 0;
47
  
48
  while (!SSPSTATbits.BF);       // Wait until byte received, returns 1 if the BF bit is set, or 0 if not
49
     bufSSPBUF = SSPBUF;         // Save incoming byte
50
    clearFlagsI2C();  
51
return bufSSPBUF;
52
}
53
54
unsigned char transmitDataI2C(void)
55
{
56
 /** \brief This function write a byte to the bus (master).
57
  */  
58
   clearFlagsI2C();
59
   if(WriteI2C(0x33) == 0)        // 0 if acknowledge was received
60
   {
61
       clearFlagsI2C();
62
       return 1;
63
   }
64
   else
65
  return 0;  
66
}

Die Hauptroutine des Master wird ebenso innerhalb der while Schleife der 
main.c aufgerufen. Die Funktionen getByte und clearFlags sind die 
gleichen wie beim Slave.
So nun liegt der Fehler wahrscheinlich in der folgenden Funktion. Aber 
wo genau?
1
main()
2
{
3
  CloseI2C();                  // close i2c if was operating earlier
4
  sync_mode = MASTER;          // I2C Master mode, 7-bit address
5
  slew = SLEW_OFF;             // 100kHz  
6
  OpenI2C(sync_mode,slew);     // initialize master mode
7
8
  SSPADD = 0x60;  //64         // 100kHz Baud clock(3) @20MHz, Fcy=10MHz (0x18 wenn Fosc = 10MHz, 0x64 wenn Fosc = 40MHz)
9
  slave_adr = 0x10;            // initialize slave address, da /Bit, um eins nach links schieben
10
  readmode1 = (slave_adr & 0xFE);    // 0x00 = Write
11
  readmode2 = (slave_adr | 0x01);    // 0x01 = Read
12
13
  while(1)
14
  {  
15
    IdleI2C();      
16
    StartI2C();
17
    IdleI2C();
18
    if(WriteI2C(readmode1)== 0)    // write SLAVE Adress and write command
19
    {    
20
      if(WriteI2C(0x01) == 0)      // Send Identifier 1
21
      {
22
      //  clearFlagsI2C();
23
      } 
24
      if(WriteI2C(0x11) == 0)      // Send highbyte
25
      {
26
      //  clearFlagsI2C();
27
      }    
28
      if(WriteI2C(0x11) == 0)      // Send lowbyte
29
      {
30
      //  clearFlagsI2C();
31
      }
32
    }
33
    IdleI2C();
34
    //RestartI2C();
35
    StopI2C();
36
    IdleI2C();
37
    StartI2C();
38
    IdleI2C();
39
    if(WriteI2C(readmode2)== 0)    // Write SLAVE Adress and write command
40
    {  
41
/* Ab hier steigt der Master aus */
42
      uint8 bufSSPBUF = 0;
43
      clearFlagsI2C();
44
//      SSPCON2bits.RCEN = 1;      // Set master receive enable
45
//      while(!SSPCON2bits.RCEN)
46
      bufSSPBUF = ReadI2C();       // Read byte from bus
47
      clearFlagsI2C();
48
      AckI2C();                    // Master receive enable = 1 and ACKDT = 0 (acknowledge will be send)
49
      clearFlagsI2C();
50
    }
51
    IdleI2C();
52
    StopI2C();                     // Send the Stop condition
53
  } // while_end
54
}

Danke im voraus für diverse Tipps.

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.