Menu

read two bytes from the slave i2c bus

Help
2012-05-25
2013-05-30
  • alejandro1957

    alejandro1957 - 2012-05-25

    I can read a byte from the slave i2c bus.
    but when I try to read two bytes are the bus stops.
    here's the master code that reads a byte:

    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    'CHIP
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    #CHIP 16F876A,4
    #CONFIG OSC=XT,WDT_OFF,PWRTE_ON,CP_OFF,DEBUG_OFF,WRT_OFF,CPD_OFF,LVP_OFF,BODEN_ON,BOREN_OFF
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    'VARIABLES & DEFINE
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    DIM Contador AS INTEGER
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    'SUB & FUNCTION
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    SUB Setup_I2C()
    SSPSTAT=b'1100000'
    SSPADD=b'00001001'
    SSPCON2=0
    SSPCON=b'00111000'
    SET PIR1.SSPIF OFF
    SET PIR2.BCLIF OFF
    END SUB
    SUB W_MSSP()
    DO
    LOOP UNTIL PIR1.SSPIF=1
    PIR1.SSPIF=0
    END SUB
    SUB START
    SET SSPCON2.SEN ON
    W_MSSP()
    END SUB
    SUB RESTART
    SET SSPCON2.RSEN ON
    W_MSSP()
    END SUB
    SUB STOP
    SET SSPCON2.PEN ON
    W_MSSP()
    END SUB
    SUB I2C_ACK()
    SET SSP1CON2.ACKDT OFF
    SET SSP1CON2.ACKEN ON 
    W_MSSP()   
    END SUB     
    SUB I2C_Not_ACK()
    SET SSP1CON2.ACKDT ON
    SET SSP1CON2.ACKEN ON 
    W_MSSP()   
    END SUB
    SUB Tx_I2C(SendByte AS BYTE)
    SSPBUF=SendByte
    W_MSSP()
    DO
    LOOP UNTIL SSPCON2.ACKSTAT=0
    END SUB
    FUNCTION I2C_Rx() AS BYTE
    SSPCON2.RCEN=1
    W_MSSP()
    I2C_Rx=SSPBUF
    END FUNCTION
    SUB WRITE_Memory(ID_Address AS BYTE,Address AS WORD,Dato AS WORD)#NR
    START()
    Tx_I2C(ID_Address)
    Tx_I2C(Address_H)
    Tx_I2C(Address)
    Tx_I2C(Dato)
    STOP()
    END SUB
    SUB WRITE_Slave(IDAddress AS WORD,Dato AS WORD)#NR
    START()
    Tx_I2C(IDAddress)
    Tx_I2C(Dato)
    STOP()
    END SUB 
    FUNCTION READ_Memoria(ID_Address AS WORD,Address AS WORD)
    START()
    Tx_I2C(ID_Address)
    Tx_I2C(Address_H)
    Tx_I2C(Address)
    RESTART()
    Tx_I2C(ID_Address+1)
    READ_Memoria=I2C_Rx()
    I2C_Not_ACK()
    STOP()
    END FUNCTION
    FUNCTION READ_Slave(ID_Address AS WORD,Comando AS BYTE)
    START()
    Tx_I2C(ID_Address)
    Tx_I2C(Comando)
    RESTART()
    Tx_I2C(ID_Address+1)
    EPWrite 0x00,I2C_Rx()
    I2C_Not_ACK()
    STOP()
    END FUNCTION
    Inicio:
       TRISA=b'000000'
       TRISB=b'00000000'
       TRISC=b'00011000'
       PORTA=b'000000'
       PORTB=b'00000000'
       PORTC=b'00000000'
       INTCON=b'00000000'
       CVRCON=b'00000000'
       CCP1CON=b'00000000'
       CCP2CON=b'00000000'                                                      
       ADCON0=b'00000000'
       ADCON1=b'10000110'
       Setup_I2C()
       WAIT 1 s
       READ_Slave(0xA6,0xF1)
       PulseOut PORTC.5,1 s
    
     
  • alejandro1957

    alejandro1957 - 2012-05-25

    This is the code of the slave 16F88:

    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    'CHIP
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    #CHIP 16F88,4
    #CONFIG OSC=XT,MCLR_ON,CP_OFF,CCP1_RB3,DEBUG_OFF,WRT_PROTECT_OFF
    #CONFIG CPD_OFF,LVP_OFF,BODEN_ON,PWRTE_ON,WDT_OFF,IESO_OFF,FCMEN_OFF
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    'INTERRUPT
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    On Interrupt SSP1Ready call I2C_Interrupt
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    'VARIABLES
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    DIM InByte,Clear_Address,Contador,Valor(2) AS BYTE
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    'SUB AND FUNCTION
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    SUB I2C_Interrupt()#NR
    IF PIR1.SSPIF=1 THEN
       IF SSPSTAT.D_A=1 THEN
          InByte=SSPBUF
          EPWrite SSPBUF,SSPBUF
       END IF
       IF SSPSTAT.R_W=1&InByte=0xF1 THEN
          SSPBUF=Valor(Contador)
          Contador+=1
          IF Contador>1 THEN Contador=0:InByte=0x00
       END IF
       Clear_Address=SSPBUF
       SSPCON.CKP=1
       PIR1.SSPIF=0
    END IF
    END SUB
    INICIO:
       TRISA=b'000000'
       TRISB=b'00010010'
       PORTA=b'000000'          
       PORTB=b'00000000'        '      
       INTCON=b'11000000'
       SSPADD=0xA6
       SSPSTAT=b'00000000'
       SSPCON=b'00110110'
       PIE1.SSPIE=1
       CVRCON=b'00000000'       
       CMCON=b'00000111'        
       CCP1CON=b'00000000'
       ANSEL=b'00000000'
       ADCON0=b'00000000'
       ADCON1=b'10000000'
       Contador=0 
       Valor(0)=0xAA
       Valor(1)=0xAB  
       InByte=0x00
       DO                       
         ''''''''''''''''''''''              
       LOOP
    
     
  • alejandro1957

    alejandro1957 - 2012-05-25

    but trying to read a second byte blocks.
    this is changing:

    .
    FUNCTION READ_Slave(ID_Address AS WORD,Comando AS BYTE)
    START()
    Tx_I2C(ID_Address)
    Tx_I2C(Comando)
    RESTART()
    Tx_I2C(ID_Address+1)
    EPWrite 0x00,I2C_Rx()
    I2C_ACK()
    EPWrite 0x01,I2C_Rx()
    I2C_Not_ACK()
    STOP()
    END FUNCTION
    .
    

    thanks in advance, and sorry for my english

     
  • kent_twt4

    kent_twt4 - 2012-05-25

    Hi Alejandro,
    Here is some code from my Master I2C read16bit procedure.  Don't have any time to help verify your code, but maybe the comments will help you along : )   The word variable could be assembled from the ReadHighByte and ReadLowByte, good luck.

    Sub Read16bit(WrtCtrl8bit,Addr8bit,RdCtrl8bit)
      Start
      TxI2C(WrtCtrl8bit)  'Device ID write byte
      TxI2C(Addr8bit)  'Send byte address
      Restart
      TxI2C(RdCtrl8bit)  'Device ID read byte
      RxI2CWord  'Receive data byte
      Set ACKDT Off  'Select master acknowledge
      MasterAck  'Master Ack or NoAck depending on ACKDT
      ReadHighByte = ReadByte
      RxI2CWord
      MasterNAck
      ReadLowByte = ReadByte
      Stop
    end sub
    
     
  • alejandro1957

    alejandro1957 - 2012-05-25

    ..Master I2C read16bit procedure..

    this code does not know him.
    could you kindly send it??

     
  • kent_twt4

    kent_twt4 - 2012-05-27

    I am suspicious of trying to do the EPWrite and I2C at the same time, i.e. EPWrite 0x00,I2C_Rx().  Why not try saving to HighByte = I2C_RX() and LowByte = I2C_RX() first; Then write to eeprom later?, i.e. EPWrite 0x00, HighByte……..

    Here is so more code from 4-5 years ago.  The ACK settings are different for RXI2C() and RXI2CWord().

    sub RxI2C
        #IFDEF PIC
            SET SSPIF OFF  
            SET RCEN ON  'Initiate reception
            waitRx:
            IF SSPIF OFF THEN goto waitRx 'Check if operation complete
            ReadByte = SSPBUF  'Read byte in buffer
            'Wait for Not acknowledge
            SET SSPIF OFF  
            SET ACKEN ON  
            waitNoAck:
            IF SSPIF OFF THEN goto waitNoAck 'Check if operation complete
        #ENDIF
    
        #IFDEF AVR
            ReadByte = TWDR
            Set TWINT On    'No "Set TWEN On" for NACK
            waitRx1:
            If TWINT On Then goto waitRx1
            waitNoAck1:
            If TWSR AND 0xF8 <> 0x50 Then goto waitNoack1
            ReadByte = TWDR ;???    
        #ENDIF
    end sub
    sub RxI2CWord  '(ReadByte)
        #IFDEF PIC
            SET SSPIF OFF  'Set PIR1.SSPIF Off
            SET RCEN ON  'Initiate reception
            waitRxWord:
            IF SSPIF OFF THEN goto waitRxWord 'Check if operation complete
            ReadByte = SSPBUF  'Read byte in buffer
        #ENDIF
        #IFDEF AVR
            'use TWEA for NACK
        #ENDIF
    end sub
    
     
  • alejandro1957

    alejandro1957 - 2012-05-27

    here is the change I made to the I2C routines Rx ().
    Addition enabling dell'ACKDT after the reading of the data:

    FUNCTION I2C_Rx() AS BYTE
    SSPCON2.RCEN=1
    W_MSSP()
    I2C_Rx=SSPBUF
    SET SSPCON2.ACKEN ON
    W_MSSP()
    END FUNCTION
    

    works well, but retrieves a byte at a time:

    FUNCTION READ_Slave_8BIT(ID_Address AS WORD,Comando AS BYTE,Address AS BYTE)#NR
    START()
    Tx_I2C(ID_Address)
    Tx_I2C(Comando)
    RESTART()
    Tx_I2C(ID_Address+1)
    SET SSPCON2.ACKDT ON
    EPWrite Address,I2C_Rx()
    STOP()
    END FUNCTION
    

    I created this routine:

    FUNCTION READ_Slave_16BIT(ID_Address AS WORD,Comando AS BYTE,Address AS BYTE)#NR
    START()
    Tx_I2C(ID_Address)
    Tx_I2C(Comando)
    RESTART()
    Tx_I2C(ID_Address+1)
    SET SSPCON2.ACKDT OFF
    EPWrite Address,I2C_Rx()
    SET SSPCON2.ACKDT ON
    EPWrite Address+1,I2C_Rx()
    STOP()
    END FUNCTION
    

    I read the first and the MSB in writing to the EEPROM address 0x00.
    the second does not stores it, but does not block the program.
    At this point I doubt if it's a management problem or a problem in the eeprom handling routines in the slave.

     
  • alejandro1957

    alejandro1957 - 2012-05-27

    Thanks for your suggestions.
    the problem was in the slave code of 16F88.
    so it works perfectly:

    FUNCTION I2C_Rx() AS BYTE
    SSPCON2.RCEN=1
    W_MSSP()
    I2C_Rx=SSPBUF
    SET SSPCON2.ACKEN ON
    W_MSSP()
    END FUNCTION
    
    FUNCTION READ_Slave_16BIT(ID_Address AS WORD,Comando AS BYTE) AS WORD
    DIM H_Byte,L_Byte AS BYTE
    START()
    Tx_I2C(ID_Address)
    Tx_I2C(Comando)
    RESTART()
    Tx_I2C(ID_Address+1)
    SET SSPCON2.ACKDT OFF
    H_Byte=I2C_Rx()
    SET SSPCON2.ACKDT ON
    L_Byte=I2C_Rx()
    STOP()
    READ_Slave_16BIT=L_Byte
    READ_Slave_16BIT_H=H_Byte
    END FUNCTION
    

    This is the interrupt slave that works (rustic, but it works):

    SUB I2C_Interrupt()#NR
    IF PIR1.SSPIF=1 THEN
       PIR1.SSPIF=0
       IF SSPSTAT.D_A=1 THEN
          IF SSPBUF>0xEF&SSPBUF<0xF5 THEN InByte=SSPBUF
          EPWrite SSPBUF,SSPBUF
          WAIT 20 ms
       END IF
       IF SSPSTAT.R_W=1 THEN
          DO
          LOOP UNTIL SSPSTAT.BF=0
          SSPCON.WCOL=0
          SELECT CASE InByte
                 CASE 0xF0
                 SSPBUF=Valor(Contador)
                 Contador+=1
                 IF Contador>=0x02 THEN Contador=0x00
                 CASE 0xF1
                 SSPBUF=Valor(Contador+1)
                 Contador+=1
                 IF Contador>=0x02 THEN Contador=0x00
                 CASE 0xF2
                 SSPBUF=Valor(Contador+2)
                 Contador+=1
                 IF Contador>=0x02 THEN Contador=0x00
                 CASE 0xF3
                 SSPBUF=Valor(Contador+3)
                 Contador+=1
                 IF Contador>=0x02 THEN Contador=0x00
                 CASE 0xF4
                 SSPBUF=Valor(Contador+4)
                 Contador+=1
                 IF Contador>=0x02 THEN Contador=0x00
                 CASE ELSE
                 SSPBUF=0x00
          END SELECT
       END IF
       Clear_Address=SSPBUF
       SSPCON.CKP=1
    END IF
    END SUB
    
     
  • alejandro1957

    alejandro1957 - 2012-05-27

    Now I have to see how to manage the information to be sent without being too in interrupt the I2C slave

    thanks again.

     
  • alejandro1957

    alejandro1957 - 2012-05-27

    + are always in love with GCBASIC :-)

     
  • Nobody/Anonymous

    Glad you got it going.  MSSP can be a tricky, it took me forever to find out that the slave clock stretching, SSPCON.CKP = 0 helps out a lot.  Instead of the 'wait 20 ms' in the interrupt routine, try nop:nop:nop:nop, I remember there is some sort of setup time required.

     
  • alejandro1957

    alejandro1957 - 2012-05-27
          EPWrite SSPBUF,SSPBUF
          WAIT 20 ms
    

    This will help to see if the master could write on a particular register of the slave.
    now no longer needed.
    This is the complete code of the slave
    it is best to use the nop.
    we say that the interrupts are somewhat sensitive to delay(WAIT)
    This is the complete code of the slave who will manage the sensors (temperature, Lighting, humidity, battery level and battery level system motors and sonar) of the robot

    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    'CHIP
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    #CHIP 16F88,4
    #CONFIG OSC=XT,MCLR_ON,CP_OFF,CCP1_RB3,DEBUG_OFF,WRT_PROTECT_OFF
    #CONFIG CPD_OFF,LVP_OFF,BODEN_ON,PWRTE_ON,WDT_OFF,IESO_OFF,FCMEN_OFF
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    'INTERRUPT
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    On Interrupt SSP1Ready call I2C_Interrupt
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    'VARIABLES
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    DIM InByte,Clear_Address,Contador AS BYTE
    DIM ADC_SyS(2),ADC_Aux(2),ADC_TEMP,ADC_Lm(2),ADC_Hm(2) AS WORD
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    'SUB AND FUNCTION
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    SUB I2C_Interrupt()#NR
    IF PIR1.SSPIF=1 THEN
       PIR1.SSPIF=0
       IF SSPSTAT.D_A=1 THEN
          IF SSPBUF>0xEF&SSPBUF<0xF4 THEN InByte=SSPBUF
       END IF
       IF SSPSTAT.R_W=1 THEN
          DO
          LOOP UNTIL SSPSTAT.BF=0
          SSPCON.WCOL=0
          SELECT CASE InByte
                 CASE 0xF0
                 SSPBUF=ADC_SyS(Contador)
                 Contador+=1
                 IF Contador>=0x02 THEN Contador=0x00
                 CASE 0xF1
                 SSPBUF=ADC_Aux(Contador)
                 Contador+=1
                 IF Contador>=0x02 THEN Contador=0x00
                 CASE 0xF2
                 SSPBUF=ADC_TEMP
                 CASE 0xF3
                 SSPBUF=ADC_Lm(Contador)
                 Contador+=1
                 IF Contador>=0x02 THEN Contador=0x00
                 CASE 0xF4
                 SSPBUF=ADC_Hm(Contador)
                 Contador+=1
                 IF Contador>=0x02 THEN Contador=0x00
                 CASE ELSE
                 SSPBUF=0x00
          END SELECT
       END IF
       Clear_Address=SSPBUF
       SSPCON.CKP=1
    END IF
    END SUB
    SUB SENSORES()#NR
    ADC_SyS(0)=ReadAD10(AN0)/256
    ADC_SyS(1)=ReadAD10(AN0)%256
    ADC_Aux(0)=ReadAD10(AN1)/256
    ADC_Aux(1)=ReadAD10(AN1)%256
    ADC_TEMP=((ReadAD10(AN2))/1024)*500
    ADC_Lm(0)=ReadAD10(AN3)/256
    ADC_Lm(1)=ReadAD10(AN3)%256
    ADC_Hm(0)=ReadAD10(AN4)/256
    ADC_Hm(1)=ReadAD10(AN4)%256
    END SUB
    INICIO:
       TRISA=b'011111'
       TRISB=b'00010010'
       PORTA=b'000000'          
       PORTB=b'00000000'    
       INTCON=b'11000000'
       SSPADD=0xA6
       SSPSTAT=b'00000000'
       SSPCON=b'00110110'
       PIE1.SSPIE=1
       CVRCON=b'00000000'       
       CMCON=b'00000111'        
       CCP1CON=b'00000000'
       ANSEL=b'00011111'
       ADCON0=b'00000001'
       ADCON1=b'10000000'
       Contador=0 
       InByte=0x00
       DO                       
         SENSORES()
         WAIT 200 ms              
       LOOP
    

    missing only handle digital compass that I am building.
    Thanks to all.
    and sorry for my English.

     
  • Nobody/Anonymous

    Good Job!!!  Very neat and clearly written.  Thanks for sharing.

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.