This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM335x I2C multi-master/slave mode

Other Parts Discussed in Thread: TMP275, TLV320AIC3106, AM3358, DM3730

Is there any application code / notes on how to use the am3558's i2c in multi-master mode / slave mode?

We're using QNX.  The product design is broadly based on the beaglebone black.

We have it working as a master - we just can't seem to get it to respond as a slave.

For the moment we are simply polling it.

  • Hi Neal,

    I am not familiar with QNX code, but you could take a reference from Linux SDK, specifically on am335x-evm.dts:
    i2c1_pins_default: pinmux_i2c1_pins {
          pinctrl-single,pins = <
              0x158 (PIN_INPUT_PULLUP | MUX_MODE2) /* spi0_d1.i2c1_sda */
              0x15c (PIN_INPUT_PULLUP | MUX_MODE2) /* spi0_cs0.i2c1_scl */
           >;
    };

    &i2c1 {
       pinctrl-names = "default", "sleep";
       pinctrl-0 = <&i2c1_pins_default>;
       pinctrl-1 = <&i2c1_pins_sleep>;

       status = "okay";
       clock-frequency = <100000>;

       lis331dlh: lis331dlh@18 {
                     compatible = "st,lis331dlh", "st,lis3lv02d";
                     reg = <0x18>;
                     Vdd-supply = <&lis3_reg>;
                     Vdd_IO-supply = <&lis3_reg>;

                     st,click-single-x;
                     st,click-single-y;
                     st,click-single-z;
                     st,click-thresh-x = <10>;
                     st,click-thresh-y = <10>;
                     st,click-thresh-z = <10>;
                     st,irq1-click;
                     st,irq2-click;
                     st,wakeup-x-lo;
                     st,wakeup-x-hi;
                     st,wakeup-y-lo;
                     st,wakeup-y-hi;
                     st,wakeup-z-lo;
                     st,wakeup-z-hi;
                     st,min-limit-x = <120>;
                     st,min-limit-y = <120>;
                     st,min-limit-z = <140>;
                     st,max-limit-x = <550>;
                     st,max-limit-y = <550>;
                     st,max-limit-z = <750>;

       };

       tsl2550: tsl2550@39 {
                    compatible = "taos,tsl2550";
                    reg = <0x39>;
       };

       tmp275: tmp275@48 {
                    compatible = "ti,tmp275";
                    reg = <0x48>;
       };

       tlv320aic3106: tlv320aic3106@1b {
                    compatible = "ti,tlv320aic3106";
                    reg = <0x1b>;
                    status = "okay";

                    /* Regulators */
                    AVDD-supply = <&vaux2_reg>;
                    IOVDD-supply = <&vaux2_reg>;
                    DRVDD-supply = <&vaux2_reg>;
                    DVDD-supply = <&vbat>;
       };
    };

    As you can see tlv320aic3106, tmp275, tsl2550, lis331dlh are connected to i2c. The linux driver that does the i2c configuration is drivers/i2c/busses/i2c-omap.c.

    Hope this helps.

    Best Regards,
    Yordan

  • HI Neal,

    Regarding I2C master/slave here are a couple of references that could help:

     ---For I2C master you can have a look at the below SW packages:

    a) RTOS based SYBIOS based SDK RTOS:
    software-dl.ti.com/.../index_FDS.html
    The SDK RTOS does support some I2C master example on the AM3358 Beaglebone black directly:
    processors.wiki.ti.com/.../Processor_SDK_RTOS_Release_Notes
    More info on the I2C driver can be found at:
    processors.wiki.ti.com/.../Processor_SDK_RTOS_I2C

    b) None RTOS based SW:
    The Starterware 2.x does provide some low level code.
    processors.wiki.ti.com/.../StarterWare
    For the Beaglebone there is an example to read/write the EEPROM.
    processors.wiki.ti.com/.../StarterWare_02.00.01.01_User_Guide
    It supports interrupt and DMA mode. See the init API sequence used at:
    processors.wiki.ti.com/.../StarterWare_HSI2C

    The code of the latest release can be found at:
    sourceforge.net/.../hsi2c.c



    --For I2C slave:
    A good starting point is to look at the AM335x TRM - SPRUH73 chap 21.

    The below wiki can help as well for the debugging. The I2C controller on the AM335x might not exactly match the block diagram but most of the explanation are generic:
    http://processors.wiki.ti.com/index.php?title=I2C_Tips
    It is worth to check the PLL settings used for the I2C module and compare it to what is used in the starterware 2.x examples.

    - We do not have specific drivers or examples available but I think that the master driver code above should setup the I2C controller in a state that would allow an other master to sent him it's own address.
    You could check the Starterware I2C example and build it to run it on your own board.

    - It might make sense to enable the interrupts or at least look at the interrupt flag (I2C_IRQSTATUS_RAW) to see what happened in the I2C access cycle (ie wheter the I2C controller was able to read it's own address sent by an other master on the bus). A good start is to check the AAS bit.
    The below E2E post (not on AM335x but on DM355) might help as well to debug further:
    http://e2e.ti.com/support/dsp/davinci_digital_media_processors/f/100/t/239965

    A.

  • Hi Neal,

    Can you please post some updates on where you stand in the debug?
    Can the other MASTER talk to other SLAVES (other than AM335x as SLAVE)?

    I am not that much knowledgeable about I2C but I think that some HW checks need to be done just to be sure:
    - Have some scope waveforms analysis been done in the case of the SLAVE transfer?
    - How does it compare with the MASTER transfer in term of timings and rising time?

    The PINMUX config might have an influence on the behavior as each pin has got some PU/PD and SLEWCTRL options that can be setup.
    The MASTER and SLAVE use case are different in the way that it is not the same device that is driving the bus. Also the behavior might depend on the value of the external pull up and on the AM335x internal PU/PD settings.
    The PINMUX options for I2C that we use on the BBB can be found at:
    git.ti.com/.../mux.c
    git.ti.com/.../mux_am33xx.h

    A.

  • Order of initialization of the I2C registers seems important for slave operation. Master operation is a lot more robust.

  • Neal,

    Thanks for the feedback.
    Did you follow section 21.3.15 of the TRM? Is the init sequence for SLAVE different to what is documented in this section?

    A.
  • Hello, the main problem appears to be a speed issue.  I now have 2 versions of the code, but I am giving a quick description of the version I am using to throttle the writes and reads, even though the older version seems to work better, it really does not work at all with no verbosity.  What is unknown is if I am looking for the proper bits in the Status RAW register and then whether the bits need to be turned off or on after the read/write operations.  Currently the slave send always send 5 bytes the 4 it expects to send and the a 5th pad (NULL) byte.  The send also send f hex 0x0FF quite often when the send should always be either 0x0000000C or 0x0000000e. Also, the slave reads seem to fail quite often..

    Following is a short narrative of what is currently being done.  I am not using interrupts at all and am only polling the Status RAW register:

    AM335x I2C rmi2c.docx

  • Hi Steven,

    Beside the I2C section of the Tech Ref Manual have you looked at the init sequence used in the I2C Starterware SW?
    http://processors.wiki.ti.com/index.php/StarterWare_HSI2C

    The I2C code of the starterware SW supports Master mode (TX/RX). Could you use a comparable init sequence as test?
    Try first to setup the controller as MASTER RX/TXto check if it works accordingly.

    The I2cAppIsr() ISR from i2c_app.c shows what interrupt register bitfields are checked and cleared.
    Also some function like I2CErrStatus() and I2CBusBusyStatus() seems to be checking the I2C_IRQSTATUS_RAW register.
    The i2c.h does as well seem to contains on the top some comments about the I2C controller init sequence.
    The different files used are located in:

    sdk\starterware\dal\i2c.c

    sdk\starterware\examples\i2c_app.c

    sdk\starterware\utils\i2c_utils.c

    sdk\starterware\include\i2c.h

    sdk\starterware\include\hw\hw_i2c.h
    http://software-dl.ti.com/dsps/dsps_public_sw/am_bu/starterware/latest/index_FDS.html

    A.

  • The link above sent me to a StarterWare 02_00_01_01 Product Download Page.  I selected the Windows installer and installed it using all defaults.  In the C:\ti directory all there is:

     Volume in drive C is OS
     Volume Serial Number is 926C-3901

     Directory of C:\ti

    19/05/2016  13:28    <DIR>          .
    19/05/2016  13:28    <DIR>          ..
    19/05/2016  13:29    <DIR>          AM335X_StarterWare_02_00_01_01
                   0 File(s)              0 bytes
                   3 Dir(s)  898,673,836,032 bytes free

    C:\ti>dir AM335X_StarterWare_02_00_01_01
     Volume in drive C is OS
     Volume Serial Number is 926C-3901

     Directory of C:\ti\AM335X_StarterWare_02_00_01_01

    19/05/2016  13:29    <DIR>          .
    19/05/2016  13:29    <DIR>          ..
    12/07/2013  07:31           205,167 AM335X_SoftwareManifest.pdf
    19/05/2016  13:28    <DIR>          binary
    19/05/2016  13:29    <DIR>          bootloader
    19/05/2016  13:29    <DIR>          build
    19/05/2016  13:29    <DIR>          docs
    19/05/2016  13:29    <DIR>          drivers
    19/05/2016  13:28    <DIR>          examples
    19/05/2016  13:29    <DIR>          grlib
    19/05/2016  13:29    <DIR>          host_apps
    19/05/2016  13:29    <DIR>          include
    19/05/2016  13:29    <DIR>          mmcsdlib
    19/05/2016  13:29    <DIR>          nandlib
    19/05/2016  13:29    <DIR>          platform
    19/05/2016  13:29    <DIR>          system_config
    19/05/2016  13:29    <DIR>          third_party
    19/05/2016  13:29    <DIR>          tools
    22/06/2016  11:02         1,512,867 uninstall.exe
    19/05/2016  13:29    <DIR>          usblib
    19/05/2016  13:29    <DIR>          utils
                   2 File(s)      1,718,034 bytes
                  19 Dir(s)  898,673,836,032 bytes free

    None of this shows a sdk folder.  In drivers there is a hsi2c.c program but no reference to what you have specified here.  I performed a search for I2cAppIsr and it does not exist in any C code: findstr /s /c:I2cAppIsr *.c* 

    Because of these issues I am quite lost!!

  • Sorry my mistake, I pointed you to a specifci version of the starterware that is included in the Industrial SDK SW, which seem to be different to the standalone starterware.

    The stand alone starterware can be downloaded from:
    http://processors.wiki.ti.com/index.php/StarterWare

    The one you downloaded is 2.00.01.01.
    For the version you have installed I think the code is located at:
    C:\ti\AM335X_StarterWare_02_00_01_01\drivers\hsi2c.c
    C:\ti\AM335X_StarterWare_02_00_01_01\platform\beaglebone\hsi2c.c
    C:\ti\AM335X_StarterWare_02_00_01_01\include\hsi2c.h
    C:\ti\AM335X_StarterWare_02_00_01_01\platform\beaglebone\hsi2c_eeprom\hsi2c_eeprom.c

    See SetupI2C() in hsi2c_eeprom.c for the high level init sequence.
    see I2CIsr() to see what bit fields are checked during the interrupt.
    The API used are defined in C:\ti\AM335X_StarterWare_02_00_01_01\drivers\hsi2c.c.

    Note as well that there is 2.xx.01.01 which is an open src one provided in sourceforge where everybody can contribute.
    The API should be very similar.


    A.

    A.

  • Hello AnBer,

    I have looked at that code and have actually tried some things similar to that.  The wait forever for the ARDY signal caused me a permanent hang situation.  I read it that "The CPU uses this flag to let it know the I2C registers are ready to be accessed again" and so I issues a while ( !ARDY) and the system just hanged.  This was after a data register read I believe (although it may have been a write).  Furthermore all your example are using Interrupts and I am polling the RAW register to handle flow control. 

    Please specify the flow control necessary when polling to correctly perform the tasks I identified in my word document that I provided.  If there would be some way we could communicate via telephone to speed this process up, that would be quite appreciated also. 

    Thank you.

    Steve

  • Hi Steve,

    A quick summary of what was discussed:

    - As far as I understood your specific I2C usage scenario is as follow:
         - Multimaster system with up to 17 devices (including an AM335x) than can all act as both MASTER and SLAVE.
            Polling mechanism is used for both MASTER and SLAVE
       - The typical bus usage follows the below pattern:
       One of the device as a specifc role (Gateway role) and will start to communicate to the 16 other device (including the AM335x) one by one:
           - Gateway does a Master READ to device 0 and device 0 reply with a SLAVE WRITE.
           - Gateway does a Master WRITE to device 0.
           - Then device 0 becomes MASTER too.
           - Gateway repeats this procedure to device 1, 2 ... til 15.

    - From a procedural point of view a good starting point is the "HS I2C Programming Flow Diagrams" section 17.5.1.3 of the DM3730 TRM - SPRUGN4R.
    The AM335x I2C controller is close enough to the DM3730 I2C controller that the Master/slave procedures (see Fig 17-29, Fig 17-3, Fig 17-31, Fig 17-32, Fig 17-35, Fig 17-36) should apply.
    Let's first check that your code is aligned with those procedure to handle the basic blocks (MASTER READ, MASTER WRITE, SLAVE WRITE,..etc).
    Then we can look at how the transitions (from SLAVE WRITE -> SLAVE READ -> MASTER) are done.

    A.

  • Hi

    Can we please arrange another concall urgently?

    Master behaviour is fine, but we are still struggling with the slave behaviour.

    We are monitoring the I2C bus with an I2C analyser and it is seeing correctly formed transmissions.  Have also checked with a scope and all looks correct on the bus.

    But the BB is not reliably telling us that a START and STOP bit has been seen by the AM3358.

    Things we have found:

    1. We are using polling
    2. Master transmit is fine
    3. We only ever read status from the I2C_IRQSTATUS_RAW
    4. We write (clear=1) to IRQ_STATUS (not the I2C_IRQSTATUS_RAW)
    5. We are happy that the device is being addressed correctly - again using an external analyser
    6. We successfully enter a slave transmit sequence and we see the expected data
    7. BUT we do not know how to terminate the transfer.  That is the BB is never being cleared to say its seen a stop.  The BF bit seems to do nothing
    8. We are using the AAS bit to indicate that we have been addressed as a slave
    9. We use the TRX bit to indicate whether its a slave receive / transmit
    10. We use XRDY+ARDY and RRDY+ARDY to indicate that a more data / data is available
    11. We have faked the reception of the stop bit (on a simple timeout), but this does not seem to work, which to me indicates that we are still missing some sort of configuration / register setting
    12. We are not clearing down the BB (BusBusy) bit - we are assuming this is managed by the logic.
    13. From what I've seen it seems to imply that the internal logic relies upon correct sequence / interaction

  • Neal,

    Could you please post the src code for I2C init and MASTER/SLAVE accesses?

    Thanks in advance,
    A.
  • It sounded like you were trying to solve issues related to slave operation. However, you seemed focus on sending the stop bit. That's something handled by the master. Can you please clarify? I suggest we focus on a single scenario such as slave transmitter.

  • wait.c
    //int first = 1;
    
    #include "proto.h"
    //#include "..\bsp-freescale-mx6q-sabrelite-src\src\hardware\startup\lib\public\arm\mx6x.h"
    
    void i2c_off(i2c_dev_t *dev)
    {
    //	out16(dev->regbase + I2C_CTRREG_OFF, in16(dev->regbase + I2C_CTRREG_OFF) & ~CTRREG_IEN);
    	out16(dev->regbase + I2C_CTRREG_OFF, 0);
    	out16(dev->regbase + AM335x_I2C_STAT, 0x07FFF);
    	if (uiVerbosity >= LOGGING_DEBUG_NORMAL)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG1, "%s:i2c_i2c_off: (CTRREG 0x%X STSREG 0x%X)",
    				pszProgram, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    }
    
    int	iMaster = 0;
    int iReset = 0;
    int	iSlave = 0;
    
    void i2c_reset(i2c_dev_t *dev)
    {
    	int 	timeout = 2000;
    //	int		iDoTwice =1;
    	int		status = in16(dev->regbase + I2C_STSREG_OFF);
    	int		ctrl = in16(dev->regbase + I2C_CTRREG_OFF);
    	if (uiVerbosity >= LOGGING_DEBUG_NORMAL)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG1, "%s:i2c_reset: entry (CTRREG 0x%X STSREG 0x%X)",
    				pszProgram, ctrl, status);
    
    	iMaster = 0;
    	iSlave = 0;
    	if ( ( ctrl & CTRREG_IEN ) && !( status & AM335x_I2C_RESET_ERROR ) && ( iReset++ < 100 ) )
    	{
    //		out16(dev->regbase + AM335x_I2C_CNT, 0);
    		out16( dev->regbase + AM335x_I2C_STAT, status & ( AM335x_I2C_ARDY | AM335x_I2C_NACK  | AM335x_I2C_AL | AM335x_I2C_BF ) );
        	nanospin_ns( 1000 );
    		int statusnew = in16(dev->regbase + I2C_STSREG_OFF);
    		if ( status != statusnew )
    		{
    			printf( "Clear Control 0x%X Status 0x%X to 0x%X\n", ctrl, status, statusnew  );
    			return;
    		}
    		if ( !( statusnew & AM335x_I2C_RESET_ERROR ) )
    		{
    			printf( "No Error Control 0x%X Status 0x%X so return\n", ctrl, statusnew  );
    			return;
    		}
    	}
    	iReset = 0;
    	printf( "Doing reset Control 0x%X Status 0x%X\n", ctrl, status );
    	// Disable interrupts
    //DoTwice:
    	out16(dev->regbase + AM335x_I2C_IE_CLR, 0x0FF); // clear interrupts
    	// Disable DMA
    	out16(dev->regbase + AM335x_I2C_BUF, 0);
    	// Disable test mode
    	out16(dev->regbase + AM335x_I2C_SYSTEST, 0);
    
    	if ( in16( dev->regbase + I2C_CTRREG_OFF) & CTRREG_IEN )
    		out16(dev->regbase + I2C_CTRREG_OFF, 0);
    	out16(dev->regbase + AM335x_I2C_STAT, 0x07FFF );  //in16(dev->regbase + I2C_STSREG_OFF) & AM335x_I2C_RESET );
    //	if ( first )
    	out16(dev->regbase + AM335x_I2C_SYSC, AM335x_I2C_SRST );
    	out16(dev->regbase + I2C_CTRREG_OFF, CTRREG_IEN );
        while ( !(in16(dev->regbase + AM335x_I2C_SYSS) & AM335x_I2C_SYSS_RDONE) && --timeout)
        {
        	nanospin_ns( 1000 );
        }
    	if(!timeout)
    	{
    		if (uiVerbosity >= LOGGING_ERRORS)
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_ERROR, "%s:i2c_reset: entry (CTRREG 0x%X STSREG 0x%X)",
    					pszProgram, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    		printf( "Timeout I2c from reset\n" );
    		exit(1);
    	}
    	out16(dev->regbase+AM335x_I2C_SYSC, AM335x_I2C_CLKACT_SYS | AM335x_I2C_IDLEMODE_SMART | AM335x_I2C_ENAWAKEUP | AM335x_I2C_AUTOIDLE ); //Smart idle mode, Fclock, Enable Wakeup, autoidle
    	/*
    	 * Enabling all wakup sources to stop I2C freezing on
    	 * WFI instruction.
    	 * REVISIT: Some wkup sources might not be needed.
    	 */
    	out16(dev->regbase + AM335x_I2C_WE, AM335x_I2C_WE_ALL );
    	out16(dev->regbase + I2C_CTRREG_OFF, 0 );
    
    	/* Set I2C bus speed */
    //	if ( first )
    	i2c_set_bus_speed( dev, dev->speed, NULL );
    
        /* Set Own Address */
    	out16(dev->regbase + I2C_ADRREG_OFF, dev->own_addr );
    	out16(dev->regbase + AM335x_I2C_SBLOCK, 0 );					// Tell it to only use OA0
    //	printf( "Enable I2c from reset\n" );
    /*
    	if ( first )
    	{
    		first = 0;
    		sleep( 30 );
    	}
    	if ( iDoTwice-- )
    		goto DoTwice;
    */
    	out16(dev->regbase + I2C_CTRREG_OFF, CTRREG_IEN );
    	dev->restart = 0;
    //	delay(10);
    	sleep(3);
    	if (uiVerbosity >= LOGGING_DEBUG_NORMAL)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG1, "%s:i2c_reset: exit (CTRREG 0x%X STSREG 0x%X)",
    				pszProgram, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    }
    
    int i2c_wait_bus_not_busy(i2c_dev_t *dev)
    {
        unsigned        tries = 1000000;
    	if (uiVerbosity >= LOGGING_DEBUG_FINE)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2, "%s:i2c_wait_bus_not_busy: entry (CTRREG 0x%X STSREG 0x%X)",
    				pszProgram, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    	if(dev->restart)
    	{
    		if (uiVerbosity >=  LOGGING_DEBUG_FINE)
    			slogf( _SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    					"%s:i2c_wait_bus_not_busy: dev->restart != 0 so return 0", pszProgram);
    		return 0;
    	}
    	while (in16(dev->regbase + I2C_STSREG_OFF) & STSREG_IBB)
    	{
    		if (tries-- == 0)
    		{
    			if (uiVerbosity >=  LOGGING_DEBUG_FINE)
    				slogf( _SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    						"%s:i2c_wait_bus_not_busy: wait bus idle failed (CTRREG 0x%X STSREG 0x%X)",
    						pszProgram, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    			/* reset the controller to see if it's able to recover*/
    			i2c_reset(dev);
    			//try again to see if it's OK now after reset
    			if(in16(dev->regbase + I2C_STSREG_OFF) & STSREG_IBB)
    			{
    //				delay(1);
    				if (uiVerbosity >=  LOGGING_DEBUG_FINE)
    					slogf( _SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    							"%s:i2c_wait_bus_not_busy: STSREG_IBB still set, return -1 (CTRREG 0x%X STSREG 0x%X)",
    							pszProgram, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    				return -1;
    			}
    			break;
    		}
    	}
    	if (uiVerbosity >= LOGGING_DEBUG_FINE)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2, "%s:i2c_wait_bus_not_busy: return 0 (CTRREG 0x%X STSREG 0x%X)",
    				pszProgram, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    	return 0;
    }
    
    #include <sys/time.h>
    #include <time.h>
    
    const char	szWrite[] = "write";
    const char	szRead[] = "read";
    
    uint32_t i2c_slave_wait_forever(i2c_dev_t *dev, int interrupt)
    {
    	int	status, ctrl;
    	int			iid, interr = EOK;
     //   int statusold = 0;
        char *	pszMode;
    
        if ( iSlave == interrupt )
        {
        	iSlave = 0;
        	out16(dev->regbase + I2C_CTRREG_OFF, CTRREG_IEN );
        }
        switch( interrupt )
        {
        case AM335x_I2C_XRDY:
        	iid = dev->slave_write_iid;
        	pszMode = szWrite;
        	break;
        case AM335x_I2C_RRDY:
        	iid = dev->slave_read_iid;
        	pszMode = szRead;
        	break;
        default:
        	return I2C_STATUS_ERROR;
    	}
    	printf( "%s Status = 0x%X\n", pszMode, in16(dev->regbase + I2C_STSREG_OFF) );
    	/* Wait forever until we get an interrupt */
    	if (uiVerbosity >= LOGGING_DEBUG_FINE)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2, "%s:i2c_slave_wait_forever: %s entry iid %d (CTRREG 0x%X STSREG 0x%X)",
    				pszProgram, pszMode, iid, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    	/*Wait for an interrupt event */
    Retry:
    	while ( iSlave || !( ( status = in16(dev->regbase + I2C_STSREG_OFF)) & STSREG_IAAS) ||
    			!( ( ctrl  = in16(dev->regbase + I2C_CTRREG_OFF) ) & CTRREG_IEN) || iMaster ||
    			(ctrl & CTRREG_MSTA ) || !( status & interrupt ) )
    	{
    		struct timespec request;
    		request.tv_sec  = 0;
    		request.tv_nsec = 2000; // 2 microseconds (although it is always at least 3 milliseconds)
    		clock_nanosleep(CLOCK_MONOTONIC , 0, &request, NULL );
    /*
    		usleep(2);
    		interr = InterruptWait_r(0, NULL);
    		if (uiVerbosity >=  LOGGING_DEBUG_FINE)
    			slogf( _SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    					"%s:i2c_slave_wait_forever:InterruptWait_r: 0x%X %s", pszProgram, interr, strerror(interr));
    */
    		ctrl = in16(dev->regbase + I2C_CTRREG_OFF );
    		if ( iMaster || (ctrl & CTRREG_MSTA ) )
    		{
    			interr = EOK;
    			if (uiVerbosity >=  LOGGING_DEBUG_FINE)
    				slogf( _SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    						"%s:i2c_slave_wait_forever: %s Interrupt for master so retry", pszProgram, pszMode);
    			continue;
    		}
    		if ( !( ctrl & CTRREG_IEN) )
    			continue;
    		if ( !iMaster && !iSlave && ( status & AM335x_I2C_ERROR) )
    		{
    			if (uiVerbosity >= LOGGING_ERRORS)
    				slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_WARNING, "%s:i2c_slave_wait_forever: error return 0x%X", pszProgram, status);
    			i2c_reset( dev );
    			continue;
    		}
    /*
    		if ( statusold != status )
    		{
    			printf( "%s INTSET = 0x%X INTCLR = 0x%X Control = 0x%X Status = 0x%X\n", pszMode, in16(dev->regbase + AM335x_I2C_IE_SET), in16(dev->regbase + AM335x_I2C_IE_CLR), ctrl, statusold = status );
    			if ( ( status & AM335x_I2C_BB ) && !( ctrl & ( AM335x_MST | AM335x_TRX ) ) )
    			{
    				ctrl = in16(dev->regbase + AM335x_I2C_DATA ) & 0x0FF;
    				printf( "%s Just read 0x%X\n", pszMode, ctrl );
    				if ( !( in16( dev->regbase + AM335x_I2C_SBLOCK ) & AM335x_OAE0 ) )
    				{
    					printf( "%s OAE0 bit not set so setting\n", pszMode );
    //	       			out16(dev->regbase + AM335x_I2C_SBLOCK, 0 );			// Tell it to only use OA0
    	       			out16(dev->regbase + AM335x_I2C_SBLOCK, AM335x_OAE0 );			// Tell it to only use OA0
    	       		}
    	       	}
    		}
    */
    	}
    	/* Clear the interrupt */
    	/* If an interrupt is pending */
    //	InterruptUnmask(dev->intr, iid);
    //ss		out16(dev->regbase + I2C_STSREG_OFF, in16(dev->regbase + I2C_STSREG_OFF) & AM335x_I2C_INT_MASK );
    //		out16(dev->regbase + I2C_STSREG_OFF, in16(dev->regbase + I2C_STSREG_OFF) & AM335x_I2C_RESET ) ; //AM335x_I2C_INT_MASK );
    	//	out16(dev->regbase + I2C_STSREG_OFF, in16(dev->regbase + I2C_STSREG_OFF) & ~(STSREG_IIF));
    	if ( iSlave )
    		goto Retry;
    	iSlave = interrupt;
    	if (uiVerbosity >= LOGGING_DEBUG_FINE)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2, "%s:i2c_slave_wait_forever: %s return 0 (CTRREG 0x%X STSREG 0x%X)",
    				pszProgram, pszMode, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    	return 0;
    }
    
    

    slave_send.c
    #include "proto.h"
    
    extern int iMaster;
    
    i2c_status_t i2c_slave_send(i2c_dev_t *dev)
    {
    	int status, timeout;
    	if ( uiVerbosity >= LOGGING_DEBUG_FINE )
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2, "%s:i2c_slave_send: entry", pszProgram);
    	char *buf = dev->slave.data;
    	int len = dev->slave.len;
    	/* At this point we have been addressed as a slave
    	 * and we replied with an ack
    	 * now we start to send data
    	 */
    
    //	out16(dev->regbase + I2C_CTRREG_OFF, AM335x_I2C_EN | AM335x_TRX );  // Mark as Slave Transmitter
    	printf( "Set Control register 0x%x\n", in16(dev->regbase + I2C_CTRREG_OFF) );
    	/* Send the rest of the data */
    //	out16(dev->regbase + AM335x_I2C_SBLOCK, 0 );					// Tell it to only use OA0
    	int iCount = 1;
    	while (len > 0)
    	{
    		timeout = 2000;
    		while ( --timeout && ( ( status = in16(dev->regbase + I2C_STSREG_OFF) ) & AM335x_I2C_SLV_XMT ) != AM335x_I2C_SLV_XMT && !( status & ( AM335x_I2C_ERROR ) ) ); //| AM335x_I2C_ARDY	) ) );
    		if ( !timeout )
    		{
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_ERROR, "%s:i2c_slave_send: timeout XMT status 0x%X, so reset", pszProgram, status );
    			i2c_reset(dev);
    			return -1;
    		}
    		if ( iMaster )
    			return -1;
    		if (status & AM335x_I2C_ERROR)
    		{
    			if (uiVerbosity >= LOGGING_ERRORS)
    				slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_WARNING, "%s:i2c_slave_send: error return 0x%X", pszProgram, status);
    			i2c_reset(dev);
    			return status;
    		}
    		if ((status & ( AM335x_I2C_SLV_XMT ) ) == AM335x_I2C_SLV_XMT)
    		{
    			out16(dev->regbase + I2C_DATREG_OFF, (*(char *)buf) & 0x0FF);
    			out16(dev->regbase + AM335x_I2C_STAT, AM335x_I2C_XRDY );
    			if ( uiVerbosity >= LOGGING_PROGRESS )
    				slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_INFO, "%s:i2c_slave_send: Byte %d is 0x%02X '%s', status 0x%X",
    						pszProgram, iCount, *((unsigned char *)buf), fnlibCharToString( *((char *)buf) ), status);
    //		    printf( "Slave write Byte %d is 0x%02X, status 0x%X\n", iCount, *((unsigned char *)buf), status );
    			++buf; --len, iCount++;
    		}
    /*
    		if ( status & AM335x_I2C_ARDY )
    		{
    			if (uiVerbosity >= LOGGING_ERRORS)
    				slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_WARNING, "%s:i2c_slave_send: ARDY found before complete return 0x%X", pszProgram, status);
    			out16(dev->regbase + AM335x_I2C_STAT, AM335x_I2C_ARDY );
    			return status;
    		}
    */
    	}
    	timeout = 2000;
    	while ( !( in16(dev->regbase + I2C_STSREG_OFF) & AM335x_I2C_ARDY ) && --timeout );
    	if ( timeout )
    	{
    //		printf( "Slave write wrote %d bytes, status 0x%X\n", dev->slave.len, in16(dev->regbase + I2C_STSREG_OFF) );
    		return 0;
    	}
    
    	while( !( ( status = in16(dev->regbase + I2C_STSREG_OFF) ) & ( AM335x_I2C_ARDY ) ) && !iMaster && ( status & AM335x_I2C_BB ) ) // | AM335x_I2C_BF ) ) )
    	{
    		if (status & AM335x_I2C_ERROR)
    		{
    			if (uiVerbosity >= LOGGING_ERRORS)
    				slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_WARNING, "%s:i2c_slave_send: error return 0x%X", pszProgram, status);
    			i2c_reset(dev);
    			return status;
    		}
    		if ((status & ( AM335x_I2C_SLV_XMT ) ) == AM335x_I2C_SLV_XMT)
    		{
    			len++;
    			out16(dev->regbase + I2C_DATREG_OFF, 0x00 );
    			out16(dev->regbase + AM335x_I2C_STAT, AM335x_I2C_XRDY ); // | AM335x_I2C_XUDF );
    			if ( uiVerbosity >= LOGGING_DEBUG_FINE )
    				slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    						"%s:i2c_slave_send: pad length %d, status 0x%X", pszProgram, len, status);
    //			printf( "Pad %d, count %d, status 0x%X\n", len, iCount, status );
    			iCount++;
    		}
    	}
    	return status;
    }
    

    slave_recv.c
    char szLibNULL[] = "";
    char szLibCHAR[8];
    #include "proto.h"
    
    char *fnlibCharToString( char c )
    {
    	if ( !isprint(c) )
    		return szLibNULL;
    	szLibCHAR[0] = c, szLibCHAR[1] = 0;
    	return szLibCHAR;
    }
    
    extern int iMaster, iReset;
    
    int i2c_slave_recv(i2c_dev_t *dev, char *buf, int len, int stop)
    {
    	int iLen = len, iCount = 0;
    	int status, timeout;
    
    //	printf( "Slave receive\n" );
    //	out16(dev->regbase + AM335x_I2C_SBLOCK, AM335x_OAE0 );			// Tell it to only use OA0
    	while ( iLen )
    	{
    //	    out16(dev->regbase + AM335x_I2C_CNT, 1);
    //		printf( "Slave Read 1 Control 0x%X Status 0x%X\n", in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF) );
    		timeout = 3000;
    		while ( --timeout && ( ( ( status = in16(dev->regbase + I2C_STSREG_OFF) ) & AM335x_I2C_SLV_RCV ) != AM335x_I2C_SLV_RCV &&
    				!( status & ( AM335x_I2C_ERROR | AM335x_I2C_ARDY ) ) ) );
    		if ( !timeout )
    		{
    //			if ( status == AM335x_I2C_AAS )
    			{
    				printf("Fake successful read of %d bytes\n", iCount );
    				return iCount;
    			}
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_ERROR, "%s:i2c_slave_receive: timeout RCV status 0x%X, so reset", pszProgram, status );
    			printf( "Slave Read 2 Timeout Control 0x%X Status 0x%X\n", in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF) );
    			iReset = 100;
    			i2c_reset(dev);
    			return -1;
    		}
    		if ( iMaster )
    			return -1;
    		// Any other errors reported???
    		if (status & AM335x_I2C_ERROR)
    		{
    			if ( uiVerbosity >= LOGGING_DEBUG_FINE )
    				slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_WARNING,
    						"%s:i2c_slave_recv: Error reported status 0x%X return EIO (CTRREG 0x%X STSREG 0x%X)",
    						pszProgram, status, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    			printf( "Slave Read fail status 0x%X\n", status );
    			errno =  EIO;
    			i2c_reset(dev);
    			return -2;
    		}
    		if ( ( status & ( AM335x_I2C_ARDY ) )  )	// || !(status & AM335x_I2C_BB ) )
    		{
    			printf( "Slave Read Stop found after reading %d bytes status 0x%X\n", iCount, status );
    			if ( uiVerbosity >= LOGGING_DEBUG_FINE )
    				slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    						"%s:i2c_slave_recv: Stop received, return %d bytes", pszProgram, iCount);
    //			out16( dev->regbase + AM335x_I2C_STAT, AM335x_I2C_ARDY | AM335x_I2C_BF );
    //			if ( in16( dev->regbase + AM335x_I2C_CNT ) )
    //				out16(dev->regbase + AM335x_I2C_CNT, 0);
    			return iCount;
    		}
    		// read byte
    		char cByte = buf[iCount++] = in16(dev->regbase + I2C_DATREG_OFF) & 0xFF;
    		out16(dev->regbase + AM335x_I2C_STAT, status & ( AM335x_I2C_RRDY | AM335x_I2C_BF ) ); // | AM335x_I2C_ROVR );
    		iLen--;
    		if ( uiVerbosity >= LOGGING_PROGRESS )
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_INFO,
    					"%s:i2c_slave_recv: Byte %d is 0x%02X '%s', (CTRREG 0x%X STSREG 0x%X)", pszProgram, iCount, (unsigned char)cByte,
    					fnlibCharToString( cByte ), in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    		printf( "\In Byte %d is 0x%02X statraw 0x%X status 0x%X...\n", iCount, cByte & 0x0FF, status, in16(dev->regbase + AM335x_I2C_STAT) );
    		/*wait for interrupt */
    //		status = i2c_slave_wait_status(dev);
    //		out16(dev->regbase + AM335x_I2C_SBLOCK, 0 );					// Tell it to only use OA0
    //		delay(1);
    //		out16(dev->regbase + AM335x_I2C_SBLOCK, AM335x_OAE0 );			// Tell it to only use OA0
    	}
    	if (uiVerbosity >=  LOGGING_ERRORS)
    		slogf( _SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_ERROR,
    				"%s:i2c_slave_recv: %d buffer overrun return -1 errno EMSGSIZE", pszProgram, len);
    	i2c_reset(dev);
    	errno = EMSGSIZE;
    //	out16(dev->regbase + AM335x_I2C_SBLOCK, 0 );			// Tell it to only use OA0
    	return -10;
    }
    
    

    slave.c
    #include "proto.h"
    
    int i2c_attach_slave_read_interrupt(i2c_dev_t *dev)
    {
    	if (-1 == ThreadCtl(_NTO_TCTL_IO, 0))
    	{
    		if ( uiVerbosity )
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_ERROR, "%s:i2c_attach_slave_interrupt:ThreadCtl: %s.", pszProgram, strerror(errno) );
    		return NULL;
    	}
    
    	/* Initialize interrupt handler */
    	SIGEV_INTR_INIT(&dev->slave_read_intrevent);
    
    	/*InterruptAttachEvent() tells the kernel that the event (intrevent) should be
    	 returned whenever the interrupt (intr) is detected, and that the interrupt level should be
    	 masked off. */
    	dev->slave_read_iid = InterruptAttachEvent(dev->intr, &dev->slave_read_intrevent, _NTO_INTR_FLAGS_TRK_MSK);
    	if (dev->slave_read_iid == -1)
    	{
    		if ( uiVerbosity )
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_ERROR, "%s:i2c_attach_slave_read_interrupt:InterruptAttachEvent: %s.", pszProgram, strerror(errno) );
    		return -1;
    	}
    	/* enable interrupts */
    //	out16(dev->regbase + I2C_CTRREG_OFF, in16(dev->regbase + I2C_CTRREG_OFF) | CTRREG_IEN | CTRREG_IIEN );
    	if (uiVerbosity >= LOGGING_PROGRESS)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_RESMGR, _SLOG_INFO, "%s:i2c_attach_slave_read_interrupt: Successful", pszProgram);
    	return 0;
    }
    
    int i2c_deattach_slave_read_interrupt(i2c_dev_t *dev)
    {
    	int r;
    
    	if (-1 == ThreadCtl(_NTO_TCTL_IO, 0))
    	{
    		if ( uiVerbosity )
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_ERROR, "%s:i2c_deattach_slave_read_interrupt:ThreadCtl: %s.", pszProgram, strerror(errno) );
    		return NULL;
    	}
    	r = InterruptDetach(dev->slave_read_iid);
    	if (r == -1)
    	{
    		if ( uiVerbosity )
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_WARNING, "%s:i2c_deattach_slave_read_interrupt:InterruptDetach: %s.",
    					pszProgram, strerror(errno) );
    	}
    	else if (uiVerbosity >= LOGGING_PROGRESS)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_RESMGR, _SLOG_INFO, "%s:i2c_deattach_slave_read_interrupt: Successful", pszProgram);
    	return 0;
    }
    
    int i2c_attach_slave_write_interrupt(i2c_dev_t *dev)
    {
    	if (-1 == ThreadCtl(_NTO_TCTL_IO, 0))
    	{
    		if ( uiVerbosity )
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_ERROR, "%s:i2c_attach_slave_write_interrupt:ThreadCtl: %s.",
    					pszProgram, strerror(errno) );
    		return NULL;
    	}
    
    	// Initialize interrupt handler
    	SIGEV_INTR_INIT(&dev->slave_write_intrevent);
    
    	// InterruptAttachEvent() tells the kernel that the event (intrevent) should be
    	// returned whenever the interrupt (intr) is detected, and that the interrupt level should be
    	// masked off.
    	dev->slave_write_iid = InterruptAttachEvent(dev->intr, &dev->slave_write_intrevent, _NTO_INTR_FLAGS_TRK_MSK);
    	if (dev->slave_write_iid == -1)
    	{
    		if ( uiVerbosity )
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_ERROR, "%s:i2c_attach_slave_write_interrupt:InterruptAttachEvent: %s.",
    					pszProgram, strerror(errno) );
    		return -1;
    	}
    
    	// enable interrupts
    //	out16(dev->regbase + I2C_CTRREG_OFF, in16(dev->regbase + I2C_CTRREG_OFF) | CTRREG_IEN | CTRREG_IIEN );
    	if (uiVerbosity >= LOGGING_PROGRESS)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_RESMGR, _SLOG_INFO, "%s:i2c_attach_slave_write_interrupt: Successful", pszProgram);
    	return 0;
    }
    
    int i2c_deattach_slave_write_interrupt(i2c_dev_t *dev)
    {
    	int r;
    
    	if (-1 == ThreadCtl(_NTO_TCTL_IO, 0))
    	{
    		if ( uiVerbosity )
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_ERROR, "%s:i2c_deattach_slave_write_interruptt:ThreadCtl: %s.",
    					pszProgram, strerror(errno) );
    		return NULL;
    	}
    	r = InterruptDetach(dev->slave_write_iid);
    	if (r == -1)
    	{
    		if ( uiVerbosity )
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_WARNING, "%s:i2c_deattach_slave_write_interrupt:InterruptDetach: %s.",
    					pszProgram, strerror(errno) );
    	}
    	else if (uiVerbosity >= LOGGING_PROGRESS)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_RESMGR, _SLOG_INFO, "%s:i2c_deattach_slave_write_interrupt: Successful", pszProgram);
    	return 0;
    }
    
    /* We could add locks if needed */
    char szlibHex[] = "0123456789ABCDEF";
    
    void fnlibConvertFromHex( char* pszText, char* pszHex, int iLength )
    {
    	char *pszPtr1;
    	char *pszPtr2;
    
    	pszPtr1 = pszText;
    	pszPtr2 = pszHex;
    //	*pszPtr1++ = '0';
    //	*pszPtr1++ = 'x';
    	while ( iLength-- )
    	{
    		int i1 = *pszPtr2++;
    		*pszPtr1++ = szlibHex[ ( i1 & 0xF0 ) >> 4 ];
    		*pszPtr1++ = szlibHex[ i1 & 0x0F ];
    	}
    	*pszPtr1 = 0;
    }
    
    int fnlibDisplayData( char psz3Lines[][80], int iLinesSize, char** pcData, int* piLen )
    {
    	int i1, i2;
    	char szHex[256];
    	i2 = *piLen;
    	if ( iLinesSize < 80*3 )
    		return 0;
    	if ( ( i1 = *piLen ) )
    	{
    		if ( i1 > 64 )
    			i1 = 64;
    		fnlibConvertFromHex( szHex, *pcData, i1 );
    		char *pszHex = szHex;
    		char *pszLine1 = psz3Lines[0];
    		char *pszLine2 = psz3Lines[1];
    		char *pszLine3 = psz3Lines[2];
    		for ( i2 = 0; i2 < i1; )
    		{
    			*pszLine1++ = ( isprint( **pcData ) ? **pcData : ' ' );
    			(*pcData)++;
    			*pszLine2++ = *pszHex++;
    			*pszLine3++ = *pszHex++;
    			if ( i2++ && (i2 < i1) && ( (i2 % 4 ) == 0 ) )
    				*pszLine1++ = *pszLine2++ = *pszLine3++ = ' ';
    		}
    		*pszLine1++ = *pszLine2++ = *pszLine3++ = '\0';
    		*piLen -= i1;
    	}
    	return ( i1 );
    }
    
    i2c_status_t i2c_set_callback(i2c_dev_t *dev, void *buf, unsigned int len)
    {
    	memcpy(dev->slave.data, buf, len);
    	dev->slave.len = len;
    	if (uiVerbosity >= LOGGING_PROGRESS)
    	{
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_INFO,
    				"%s:i2c_set_callback: Slave transmit length %d bytes:", pszProgram, len );
    		char sz3Lines[3][80];
    		int i = len;
    		char *pch = buf;
    		while( fnlibDisplayData( &sz3Lines[0], sizeof(sz3Lines), &pch, &i ) )
    		{
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_INFO, "%s:i2c_set_callback: %s", pszProgram, sz3Lines[0] );
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_INFO, "%s:i2c_set_callback: %s", pszProgram, sz3Lines[1] );
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_INFO, "%s:i2c_set_callback: %s", pszProgram, sz3Lines[2] );
    		}
    	}
    	return 0;
    }
    
    i2c_status_t i2c_slave_read(i2c_dev_t *dev, void *buf, unsigned int len,
    		unsigned int stop)
    {
    	i2c_status_t status; //needs to come from an interrupt
    	i2c_status_t ret;
    	int t;
    
    	if (uiVerbosity >= LOGGING_DEBUG_FINE)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    				"%s:i2c_slave_read: entry", pszProgram);
    	if (len <= 0)
    	{
    		if (uiVerbosity >= LOGGING_DEBUG_FINE)
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    					"%s:i2c_slave_read: length passed as %d so return 0",
    					pszProgram, len);
    		return 0;
    	}
    	t = i2c_attach_slave_read_interrupt(dev);
    	if (t == -1)
    	{
    		if (uiVerbosity >= LOGGING_ERRORS)
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_ERROR,
    					"%s:i2c_slave_read:i2c_attach_slave_read_interrupt failure",
    					pszProgram);
    		return (t);
    	}
    	/* Wait for an interrupt */
    //start:
    	status = i2c_slave_wait_forever(dev, AM335x_I2C_RRDY);	// Signal a slave read wait forever
    
    	/*  If we are Addressed as a slave we keep control until we have left the i2c_slave function,
    	 *  lock is then released outside of this.
    	 *
    	 *  If we are addresses as a slave after we have started a Master Write or Master Read
    	 *  and have not fully completed the  Master Write  / Master Read action (this means that the Master has not released
    	 *  the control lock and this could block here) . Hence we "try" the lock and if we can't lock it we just ignore this slave request
    	 *  and go back to waiting for another one, while the Master Write finishes and releases the lock.
    	 *
    	 *  This should be very unlikely to happen since the only reason the modules does a Master Write is in response to a previous
    	 *  Master Read by the GW . The GW would need to do a Master Write to the Module, and then do a Master Read (Polling), while the Module
    	 *  was attempting to complete it's Master Write  */
    	/*
    	t = pthread_mutex_trylock(&dev->control_lock);
    	if (t == EBUSY)
    	{
    		if ( uiVerbosity >= LOGGING_DEBUG_FINE )
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    				"%s:i2c_slave_read:pthread_mutex_trylock: mutex already locked, ignore this slave request wait for another so retry", pszProgram);
    		goto start;
    	}
    	else if ( uiVerbosity >= LOGGING_DEBUG_FINE )
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    			"%s:i2c_slave_read:pthread_mutex_trylock: status 0x%X", pszProgram, t);
    	 */
    
    	t = i2c_deattach_slave_read_interrupt((void *) dev);
    	if (t == -1)
    	{
    		if (uiVerbosity >= LOGGING_ERRORS)
    			slogf(_SLOGC_SNELL_IQMIT_I2C_RESMGR, _SLOG_ERROR,
    					"%s:i2c_slave_read:i2c_deattach_slave_read_interrupt failure", pszProgram);
    		return(t);
    	}
    	if ( status )
    	{
    		if (uiVerbosity >= LOGGING_DEBUG_FINE)
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    					"%s:i2c_slave_read:i2c_slave_wait_forever: error status 0x%X return -1", pszProgram, status);
    
    		return (-1);
    	}
    	// Slave Rx/ Read mode as Master Writing -eg Master Tx
    	if (uiVerbosity >= LOGGING_DEBUG_FINE)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    				"%s:i2c_slave_read:  Starting receive (CTRREG 0x%X STSREG 0x%X)", pszProgram, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    /*
    	//A dummy read of I2C_I2DR in Slave Receive mode releases SCL, allowing the master to send data
    	int c = in16(dev->regbase + I2C_DATREG_OFF) & 0x0FF;
    	printf( "%X %c\n", c, c );
    */
    	// Move to waiting for the data cycle now
    	ret = i2c_slave_recv(dev, buf, len, stop);
    //	out16(dev->regbase + AM335x_I2C_SBLOCK, 0 );					// Tell it to only use OA0
    	out16( dev->regbase + AM335x_I2C_STAT, in16( dev->regbase + I2C_STSREG_OFF ) & ( AM335x_I2C_RRDY | AM335x_I2C_ROVR | AM335x_I2C_ARDY | AM335x_I2C_NACK  | AM335x_I2C_AL | AM335x_I2C_BF ) );
    	status = errno;
    	//return from the Slave read
    	if (uiVerbosity >= LOGGING_DEBUG_FINE)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    				"%s:i2c_slave:i2c_slave_recv: return 0x%X %s", pszProgram,
    				ret, ret > 0 ? "" : strerror(t));
    	// Unlock the control now that the slave function has returned
    	/*
    	t = pthread_mutex_unlock(&dev->control_lock);
    	if (t != 0)
    	{
    		if (uiVerbosity >= LOGGING_ERRORS)
    			slogf(_SLOGC_SNELL_IQMIT_I2C_RESMGR, _SLOG_ERROR,
    				"%s:io_read:pthread_mutex_unlock failure", pszProgram);
    		return(-1);
    	}
    	 */
    	errno = status;
    //	i2c_reset(dev);
    	return ret;
    }
    
    void i2c_slave_write(i2c_dev_t *dev)
    {
    	i2c_status_t status; //needs to come from an interrupt
    	int t;
    
    	if (uiVerbosity >= LOGGING_DEBUG_FINE)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    				"%s:i2c_slave_write: entry", pszProgram);
    	t = i2c_attach_slave_write_interrupt(dev);
    	if (t == -1)
    	{
    		if (uiVerbosity >= LOGGING_ERRORS)
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_ERROR,
    					"%s:i2c_slave_write:i2c_attach_slave_write_interrupt failure",
    					pszProgram);
    		exit (t);
    	}
    	/* Wait for an interrupt */
    start:
    	status = i2c_slave_wait_forever(dev, AM335x_I2C_XRDY);	// Signal a slave write wait forever
    
    	/*  If we are Addressed as a slave we keep control until we have left the i2c_slave function,
    	 *  lock is then released outside of this.
    	 *
    	 *  If we are addresses as a slave after we have started a Master Write or Master Read
    	 *  and have not fully completed the  Master Write  / Master Read action (this means that the Master has not released
    	 *  the control lock and this could block here) . Hence we "try" the lock and if we can't lock it we just ignore this slave request
    	 *  and go back to waiting for another one, while the Master Write finishes and releases the lock.
    	 *
    	 *  This should be very unlikely to happen since the only reason the modules does a Master Write is in response to a previous
    	 *  Master Read by the GW . The GW would need to do a Master Write to the Module, and then do a Master Read (Polling), while the Module
    	 *  was attempting to complete it's Master Write  */
    /*
    	t = pthread_mutex_trylock(&dev->control_lock);
    	if (t == EBUSY)
    	{
    		if ( uiVerbosity >= LOGGING_DEBUG_FINE )
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    					"%s:i2c_slave_write:pthread_mutex_trylock: mutex already locked, ignore this slave request wait for another so retry", pszProgram);
    		goto start;
    	}
    	else if ( uiVerbosity >= LOGGING_DEBUG_FINE )
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    				"%s:i2c_slave_write:pthread_mutex_trylock: status 0x%X", pszProgram, t);
    */
    	if (uiVerbosity >= LOGGING_DEBUG_FINE)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    				"%s:i2c_slave_write:i2c_slave_wait_forever: status 0x%X", pszProgram, status);
    	if (status)
    		goto start;
    	// Slave Tx/ Write mode as Master Reading eg Master Rx
    	if ( uiVerbosity >= LOGGING_DEBUG_FINE )
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    				"%s:i2c_slave_write: Slave Write", pszProgram);
    /*sws
    	// Make sure I2C Module on and Interrupts CTRREG_IIEN on
    	out16(dev->regbase + I2C_CTRREG_OFF, CTRREG_IEN | CTRREG_IIEN);
    	// Slave mode
    	out16(dev->regbase + I2C_CTRREG_OFF, in16(dev->regbase + I2C_CTRREG_OFF) & (~CTRREG_MSTA));
    	//Set Tx Mode based on SRW when STSREG_IAAS is set only (eg when addresses)  - here we are a  Transmitter CTRREG_MTX
    	out16(dev->regbase + I2C_CTRREG_OFF, in16(dev->regbase + I2C_CTRREG_OFF) | CTRREG_MTX);
    	// Send Acknowledgement ~CTRREG_TXAK
    	out16(dev->regbase + I2C_CTRREG_OFF, in16(dev->regbase + I2C_CTRREG_OFF) & (~CTRREG_TXAK));
    	//Repeat Start =0 N/A here
    	out16(dev->regbase + I2C_CTRREG_OFF, in16(dev->regbase + I2C_CTRREG_OFF) & (~CTRREG_RSTA));
    */
    
    	// Slave Tx bytes
    	i2c_slave_send(dev);
    	status = in16( dev->regbase + I2C_STSREG_OFF );
    //	printf( "Slave Write done status 0x%X\n", status );
    	out16( dev->regbase + AM335x_I2C_STAT,  status & ( AM335x_I2C_XRDY | AM335x_I2C_XUDF | AM335x_I2C_ARDY | AM335x_I2C_NACK  | AM335x_I2C_AL | AM335x_I2C_BF ) );
    
    	/* After the Slave Write, we don't want to return from io_read , we only do this after a Slave Read
    	 * hence we return to waiting for another interrupt.
    	 * Additionally we have to unlock control here instead of in the io_read function, now that the slave has finished
    	 * and we don't leave i2c_slave
    	 */
    /*
    	t = pthread_mutex_unlock(&dev->control_lock);
    	if (t != 0)
    	{
    		if ( uiVerbosity >= LOGGING_ERRORS )
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_ERROR,
    					"%s:i2c_slave_write:pthread_mutex_unlock: failure exit 1", pszProgram);
    		exit(1);
    	}
    */
    	if ( uiVerbosity >= LOGGING_DEBUG_FINE )
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_ERROR,
    				"%s:i2c_slave_write: complete, so do it again Status In 0x%X Out 0x%X", pszProgram, status, in16( dev->regbase + I2C_STSREG_OFF ) );
    //	i2c_reset(dev);		// reset and restart
    	goto start;
    	t = i2c_deattach_slave_write_interrupt((void *) dev);
    	if (t == -1)
    	{
    		if (uiVerbosity >= LOGGING_ERRORS)
    			slogf(_SLOGC_SNELL_IQMIT_I2C_RESMGR, _SLOG_ERROR,
    					"%s:i2c_slave_write:i2c_deattach_slave_write_interrupt failure", pszProgram);
    		return;
    	}
    	/* Should never get here */
    	if ( uiVerbosity >= LOGGING_ERRORS )
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_CRITICAL,
    				"%s:i2c_slave_write: Should never get here return 0", pszProgram);
    	return;
    }
    

    send.c
    #include "proto.h"
    
    extern int iMaster;
    
    i2c_status_t i2c_send(i2c_dev_t *dev, void *buf, unsigned int len, unsigned int stop)
    {
        int    status, timeout;;
    
        if (len <= 0)
        {
        	if (uiVerbosity >= LOGGING_ERRORS)
        		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_WARNING, "%s:i2c_send: len <= 0 return I2C_STATUS_DONE", pszProgram);
           return I2C_STATUS_DONE;
        }
    
        /* set slave address */
        if (dev->slave_addr_fmt == I2C_ADDRFMT_7BIT)
            out16(dev->regbase + I2C_CTRREG_OFF, in16(dev->regbase + I2C_CTRREG_OFF) & (~CTRREG_XSA));
        else
            out16(dev->regbase + I2C_CTRREG_OFF, in16(dev->regbase + I2C_CTRREG_OFF) | CTRREG_XSA);
        out16(dev->regbase + AM335x_I2C_SA, dev->slave_addr);
    
        if(i2c_wait_bus_not_busy(dev))
    	{
    		if (uiVerbosity >= LOGGING_ERRORS)
        		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_WARNING, "%s:i2c_send:i2c_wait_bus_not_busy: not 0 return I2C_STATUS_ERROR", pszProgram);
    		return I2C_STATUS_ERROR;
    	}
    
    	iMaster = 1;
    
        // Set Master Send Byte Count
        out16(dev->regbase + AM335x_I2C_CNT, len);
    	out16(dev->regbase + I2C_CTRREG_OFF, CTRREG_IEN | CTRREG_MSTA | CTRREG_MTX | AM335x_STT | ( stop ? AM335x_STP : 0 ) );
    //	printf( "Master write len %d\n", len );
    	timeout = 2000;
    	while ( --timeout && in16(dev->regbase + I2C_CTRREG_OFF) & ( CTRREG_IEN | CTRREG_MSTA | CTRREG_MTX ) != ( CTRREG_IEN | CTRREG_MSTA | CTRREG_MTX ) );
    	if ( !timeout )
    	{
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_ERROR, "%s:i2c_send: timeout CTLREG, so reset", pszProgram );
    		i2c_reset(dev);
    		return -1;
    	}
    	/* Send the rest of the data */
    	int iCount = 1;
    	while ( len > 0)
    	{
    		timeout = 2000;
    		while ( --timeout && ( ( status = in16(dev->regbase + I2C_STSREG_OFF) ) & AM335x_I2C_MST_XMT ) != AM335x_I2C_MST_XMT && !( status & ( AM335x_I2C_ERROR ) ) ); //| AM335x_I2C_ARDY ) ) );
    		if ( !timeout )
    		{
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_ERROR, "%s:i2c_send: timeout XMT status 0x%X, so reset", pszProgram, status );
    			i2c_reset(dev);
    			return -2;
    		}
    		if (status & AM335x_I2C_ERROR)
    		{
    			if (uiVerbosity >= LOGGING_ERRORS)
    				slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_WARNING, "%s:i2c_send: error return 0x%X", pszProgram, status);
    			i2c_reset(dev);
    			return status;
    		}
    		out16(dev->regbase + I2C_DATREG_OFF, (*(char *)buf) & 0x0FF);
    		out16(dev->regbase + AM335x_I2C_STAT, AM335x_I2C_XRDY );
    		if ( uiVerbosity >= LOGGING_PROGRESS )
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_INFO, "%s:i2c_send: Byte %d is 0x%02X '%s', status 0x%X",
    				pszProgram, iCount, *((unsigned char *)buf), fnlibCharToString( *((char *)buf) ), status);
    //	    printf( "Master write Byte %d is 0x%02X status 0x%X\n", iCount, *((unsigned char *)buf) & 0x0FF, status );
    		++buf; --len, iCount++;
    /*
    		if ( status & AM335x_I2C_ARDY )
    		{
    			if (uiVerbosity >= LOGGING_ERRORS)
    				slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_WARNING, "%s:i2c_slave_send: ARDY found before complete return 0x%X", pszProgram, status);
    			out16(dev->regbase + AM335x_I2C_STAT, AM335x_I2C_ARDY );
    			return status;
    		}
    */
    	}
    	timeout = 2000;
    	while( --timeout && !( in16(dev->regbase + I2C_STSREG_OFF) & AM335x_I2C_ARDY ) );
    	if ( !timeout )
    	{
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_ERROR, "%s:i2c_send: timeout ARDY status 0x%X, so reset", pszProgram, in16(dev->regbase + I2C_STSREG_OFF) );
    		i2c_reset(dev);
    		return -3;
    	}
    
    	dev->restart = !stop;
    //	out16(dev->regbase + I2C_CTRREG_OFF, CTRREG_IEN | AM335x_STP );
    	status = in16( dev->regbase + I2C_STSREG_OFF );
    //	printf( "Master Write done status 0x%X\n", status );
    	out16( dev->regbase + AM335x_I2C_STAT,  status & ( AM335x_I2C_XRDY | AM335x_I2C_XUDF | AM335x_I2C_ARDY | AM335x_I2C_NACK  | AM335x_I2C_AL | AM335x_I2C_BF ) );
    	iMaster = 0;
    	if (uiVerbosity >= LOGGING_PROGRESS)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_INFO, "%s:i2c_send: complete return 0", pszProgram);
    	return 0;
    }
    

    am335x_i2c_reg_offsets.h

    Well, although it may not be perfect we seem to have the code working reasonably well for the Slave transmit and the Master Transmit.  It seems the combination of XUDF | XRDY works well to slow down the process and get the bits out and then looking for the ARDY bit seems to signal end and all seems well.  The BB bit is set throughout the transfer.  The main issue is when in Slave receive mode.  The BB bit and BF bits seem to reflect nothing consistent at all. 

    I was hoping on receipt of the AAS | RRDY there would also be a BB bit to hold off further Master Receives while the Master Send is in progress.  I also look for an ARDY to signal that the STOP has been performed (I also would like to see the loss of a BB to identify this also but as BB seems irregular that does not happen either).

    I will include my code for the Slave receive and perhaps you can shine some idea of where we are going wrong.  I have tried to get the ROVR flag to work by setting the DCOUNT to 1 and waiting but that does not work.  Also why reading, what happens id the XUDF | BB | XRDY bits also get set stating that a slave XMIT should happen simultaneously.  I feel this should never occur.

  • Let's please focus on a single thing: slave receive.

    Steven Stoner said:

    I was hoping on receipt of the AAS | RRDY there would also be a BB bit to hold off further Master Receives while the Master Send is in progress.  I also look for an ARDY to signal that the STOP has been performed (I also would like to see the loss of a BB to identify this also but as BB seems irregular that does not happen either).

    For slave receive, BB will be set throughout the entire transaction. When the master ends the transaction (sends a stop bit) then you should see BB=0.  It seems to me that BB=0 would be a natural condition to exit out of your code.

    Let's stick with this slave receive scenario.  Can you please provide some more details as to what behavior you're seeing?  For example, let's say that the master on the bus sends you 8 bytes.  What's the corresponding behavior?  Do you receive all 8 bytes?  I'm not clear on exactly what problem we're trying to solve...

  • Hello Brad,

    Thanks so much for the quick reply.  I believe you and I both agree the BB should be set on a Slave Receive, but this is not what we are seeing.

    If you look in wait.c above there is a routine i2c_slave_wait_forever which will have two threads waiting on it.  There will be a Slave Read and a Slave Write thread both sitting in this routine.  When AAS and RRDY is set the Slave Read will start.  This read will loop, in i2c_slave_recv in slave_recv.c, until it receives a I2C_SLV_RCV, a timeout or an Error/ARDY.  Now if you look in am335x_i2c_reg_offsets you will see that we have tried several combinations of I2C_SLV_RCV.  The one I think should work (similar to the I2C_SLV_XMT) is BB | AAS | ROVR | RRDY.  If we could use that to throttle the communications and ensure accuracy it would be brilliant.  Unfortunately the ONLY bits that we seem to be able to use are RRDY | AAS and even that is not consistent.

    Both the BB and BF bits seem to be inconsistent and unreliable in what we have seen so far in  respect to Slave Receive.  In both Transmit modes the BB works as expected although BF is still unreliable.

    Thanks Steve

  • Hello once again Brad, to complete the answer to your question, if eight bytes are sent we do get all eight bytes but in getting them, for example, the first one will have AAS | BF | RRDY (clearing the RRDY | BF bit after each byte read) the next six may have AAS | RRDY only and then perhaps a BB | XUDF | AAS | BF | XRDY | RRDY on the last byte. If I were to handle only the read and clear the RRDY | BF and let us say this is the last byte then the status-raw will go to AAS and I will not receive and ARDY at all. It will timeout and produce an error. It looks to me like a Master Read is trying to come in at the same time that we handle the Master Write. That is one example of a failing Slave Read. Realise we may have had three to four successful ones before this failure. Thanks Steve
  • Steven Stoner said:
    It looks to me like a Master Read is trying to come in at the same time that we handle the Master Write.

    Have you tried testing in a controlled/contrived environment so that you can more precisely understand what scenarios are causing problems?  In general I expect very consistent behavior, so if you're seeing different behavior at certain times I think it would be useful to understand precisely under what circumstances.

  • Steve,

    In the behavior you described above are there only 2 devices involved (ie 1 slave and 1 master)?
    Or do you still have multiple devices on the bus? Do you see the same behavior if only 2 devices are active on the bus?
    Can you test with 2 devices only to start with?

    Looking at Fig 17-35 SLAVE TX/RX Polling of SPRUGN4R as reference and for the AM335x slave read scenario you mention (ie receive 8 bytes from the Master):
    To try to understand the behavior:
    What is the complete I2C_STAT reg value for each loop iteration of the complete transaction (ie 8bytes transfered)?
    What is the I2C_CON MST and TRX bit value for each loop iteration of the complete transaction?
    How many time is the loop running for the complete transaction?

    A.
  • Hello Brad and AnBer,

    I apoligise for the late response here but I have been on holiday for the last three weeks and was actually out of the country for two of those weeks.  The environment we have been using for our testing only involves two cards on the I2C bus, so it is rather controlled.  When each of the different scenarios is tried between two individual TI cards they work on a one off basis.  I.E. when told to send "Hello" it sends from one card and receives on the other. 

    The issue occurs when we have one "gateway" card and one TI card.  The gateway polls each of the slots on the bus regularly to determine presence of cards on the bus.  This is performed by a Master read issued to each slot.  If a card is present it responds with an "I am here response" (4 bytes).  Once this is received the gateway then asks the card to identify itself with a Master Write.  The card reads this (and this is the read we have issues with) and responds with it's own identification to uniquely identify the type of card that is responding.  This is done by a Master Write from the TI card to the gateway. 

    Once this is done then the gateway can be told to connect with the card.  This is where a lot of transmissions are started by each of the two cards to request and respond to different scenarios based on the card type.  Also while this is occurring the gateway still continues it's sequential polling of each slot to verify presence of cards in each slot (including the slot containing our card).

    Now while I was away, my colleague tried to implement a ISR driven driver as opposed to my polling driver.  This was moving along up until there appears to be similar issues with this new alternative implementation similar to the issues we have been speaking about in this discussion thread.  We are going to try and organise a conference call with TI again and would really appreciate it if Brad could be on that call. We need to determine what is necessary to get a functional I2C driver working for our card using this processor. 

    Thanks so much, Steve

  • To make the debug productive, I request that you:

    1. Hook up a logic analyzer to capture a failing sequence. The first critical step in debugging the issue will be to understand what's happening at the bus level.

    2. Instrument your driver to log data into a RAM buffer. Ultimately we'll need to be able to correlate this register level data with what's happening at the bus level.
  • Here is a quick flow of the Slave Reads on initial start-up. At this point all is good but the values still do not look correct.
    Following this our system is still alive but the status after byte 4 appears to be all incorrect.

    In Byte 1 is 0x2E statraw 0x1208 status 0x1000...
    In Byte 2 is 0x2D statraw 0x1208 status 0x1000...
    In Byte 3 is 0x00 statraw 0x1208 status 0x1000...
    In Byte 4 is 0x02 statraw 0x1208 status 0x1000...
    In Byte 5 is 0x00 statraw 0x308 status 0x0...
    In Byte 6 is 0x04 statraw 0x208 status 0x0...
    In Byte 7 is 0x2D statraw 0x208 status 0x0...
    In Byte 8 is 0x00 statraw 0x208 status 0x0...
    In Byte 9 is 0x00 statraw 0x208 status 0x0...
    In Byte 10 is 0x00 statraw 0x208 status 0x0...
    Slave Read Stop found after reading 10 bytes status 0x4
    QNX RollCall checkIPL
    checkIPL CWD: /fs/sda/flash001/bin
    changed CWD to: /fs/sda
    Read 8 bytes from ipl and it contains flash001
    iplthis contains flash001
    ipllast contains flash001
    ipl contains flash001
    cwd is flash001
    LCR:Set IPL files: checkIPL exit code should be 0 for success: 0
    Licence initialise...Licence OnInitDone
    /fs/sda/flash/upgrade.opt - license file Error: No Licence File, nothing enabled or disabled
    [OK]
    FPGA is healthy
    Started application at 2000-01-01 00:00:37 ============================
    In Byte 1 is 0x2E statraw 0x308 status 0x0...
    In Byte 2 is 0x06 statraw 0x208 status 0x0...
    In Byte 3 is 0x00 statraw 0x208 status 0x0...
    In Byte 4 is 0x02 statraw 0x208 status 0x0...
    In Byte 5 is 0x00 statraw 0x208 status 0x0...
    In Byte 6 is 0x02 statraw 0x208 status 0x0...
    In Byte 7 is 0x06 statraw 0x208 status 0x0...
    In Byte 8 is 0x00 statraw 0x208 status 0x0...
    Slave Read Stop found after reading 8 bytes status 0x4
    In Byte 1 is 0x4E statraw 0x308 status 0x0...
    In Byte 2 is 0x16 statraw 0x208 status 0x0...
    In Byte 3 is 0x00 statraw 0x208 status 0x0...
    In Byte 4 is 0x02 statraw 0x208 status 0x0...
    In Byte 5 is 0x00 statraw 0x208 status 0x0...
    In Byte 6 is 0x02 statraw 0x208 status 0x0...
    In Byte 7 is 0x16 statraw 0x208 status 0x0...
    In Byte 8 is 0x00 statraw 0x208 status 0x0...
    Slave Read Stop found after reading 8 bytes status 0x4

    I can provide more detail, but I thought an initial look in to what we are seeing would be good.
  • Steven Stoner said:
    Here is a quick flow of the Slave Reads on initial start-up. At this point all is good but the values still do not look correct.
    Following this our system is still alive but the status after byte 4 appears to be all incorrect.

    In Byte 1 is 0x2E statraw 0x1208 status 0x1000...
    In Byte 2 is 0x2D statraw 0x1208 status 0x1000...
    In Byte 3 is 0x00 statraw 0x1208 status 0x1000...
    In Byte 4 is 0x02 statraw 0x1208 status 0x1000...
    In Byte 5 is 0x00 statraw 0x308 status 0x0...

    Just to be clear, the AM335x is the slave receiver?  Some other device is the master transmitter sending us data?

    This is where it would be useful to see what's happening at the bus level.  Is a stop bit sent after byte 4?

  • I will get you that tomorrow but I do believe that it will show the stop after the 10th and then the 8th bytes after that. I would have done that today but both analysers are on similar projects all having I2C issues!!
  • The only 2 cards are the gateway card (0x10) and the TI card (0x4E).

    In this run the results were not identical to the previous one and the information is far greater as I also did a sloginfo which prints driver specific info.

    The result of my simple run today on the analyser is as follows:

    The full debug text as I posted it to you the other day is as follows:

    Jan 01 21:06:41    5 21001   100 rmi2c:main: Loading new I2C Resource Manager using device=/dev/i2c0 and verbosity 5
    Jan 01 21:06:41    6 21001   100 rmi2c:main:iofunc_func_init: Setting I2C Resource Manager connect functions and i/o functions
    Jan 01 21:06:41    6 21001   100 rmi2c:main:iofunc_attr_init: Setting I2C Resource Manager attributes and permissions
    Jan 01 21:06:41    6 21001   100 rmi2c:main:i2c_init: Calling function with 4 arguments
    Jan 01 21:06:41    5 21001     0 rmi2c:i2c_options: case 'p' setting dev->physbase to 0x44E0B000
    Jan 01 21:06:41    5 21001     0 rmi2c:i2c_options: case 'i' setting dev->intr to 0x46
    Jan 01 21:06:41    5 21001   100 rmi2c:i2c_init: Successful
    Jan 01 21:06:41    5 21001     0 rmi2c:i2c_set_own_addr: setting from address as 0x4E
    Jan 01 21:06:41    6 21001   100 rmi2c:main: Slot Number is E Own address set to 0x4E
    Jan 01 21:06:41    7 21001     0 rmi2c:i2c_slave_write: entry
    Jan 01 21:06:41    5 21001   100 rmi2c:i2c_attach_slave_write_interrupt: Successful
    Jan 01 21:06:41    7 21001     0 rmi2c:i2c_slave_wait_forever: write entry iid 12 (CTRREG 0x0 STSREG 0x100)
    Jan 01 21:06:41    6 21001   100 rmi2c:main:pthread_create: Master Read/Slave Write thread id is: 2 0x2
    Jan 01 21:06:41    6 21001   100 rmi2c:main:pthread_create: MQ thread id is: 3 0x3
    Jan 01 21:06:41    6 21001   100 rmi2c:ProcessMQThread:mq_open: Queue /rmi2c0 returned 1902968833 0x716D0001
    LCR:main: RollCall Multi-Home Server starting
    Jan 01 21:07:12    5 21100     0 LCR:main: RollCall Multi-Home Server starting
    LCR:Detected LCR card in slot 14
    Starting RollCall
    Jan 01 21:07:12    5 21100     0 LCR:Detected LCR card in slot 14
    service 'SetupSerialNoEdit' unknown for command 32778 - substituting 'print'
    Trying to open MemMap file: /fs/sda/flash001/IQHCO50/soft/sys/MemMap.cfg
    nvram Memstore OK
    Jan 01 21:07:13    5 21001   100 rmi2c:io_open:iofunc_open_default: I2C Resource Manager opening return 0x0
    Doing reset Control 0x0 Status 0x100
    Jan 01 21:07:13    6 21001     0 rmi2c:i2c_reset: entry (CTRREG 0x0 STSREG 0x100)
    Jan 01 21:07:13    5 21001     0 rmi2c:i2c_set_bus_speed: entry target speed 100000
    Jan 01 21:07:13    7 21001     0 rmi2c:i2c_slave_wait_forever: write return 0 (CTRREG 0x8000 STSREG 0x1710)
    Jan 01 21:07:13    7 21001     0 rmi2c:i2c_slave_write:i2c_slave_wait_forever: status 0x0
    Jan 01 21:07:13    7 21001     0 rmi2c:i2c_slave_write: Slave Write
    Jan 01 21:07:13    7 21001     0 rmi2c:i2c_slave_send: entry
    Jan 01 21:07:13    7 21001     0 rmi2c:i2c_slave_send: pad length 1, status 0x1710
    Jan 01 21:07:13    7 21001     0 rmi2c:i2c_slave_send: pad length 2, status 0x1710
    Jan 01 21:07:13    7 21001     0 rmi2c:i2c_slave_send: pad length 3, status 0x1710
    Jan 01 21:07:13    7 21001     0 rmi2c:i2c_slave_send: pad length 4, status 0x1710
    Jan 01 21:07:13    2 21001     0 rmi2c:i2c_slave_write: complete, so do it again Status In 0x106 Out 0x0
    Jan 01 21:07:13    7 21001     0 rmi2c:i2c_slave_wait_forever: write entry iid 12 (CTRREG 0x8000 STSREG 0x0)
    Jan 01 21:07:14    7 21001     0 rmi2c:i2c_slave_wait_forever: write return 0 (CTRREG 0x8000 STSREG 0x1710)
    Jan 01 21:07:14    7 21001     0 rmi2c:i2c_slave_write:i2c_slave_wait_forever: status 0x0
    Jan 01 21:07:14    7 21001     0 rmi2c:i2c_slave_write: Slave Write
    Jan 01 21:07:14    7 21001     0 rmi2c:i2c_slave_send: entry
    Jan 01 21:07:14    7 21001     0 rmi2c:i2c_slave_send: pad length 1, status 0x1710
    Jan 01 21:07:14    7 21001     0 rmi2c:i2c_slave_send: pad length 2, status 0x1710
    Jan 01 21:07:14    7 21001     0 rmi2c:i2c_slave_send: pad length 3, status 0x1710
    Jan 01 21:07:14    7 21001     0 rmi2c:i2c_slave_send: pad length 4, status 0x1710
    Jan 01 21:07:14    2 21001     0 rmi2c:i2c_slave_write: complete, so do it again Status In 0x106 Out 0x0
    Jan 01 21:07:14    7 21001     0 rmi2c:i2c_slave_wait_forever: write entry iid 12 (CTRREG 0x8000 STSREG 0x0)
    Jan 01 21:07:15    7 21001     0 rmi2c:i2c_slave_wait_forever: write return 0 (CTRREG 0x8000 STSREG 0x1710)
    Jan 01 21:07:15    7 21001     0 rmi2c:i2c_slave_write:i2c_slave_wait_forever: status 0x0
    Jan 01 21:07:15    7 21001     0 rmi2c:i2c_slave_write: Slave Write
    Jan 01 21:07:15    7 21001     0 rmi2c:i2c_slave_send: entry
    Jan 01 21:07:15    7 21001     0 rmi2c:i2c_slave_send: pad length 1, status 0x1710
    Jan 01 21:07:15    7 21001     0 rmi2c:i2c_slave_send: pad length 2, status 0x1710
    Jan 01 21:07:15    7 21001     0 rmi2c:i2c_slave_send: pad length 3, status 0x1710
    Jan 01 21:07:15    7 21001     0 rmi2c:i2c_slave_send: pad length 4, status 0x1710
    Jan 01 21:07:15    2 21001     0 rmi2c:i2c_slave_write: complete, so do it again Status In 0x106 Out 0x0
    Jan 01 21:07:15    7 21001     0 rmi2c:i2c_slave_wait_forever: write entry iid 12 (CTRREG 0x8000 STSREG 0x0)
    Jan 01 21:07:16    6 21001     0 rmi2c:i2c_reset: exit (CTRREG 0x8000 STSREG 0x100)
    Jan 01 21:07:16    5 21001   100 rmi2c:io_devctl: Type.............. 262
    Jan 01 21:07:16    5 21001   100 rmi2c:io_devctl: Combine length.... 16
    Jan 01 21:07:16    5 21001   100 rmi2c:io_devctl: DCMD.............. 0x80040504
    Jan 01 21:07:16    5 21001   100 rmi2c:io_devctl: Number of bytes... 4
    Jan 01 21:07:16    5 21001   100 rmi2c:io_devctl:DCMD_I2C_DRIVER_BUS_SPEED
    Jan 01 21:07:16    5 21001   100 rmi2c:io_devctl:DCMD_I2C_DRIVER_BUS_SPEED: Set bus speed to 100000
    Jan 01 21:07:16    5 21001   100 rmi2c:io_devctl: Type.............. 262
    Jan 01 21:07:16    5 21001   100 rmi2c:io_devctl: Combine length.... 16
    Jan 01 21:07:16    5 21001   100 rmi2c:io_devctl: DCMD.............. 0x80010505
    Jan 01 21:07:16    5 21001   100 rmi2c:io_devctl: Number of bytes... 1
    Jan 01 21:07:16    5 21001   100 rmi2c:io_devctl:DCMD_I2C_DRIVER_SET_OWN_ADDR
    Jan 01 21:07:16    5 21001   100 rmi2c:io_devctl:DCMD_I2C_DRIVER_SET_OWN_ADDR: Set my address to 0x1864E
    Jan 01 21:07:16    5 21001     0 rmi2c:i2c_set_own_addr: setting from address as 0x4E
    Jan 01 21:07:16    5 21001   100 rmi2c:io_devctl: Type.............. 262
    Jan 01 21:07:16    5 21001   100 rmi2c:io_devctl: Combine length.... 16
    Jan 01 21:07:16    5 21001   100 rmi2c:io_devctl: DCMD.............. 0x80040503
    Jan 01 21:07:16    5 21001   100 rmi2c:io_devctl: Number of bytes... 4
    Jan 01 21:07:16    5 21001   100 rmi2c:io_devctl:DCMD_I2C_DRIVER_MSLAVE_DEST
    Jan 01 21:07:16    5 21001   100 rmi2c:io_devctl:DCMD_I2C_DRIVER_MSLAVE_DEST: Set slave address to 0x10
    Jan 01 21:07:16    5 21001     0 rmi2c:i2c_set_slave_addr: setting to address as 0x10
    Jan 01 21:07:16    5 21001   100 rmi2c:io_devctl: Type.............. 262
    Jan 01 21:07:16    5 21001   100 rmi2c:io_devctl: Combine length.... 16
    Jan 01 21:07:16    5 21001   100 rmi2c:io_devctl: DCMD.............. 0x82020507
    Jan 01 21:07:16    5 21001   100 rmi2c:io_devctl: Number of bytes... 514
    Jan 01 21:07:16    5 21001   100 rmi2c:io_devctl:DCMD_I2C_DRIVER_SLAVE_DATA
    Jan 01 21:07:16    5 21001     0 rmi2c:i2c_set_callback: Slave transmit length 4 bytes:
    Jan 01 21:07:16    5 21001     0 rmi2c:i2c_set_callback:
    Starting RollCall services
    In Byte 1 is 0x2E statraw 0x308 status 0x0...
    Jan 01 21:07:16    5 21001     0 rmi2c:i2c_set_callback: 0000
    In Byte 2 is 0x2D statraw 0x208 status 0x0...
    Jan 01 21:07:16    5 21001     0 rmi2c:i2c_set_callback: 000C
    Jan 01 21:07:16    5 21001   100 rmi2c:io_read: I2C Resource Manager reading
    In Byte 3 is 0x00 statraw 0x208 status 0x0...
    Jan 01 21:07:16    3 21001   100 rmi2c:io_read: creating read thread 1: 0x1
    [IQHCO50] TableLogInit: Enums 0, Nums 0, Strings 217, Fixed 0
    Jan 01 21:07:16    5 21001   100 rmi2c:io_read: Reading up to 512 bytes
    In Byte 4 is 0x02 statraw 0x208 status 0x0...
    ---------Enable Module Logging-----------
    Jan 01 21:07:16    6 21001   100 rmi2c:io_read: Setting iBlockId 0x140003
    StartLogging
    Jan 01 21:07:16    7 21001     0 rmi2c:i2c_slave_read: entry
    In Byte 5 is 0x00 statraw 0x208 status 0x0...
    Jan 01 21:07:16    5 21001   100 rmi2c:i2c_attach_slave_read_interrupt: Successful
    Jan 01 21:07:16    7 21001     0 rmi2c:i2c_slave_wait_forever: read entry iid 13 (CTRREG 0x8000 STSREG 0x100)
    In Byte 6 is 0x04 statraw 0x208 status 0x0...
    Jan 01 21:07:16    7 21001     0 rmi2c:i2c_slave_wait_forever: write return 0 (CTRREG 0x8000 STSREG 0x1710)
    Jan 01 21:07:16    7 21001     0 rmi2c:i2c_slave_write:i2c_slave_wait_forever: status 0x0
    In Byte 7 is 0x2D statraw 0x208 status 0x0...
    Jan 01 21:07:16    7 21001     0 rmi2c:i2c_slave_write: Slave Write
    Jan 01 21:07:16    7 21001     0 rmi2c:i2c_slave_send: entry
    In Byte 8 is 0x00 statraw 0x208 status 0x1000...
    Jan 01 21:07:16    5 21001     0 rmi2c:i2c_slave_send: Byte 1 is 0x00 '', status 0x1710
    Jan 01 21:07:16    5 21001     0 rmi2c:i2c_slave_send: Byte 2 is 0x00 '', status 0x1710
    In Byte 9 is 0x00 statraw 0x308 status 0x0...
    Jan 01 21:07:16    5 21001     0 rmi2c:i2c_slave_send: Byte 3 is 0x00 '', status 0x1710
    Jan 01 21:07:16    5 21001     0 rmi2c:i2c_slave_send: Byte 4 is 0x0C '', status 0x1710
    In Byte 10 is 0x00 statraw 0x308 status 0x0...
    Jan 01 21:07:16    2 21001     0 rmi2c:i2c_slave_write: complete, so do it again Status In 0x106 Out 0x0
    Fake successful read of 10 bytes
    Jan 01 21:07:16    7 21001     0 rmi2c:i2c_slave_wait_forever: write entry iid 12 (CTRREG 0x8000 STSREG 0x0)
    Jan 01 21:07:16    7 21001     0 rmi2c:i2c_slave_wait_forever: read return 0 (CTRREG 0x8000 STSREG 0x308)
    Jan 01 21:07:16    5 21001   100 rmi2c:i2c_deattach_slave_read_interrupt: Successful
    Jan 01 21:07:16    7 21001     0 rmi2c:i2c_slave_read:  Starting receive (CTRREG 0x8000 STSREG 0x308)
    Jan 01 21:07:16    5 21001     0 rmi2c:i2c_slave_recv: Byte 1 is 0x2E '.', (CTRREG 0x8000 STSREG 0x208)
    Jan 01 21:07:16    5 21001     0 rmi2c:i2c_slave_recv: Byte 2 is 0x2D '-', (CTRREG 0x8000 STSREG 0x208)
    Jan 01 21:07:16    5 21001     0 rmi2c:i2c_slave_recv: Byte 3 is 0x00 '', (CTRREG 0x8000 STSREG 0x208)
    Jan 01 21:07:16    5 21001     0 rmi2c:i2c_slave_recv: Byte 4 is 0x02 '', (CTRREG 0x8000 STSREG 0x208)
    Jan 01 21:07:16    5 21001     0 rmi2c:i2c_slave_recv: Byte 5 is 0x00 '', (CTRREG 0x8000 STSREG 0x208)
    Jan 01 21:07:16    5 21001     0 rmi2c:i2c_slave_recv: Byte 6 is 0x04 '', (CTRREG 0x8000 STSREG 0x208)
    Jan 01 21:07:16    5 21001     0 rmi2c:i2c_slave_recv: Byte 7 is 0x2D '-', (CTRREG 0x8000 STSREG 0x208)
    Jan 01 21:07:16    5 21001     0 rmi2c:i2c_slave_recv: Byte 8 is 0x00 '', (CTRREG 0x8000 STSREG 0x208)
    Jan 01 21:07:16    5 21001     0 rmi2c:i2c_slave_recv: Byte 9 is 0x00 '', (CTRREG 0x8000 STSREG 0x208)
    Jan 01 21:07:16    5 21001     0 rmi2c:i2c_slave_recv: Byte 10 is 0x00 '', (CTRREG 0x8000 STSREG 0x200)
    Jan 01 21:07:16    7 21001     0 rmi2c:i2c_slave:i2c_slave_recv: return 0xA
    Jan 01 21:07:16    6 21001   100 rmi2c:io_read: Clearing iBlockId 0x140003
    Jan 01 21:07:16    5 21001   100 rmi2c:io_read:i2c_slave: Returned 10 byte count read:
    Jan 01 21:07:16    5 21001   100 rmi2c:io_read:i2c_slave: .-     -
    Jan 01 21:07:16    5 21001   100 rmi2c:io_read:i2c_slave: 2200 0020 00
    Jan 01 21:07:16    5 21001   100 rmi2c:io_read:i2c_slave: ED02 04D0 00
    Jan 01 21:07:16    5 21001   100 rmi2c:io_read: I2C Resource Manager reading
    Jan 01 21:07:16    5 21001   100 rmi2c:io_read: Reading up to 512 bytes
    Jan 01 21:07:16    6 21001   100 rmi2c:io_read: Setting iBlockId 0x140003
    Jan 01 21:07:16    7 21001     0 rmi2c:i2c_slave_read: entry
    Jan 01 21:07:16    5 21001   100 rmi2c:i2c_attach_slave_read_interrupt: Successful
    Jan 01 21:07:16    7 21001     0 rmi2c:i2c_slave_wait_forever: read entry iid 13 (CTRREG 0x8000 STSREG 0x200)
    QNX RollCall checkIPL
    checkIPL CWD: /fs/sda/flash001/bin
    changed CWD to: /fs/sda
    Read 8 bytes from ipl and it contains flash001
    iplthis contains flash001
    ipllast contains flash001
    ipl     contains flash001
    cwd        is    flash001
    LCR:Set IPL files: checkIPL exit code should be 0 for success: 0
    Licence initialise...Licence  OnInitDone
    Jan 01 21:07:16    2 21100     0 LCR:Set IPL files: checkIPL exit code should be 0 for success: 0
    /fs/sda/flash/upgrade.opt - license file Error: No Licence File, nothing enabled or disabled
    [OK]
    FPGA is healthy
    Started application at 2000-01-01 21:07:16  ============================
    Jan 01 21:07:17    7 21001     0 rmi2c:i2c_slave_wait_forever: write return 0 (CTRREG 0x8000 STSREG 0x1714)
    Jan 01 21:07:17    7 21001     0 rmi2c:i2c_slave_write:i2c_slave_wait_forever: status 0x0
    Jan 01 21:07:17    7 21001     0 rmi2c:i2c_slave_write: Slave Write
    Jan 01 21:07:17    7 21001     0 rmi2c:i2c_slave_send: entry
    Jan 01 21:07:17    5 21001     0 rmi2c:i2c_slave_send: Byte 1 is 0x00 '', status 0x1714
    Jan 01 21:07:17    5 21001     0 rmi2c:i2c_slave_send: Byte 2 is 0x00 '', status 0x1714
    Jan 01 21:07:17    5 21001     0 rmi2c:i2c_slave_send: Byte 3 is 0x00 '', status 0x1714
    Jan 01 21:07:17    5 21001     0 rmi2c:i2c_slave_send: Byte 4 is 0x0C '', status 0x1714
    Jan 01 21:07:17    2 21001     0 rmi2c:i2c_slave_write: complete, so do it again Status In 0x106 Out 0x0
    Jan 01 21:07:17    7 21001     0 rmi2c:i2c_slave_wait_forever: write entry iid 12 (CTRREG 0x8000 STSREG 0x0)
    Jan 01 21:07:18    7 21001     0 rmi2c:i2c_slave_wait_forever: write return 0 (CTRREG 0x8000 STSREG 0x1710)
    Jan 01 21:07:18    7 21001     0 rmi2c:i2c_slave_write:i2c_slave_wait_forever: status 0x0
    Jan 01 21:07:18    7 21001     0 rmi2c:i2c_slave_write: Slave Write
    Jan 01 21:07:18    7 21001     0 rmi2c:i2c_slave_send: entry
    Jan 01 21:07:18    5 21001     0 rmi2c:i2c_slave_send: Byte 1 is 0x00 '', status 0x1710
    Jan 01 21:07:18    5 21001     0 rmi2c:i2c_slave_send: Byte 2 is 0x00 '', status 0x1710
    Jan 01 21:07:18    5 21001     0 rmi2c:i2c_slave_send: Byte 3 is 0x00 '', status 0x1710
    Jan 01 21:07:18    5 21001     0 rmi2c:i2c_slave_send: Byte 4 is 0x0C '', status 0x1710
    Jan 01 21:07:18    2 21001     0 rmi2c:i2c_slave_write: complete, so do it again Status In 0x106 Out 0x0
    Jan 01 21:07:18    7 21001     0 rmi2c:i2c_slave_wait_forever: write entry iid 12 (CTRREG 0x8000 STSREG 0x0)
    Jan 01 21:07:19    7 21001     0 rmi2c:i2c_slave_wait_forever: write return 0 (CTRREG 0x8000 STSREG 0x1710)
    Jan 01 21:07:19    7 21001     0 rmi2c:i2c_slave_write:i2c_slave_wait_forever: status 0x0
    Jan 01 21:07:19    7 21001     0 rmi2c:i2c_slave_write: Slave Write
    Jan 01 21:07:19    7 21001     0 rmi2c:i2c_slave_send: entry
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_slave_send: Byte 1 is 0x00 '', status 0x1710
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_slave_send: Byte 2 is 0x00 '', status 0x1710
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_slave_send: Byte 3 is 0x00 '', status 0x1710
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_slave_send: Byte 4 is 0x0C '', status 0x1710
    Jan 01 21:07:19    2 21001     0 rmi2c:i2c_slave_write: complete, so do it again Status In 0x106 Out 0x0
    Jan 01 21:07:19    7 21001     0 rmi2c:i2c_slave_wait_forever: write entry iid 12 (CTRREG 0x8000 STSREG 0x0)
    Jan 01 21:07:19    7 21001     0 rmi2c:i2c_slave_wait_forever: read return 0 (CTRREG 0x8000 STSREG 0x1208)
    Jan 01 21:07:19    5 21001   100 rmi2c:i2c_deattach_slave_read_interrupt: Successful
    In Byte 1 is 0x2E statraw 0x1208 status 0x1000...
    Jan 01 21:07:19    7 21001     0 rmi2c:i2c_slave_read:  Starting receive (CTRREG 0x8000 STSREG 0x1208)
    In Byte 2 is 0x06 statraw 0x308 status 0x0...
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_slave_recv: Byte 1 is 0x2E '.', (CTRREG 0x8000 STSREG 0x1208)
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_slave_recv: Byte 2 is 0x06 '', (CTRREG 0x8000 STSREG 0x208)
    In Byte 3 is 0x00 statraw 0x208 status 0x0...
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_slave_recv: Byte 3 is 0x00 '', (CTRREG 0x8000 STSREG 0x208)
    In Byte 4 is 0x02 statraw 0x208 status 0x0...
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_slave_recv: Byte 4 is 0x02 '', (CTRREG 0x8000 STSREG 0x208)
    In Byte 5 is 0x00 statraw 0x208 status 0x0...
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_slave_recv: Byte 5 is 0x00 '', (CTRREG 0x8000 STSREG 0x208)
    In Byte 6 is 0x02 statraw 0x208 status 0x0...
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_slave_recv: Byte 6 is 0x02 '', (CTRREG 0x8000 STSREG 0x208)
    In Byte 7 is 0x06 statraw 0x208 status 0x0...
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_slave_recv: Byte 7 is 0x06 '', (CTRREG 0x8000 STSREG 0x208)
    In Byte 8 is 0x00 statraw 0x208 status 0x0...
    Slave Read Stop found after reading 8 bytes status 0x104
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_slave_recv: Byte 8 is 0x00 '', (CTRREG 0x8000 STSREG 0x4)
    Jan 01 21:07:19    7 21001     0 rmi2c:i2c_slave_recv: Stop received, return 8 bytes
    Jan 01 21:07:19    7 21001     0 rmi2c:i2c_slave:i2c_slave_recv: return 0x8
    Jan 01 21:07:19    6 21001   100 rmi2c:io_read: Clearing iBlockId 0x140003
    Jan 01 21:07:19    5 21001   100 rmi2c:io_read:i2c_slave: Returned 8 byte count read:
    Jan 01 21:07:19    5 21001   100 rmi2c:io_read:i2c_slave: .
    Jan 01 21:07:19    5 21001   100 rmi2c:io_read:i2c_slave: 2000 0000
    Jan 01 21:07:19    5 21001   100 rmi2c:io_read:i2c_slave: E602 0260
    Jan 01 21:07:19    5 21001   100 rmi2c:io_write: entry
    Jan 01 21:07:19    5 21001   100 rmi2c:io_write: Writing 39 bytes
    Jan 01 21:07:19    7 21001     0 rmi2c:i2c_wait_bus_not_busy: entry (CTRREG 0x8000 STSREG 0x0)
    Jan 01 21:07:19    7 21001     0 rmi2c:i2c_wait_bus_not_busy: return 0 (CTRREG 0x8000 STSREG 0x0)
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 1 is 0x2E '.', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 2 is 0x07 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 3 is 0x00 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 4 is 0x02 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 5 is 0x00 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 6 is 0x21 '!', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 7 is 0x07 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 8 is 0x00 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 9 is 0x01 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 10 is 0x00 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 11 is 0x03 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 12 is 0x00 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 13 is 0x0B '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 14 is 0x03 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 15 is 0x2B '+', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 16 is 0x05 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 17 is 0x00 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 18 is 0x20 ' ', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 19 is 0x05 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 20 is 0x49 'I', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 21 is 0x51 'Q', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 22 is 0x48 'H', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 23 is 0x43 'C', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 24 is 0x4F 'O', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 25 is 0x35 '5', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 26 is 0x30 '0', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 27 is 0x00 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 28 is 0x00 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 29 is 0x00 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 30 is 0x00 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 31 is 0x00 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 32 is 0x00 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 33 is 0x00 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 34 is 0x00 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 35 is 0x00 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 36 is 0x00 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 37 is 0x00 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 38 is 0x00 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: Byte 39 is 0x00 '', status 0x1410
    Jan 01 21:07:19    5 21001     0 rmi2c:i2c_send: complete return 0
    Jan 01 21:07:19    5 21001   100 rmi2c:io_write:i2c_send: returned 0x0
    Jan 01 21:07:19    5 21001   100 rmi2c:io_read: I2C Resource Manager reading
    Jan 01 21:07:19    5 21001   100 rmi2c:io_read: Reading up to 512 bytes
    Jan 01 21:07:19    6 21001   100 rmi2c:io_read: Setting iBlockId 0x140003
    Jan 01 21:07:19    7 21001     0 rmi2c:i2c_slave_read: entry
    Jan 01 21:07:19    5 21001   100 rmi2c:i2c_attach_slave_read_interrupt: Successful
    Jan 01 21:07:19    7 21001     0 rmi2c:i2c_slave_wait_forever: read entry iid 13 (CTRREG 0x8000 STSREG 0x0)
    Jan 01 21:07:20    7 21001     0 rmi2c:i2c_slave_wait_forever: write return 0 (CTRREG 0x8000 STSREG 0x1710)
    Jan 01 21:07:20    7 21001     0 rmi2c:i2c_slave_write:i2c_slave_wait_forever: status 0x0
    Jan 01 21:07:20    7 21001     0 rmi2c:i2c_slave_write: Slave Write
    Jan 01 21:07:20    7 21001     0 rmi2c:i2c_slave_send: entry
    Jan 01 21:07:20    5 21001     0 rmi2c:i2c_slave_send: Byte 1 is 0x00 '', status 0x1710
    Jan 01 21:07:20    5 21001     0 rmi2c:i2c_slave_send: Byte 2 is 0x00 '', status 0x1710
    Jan 01 21:07:20    5 21001     0 rmi2c:i2c_slave_send: Byte 3 is 0x00 '', status 0x1710
    Jan 01 21:07:20    5 21001     0 rmi2c:i2c_slave_send: Byte 4 is 0x0C '', status 0x1710
    Jan 01 21:07:20    2 21001     0 rmi2c:i2c_slave_write: complete, so do it again Status In 0x106 Out 0x0
    Jan 01 21:07:20    7 21001     0 rmi2c:i2c_slave_wait_forever: write entry iid 12 (CTRREG 0x8000 STSREG 0x0)
    Jan 01 21:07:21    7 21001     0 rmi2c:i2c_slave_wait_forever: write return 0 (CTRREG 0x8000 STSREG 0x1710)
    Jan 01 21:07:21    7 21001     0 rmi2c:i2c_slave_write:i2c_slave_wait_forever: status 0x0
    Jan 01 21:07:21    7 21001     0 rmi2c:i2c_slave_write: Slave Write
    Jan 01 21:07:21    7 21001     0 rmi2c:i2c_slave_send: entry
    Jan 01 21:07:21    5 21001     0 rmi2c:i2c_slave_send: Byte 1 is 0x00 '', status 0x1710
    Jan 01 21:07:21    5 21001     0 rmi2c:i2c_slave_send: Byte 2 is 0x00 '', status 0x1710
    Jan 01 21:07:21    5 21001     0 rmi2c:i2c_slave_send: Byte 3 is 0x00 '', status 0x1710
    Jan 01 21:07:21    5 21001     0 rmi2c:i2c_slave_send: Byte 4 is 0x0C '', status 0x1710
    Jan 01 21:07:21    2 21001     0 rmi2c:i2c_slave_write: complete, so do it again Status In 0x106 Out 0x0
    Jan 01 21:07:21    7 21001     0 rmi2c:i2c_slave_wait_forever: write entry iid 12 (CTRREG 0x8000 STSREG 0x0)
    Jan 01 21:07:21    7 21001     0 rmi2c:i2c_slave_wait_forever: write return 0 (CTRREG 0x8000 STSREG 0x1710)
    Jan 01 21:07:21    7 21001     0 rmi2c:i2c_slave_write:i2c_slave_wait_forever: status 0x0
    Jan 01 21:07:21    7 21001     0 rmi2c:i2c_slave_write: Slave Write
    Jan 01 21:07:21    7 21001     0 rmi2c:i2c_slave_send: entry
    Jan 01 21:07:21    5 21001     0 rmi2c:i2c_slave_send: Byte 1 is 0x00 '', status 0x1710
    Jan 01 21:07:21    5 21001     0 rmi2c:i2c_slave_send: Byte 2 is 0x00 '', status 0x1710
    Jan 01 21:07:21    5 21001     0 rmi2c:i2c_slave_send: Byte 3 is 0x00 '', status 0x1710
    Jan 01 21:07:21    5 21001     0 rmi2c:i2c_slave_send: Byte 4 is 0x0C '', status 0x1710
    Jan 01 21:07:21    2 21001     0 rmi2c:i2c_slave_write: complete, so do it again Status In 0x106 Out 0x0
    Jan 01 21:07:21    7 21001     0 rmi2c:i2c_slave_wait_forever: write entry iid 12 (CTRREG 0x8000 STSREG 0x0)
    Jan 01 21:07:22    7 21001     0 rmi2c:i2c_slave_wait_forever: write return 0 (CTRREG 0x8000 STSREG 0x1710)
    Jan 01 21:07:22    7 21001     0 rmi2c:i2c_slave_write:i2c_slave_wait_forever: status 0x0
    Jan 01 21:07:22    7 21001     0 rmi2c:i2c_slave_write: Slave Write
    Jan 01 21:07:22    7 21001     0 rmi2c:i2c_slave_send: entry
    Jan 01 21:07:22    5 21001     0 rmi2c:i2c_slave_send: Byte 1 is 0x00 '', status 0x1710
    Jan 01 21:07:22    5 21001     0 rmi2c:i2c_slave_send: Byte 2 is 0x00 '', status 0x1710
    Jan 01 21:07:22    5 21001     0 rmi2c:i2c_slave_send: Byte 3 is 0x00 '', status 0x1710
    Jan 01 21:07:22    5 21001     0 rmi2c:i2c_slave_send: Byte 4 is 0x0C '', status 0x1710
    Jan 01 21:07:22    2 21001     0 rmi2c:i2c_slave_write: complete, so do it again Status In 0x106 Out 0x0
    Jan 01 21:07:22    7 21001     0 rmi2c:i2c_slave_wait_forever: write entry iid 12 (CTRREG 0x8000 STSREG 0x0)

    # In Byte 1 is 0x4E statraw 0x308 status 0x0...
    In Byte 2 is 0x16 statraw 0x208 status 0x0...
    In Byte 3 is 0x00 statraw 0x208 status 0x0...
    In Byte 4 is 0x02 statraw 0x208 status 0x0...
    In Byte 5 is 0x00 statraw 0x208 status 0x0...
    In Byte 6 is 0x02 statraw 0x208 status 0x0...
    In Byte 7 is 0x16 statraw 0x208 status 0x0...
    In Byte 8 is 0x00 statraw 0x208 status 0x0...
    Slave Read Stop found after reading 8 bytes status 0x4

    I have saved the entire .tdc file of this run if you would like that also.

    I hope all this helps and is understandable.  I would welcome the chance to discuss this on a telephone.

    Thanks Steve

  • File here if the image does not work: Document.rtf

  • Hello Brad,

    This is getting quite critical now and I have heard no answer since my last several postings.  My company is prepared to send me to Dallas if that is the only solution available.  I personally feel if we could talk over a telephone we could resolve the issue(s) rather expediently.  Either solution is quite acceptable to me provided we can get this up and running. 

    If you would provide steven.stoner@s-a-m.com an email I will reply to you so we can connect. 

    Thanks Steve

  • Steve,

    Sorry, I'm out on vacation this week.

    Brad

  • Hello Brad,

    I hope you had a great vacation.  Things have not changed here at all and our Directors are getting quite frantic.  We really need your assistance in debugging this driver issue.  It would be best with a telephone or Skype/Lync connection.  The latter would be preferable as then you could actually see out screen and speak with us at the same time.  In an earlier message I provided my email contact and if you would use that as a contact then I would be able to send you full telephone details for us/me.  Alternatively, if you would prefer that we come visit you with our hardware/software we would fly to you so we could do this debugging in person.

    Please let me know how you would like to proceed. 

    Thanks so much again for your help.... Steve

  • Steve,

    The behavior you're observing (e.g. Bus Busy not reliably reflecting the bus status) is unexpected. I think you have something configured incorrectly at the chip level, or might potentially have a power issue. Please check a few things:

    1. Please put an oscilloscope on vdd_core as close as possible to the AM335x. Please set the scope to infinite persistence and report back the min and max voltage observed.

    2. Please use CCS and JTAG to grab a clock tree tool dump (i.e. rd1 file) as documented here:

    processors.wiki.ti.com/.../AM335x_Clock_Tree_Tool

    3. Which I2C instance are you using? I would like to see the corresponding pin mux register values for ALL pins of that peripheral, i.e. if a second set of pins has been configured for the same I2C signal, that can cause strange issues.
  • Hello again Brad,

    Thanks for the quick reply.  Here are several of your answers.

    1. vdd_core min – 1.094V  vdd_core max – 1.097V as supplied by Graham Pond

    3. i2c0 is the device we are using as our external I2C bus.

    We are also working on a conference call today if possible.  Hope this helps a bit.

    As always, thank you again for your assistance Brad, I just hope we get to the bottom of this.

    Steve

  • s-a-m_pinMux_Info.ziphello all,

    I am in the same team as Steve and Neal and am working on the same product.Thanks for supporting us. 

    I attach the pinmux files in s-a-m_pinMux_Info.zip.

    For I2C these are unchanged from Beaglebone black for I2C (Based on BSP v574 11Feb16 - file included for reference) .

    FYI we're using "cape" setting 4 ( see cape_profiles)

    For I2C, can you check the settings here - particularly for pulls and slew, in case that should change - though these are the same as on BBB.

       out32(conf_i2c0_sda         , (MODE(0) | RXACTIVE | PULLUDEN | SLEWCTRL));     /* I2C_DATA  */  /* (C17) I2C0_SDA.I2C0_SDA */

       out32(conf_i2c0_scl         , (MODE(0) | RXACTIVE | PULLUDEN | SLEWCTRL));     /* I2C_SCLK  */  /* (C16) I2C0_SCL.I2C0_SCL */

    Regarding the Clock Tree Tool - we can try to obtain that, we have a Lauterbach JTAG debugger.  However, on our current HW rev of our boards, we have an issue on our board that you can maybe advise us on. On pins JTAG_EMU1/3 from the AM335x are unfortunately shorted to GND.  Do you know if this will prevent the CTT running? We can of course try it.

    cheers,

    Paul

  • I2C0 is easy since there is only a single pin-out option.  That means we only have to verify two registers (one for SCL and one for SDA).  Had we been discussing I2C1 or I2C2, there are 3 pin-out options so I would have wanted to check 6 total registers.

    Can you please dump the following registers at run-time:

    • conf_i2c0_sda (0x44E10988)
    • conf_i2c0_scl (0x44E1098C)

    Paul L said:
    Regarding the Clock Tree Tool - we can try to obtain that, we have a Lauterbach JTAG debugger.

    You can use Lauterbach as well.  Download and install the Clock Tree Tool from here:

    http://www.ti.com/tool/clocktreetool

    In the Scripts directory you'll find a cmm script that can be used with Lauterbach.

    Paul L said:
    On pins JTAG_EMU1/3 from the AM335x are unfortunately shorted to GND.

    As long as you can connect with JTAG, you should be able to run the cmm script.  The output of the script is a rd1 file.  Please attach that file to a forum post so I can have a look.  It's just a collection of PRCM registers, but formatted in a way that can be imported into the Clock Tree Tool.

  • One other thing...  Can you please also grab a few I2C register values at run-time:

    • I2C_SYSC (offset 0x10)
    • I2C_PSC (offset 0xB0)
    • I2C_SCLL (offset 0xB4)
    • I2C_SCLH (offset 0xB8)

  • Hello Brad,
    Thanks for the quick reply,  I am going to add 2 files here, bus_speed.c and wait.c.  The routine i2c_reset() in wait.c sets up all those registers for us and we followed what was set.  All our timings look quite good running at 100,000 .  I will get you actual values tomorrow, but as such short notice for this and I have been working on another card, tomorrow is the soonest. 

    Thanks Steve

    bus_speed.c
    /*
     * $QNXLicenseC:
     * Copyright 2008, QNX Software Systems.
     *
     * Licensed under the Apache License, Version 2.0 (the "License"). You
     * may not reproduce, modify or distribute this software except in
     * compliance with the License. You may obtain a copy of the License
     * at: http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" basis,
     * WITHOUT WARRANTIES OF ANY KIND, either express or implied.
     *
     * This file may contain contributions from others, either as
     * contributors under the License or as licensors under other terms.
     * Please review this entire file for other proprietary rights or license
     * notices, as well as the QNX Development Suite License Guide at
     * http://licensing.qnx.com/license-guide/ for other information.
     * $
     */
    
    #include "proto.h"
    
    // these defines taken from OMAP44xx and OMAP35xx TRM
    #define SCLL_BIAS 7
    #define SCLH_BIAS 5
    
    #define I2C_ICLK           4000000UL   /* internal clock for 100K bus speed */
    #define I2C_ICLK_9600K     9600000UL   /* internal clock for 400K bus speed */
    
    int i2c_set_bus_speed(i2c_dev_t *dev, unsigned int speed, unsigned int *ospeed)
    {
    	unsigned long   iclk;
    	unsigned        scll_plus_sclh;
    	int             scll_delta;
    	int             high_adjust;
    	int             low_adjust;
    	int             scll_to_write;
    	int             sclh_to_write;
    
    	if (uiVerbosity >= LOGGING_PROGRESS)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_INFO, "%s:i2c_set_bus_speed: entry target speed %d", pszProgram, speed );
    
        /* This driver support bus speed range from 8KHz to 400KHz
         * limit the low bus speed to 8KHz to protect SCLL/SCLH from overflow(large than 0xff)
         * if speed=8KHz, iclk=4MHz, then SCLL=0xf3, SCLH=0xf5
         */
        if (speed > 400000 || speed < 8000)
    	{
    		if (uiVerbosity >= LOGGING_ERRORS)
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_WARNING, "%s:i2c_set_bus_speed: speed greater than 400000 return -1 %s", pszProgram, strerror(EINVAL));
    		errno = EINVAL;
    		return -1;
    	}
    
    	/* Set the I2C prescaler register to obtain the maximum I2C bit rates
    	 * and the maximum period of the filtered spikes in F/S mode:
    	 * Stander Mode: I2Ci_INTERNAL_CLK = 4 MHz
    	 * Fast Mode:    I2Ci_INTERNAL_CLK = 9.6 MHz
    	 */
    	if (speed <= 100000)
    	{
    	#ifndef VARIANT_j5
    		out16(dev->regbase + AM335x_I2C_PSC, 11);     // The sysclk is 48 MHz in J5 and 96 MHz in OMAP
    	#else
    		out16(dev->regbase + AM335x_I2C_PSC, 23);     // I2Ci_INTERNAL_CLK = 4 MHz
    	#endif
    		iclk = I2C_ICLK;
    		high_adjust = dev->high_adjust_slow;
    		low_adjust = dev->low_adjust_slow;
    		// in standard mode, scll is smaller than (scll_plus_sclh>>1) by 1
    		scll_delta = -1;
    	} else {
    	#ifndef VARIANT_j5
    		out16(dev->regbase + AM335x_I2C_PSC, 4);      // The sysclk is 48 MHz in J5 and 96 MHz in OMAP
    	#else
    		out16(dev->regbase + AM335x_I2C_PSC, 9);      // I2Ci_INTERNAL_CLK = 9.6 MHz
    	#endif
    		iclk = I2C_ICLK_9600K;
    		high_adjust = dev->high_adjust_fast;
    		low_adjust = dev->low_adjust_fast;
    	#ifdef VARIANT_omap4
    		// in fast mode, scll is larger than (scll_plus_sclh>>1) by 1
    		scll_delta = 1;
    	#else
    		// At this point it is unclear whether omap3 also has this relationship
    		// between SCLL and SCLH in fast mode, so we leave it alone for now to
    		// avoid breakage.
    		scll_delta = -1;
    	#endif
    	}
    
    	/* Set clock based on "speed" bps */
    	scll_plus_sclh = (iclk/speed - (SCLL_BIAS + SCLH_BIAS));
    
    	scll_to_write = (scll_plus_sclh>>1) + scll_delta;
    	sclh_to_write = scll_plus_sclh - scll_to_write;
    	scll_to_write += low_adjust;
    	sclh_to_write += high_adjust;
    
    	if (scll_to_write < 0) scll_to_write = 0;
    	if (sclh_to_write <= 2) sclh_to_write = 3;
    
    	out16(dev->regbase + AM335x_I2C_SCLL, scll_to_write);
    	out16(dev->regbase + AM335x_I2C_SCLH, sclh_to_write);
    	dev->speed = iclk / (scll_to_write + SCLL_BIAS + sclh_to_write + SCLH_BIAS);
    
    	if (ospeed)
    		*ospeed = dev->speed;
    
    	return 0;
    }
    
    __SRCVERSION( "$URL: http://svn/product/branches/6.5.0/trunk/hardware/i2c/i2c/bus_speed.c $ $Rev: 390064 $" );
    
    7077.wait.c
    /*
     * $QNXLicenseC: 
     * Copyright 2008, QNX Software Systems.  
     *  
     * Licensed under the Apache License, Version 2.0 (the "License"). You  
     * may not reproduce, modify or distribute this software except in  
     * compliance with the License. You may obtain a copy of the License  
     * at: http://www.apache.org/licenses/LICENSE-2.0  
     *  
     * Unless required by applicable law or agreed to in writing, software  
     * distributed under the License is distributed on an "AS IS" basis,  
     * WITHOUT WARRANTIES OF ANY KIND, either express or implied. 
     * 
     * This file may contain contributions from others, either as  
     * contributors under the License or as licensors under other terms.   
     * Please review this entire file for other proprietary rights or license  
     * notices, as well as the QNX Development Suite License Guide at  
     * http://licensing.qnx.com/license-guide/ for other information. 
     * $
     */
    
    //int first = 1;
    
    #include "proto.h"
    //#include "..\bsp-freescale-mx6q-sabrelite-src\src\hardware\startup\lib\public\arm\mx6x.h"
    
    void i2c_off(i2c_dev_t *dev)
    {
    //	out16(dev->regbase + I2C_CTRREG_OFF, in16(dev->regbase + I2C_CTRREG_OFF) & ~CTRREG_IEN);
    	out16(dev->regbase + I2C_CTRREG_OFF, 0);
    	out16(dev->regbase + AM335x_I2C_STAT, 0x07FFF);
    	if (uiVerbosity >= LOGGING_DEBUG_NORMAL)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG1, "%s:i2c_i2c_off: (CTRREG 0x%X STSREG 0x%X)",
    				pszProgram, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    }
    
    int	iMaster = 0;
    int iReset = 0;
    int	iSlave = 0;
    
    void i2c_reset(i2c_dev_t *dev)
    {
    	int 	timeout = 2000;
    //	int		iDoTwice =1;
    	int		status = in16(dev->regbase + I2C_STSREG_OFF);
    	int		ctrl = in16(dev->regbase + I2C_CTRREG_OFF);
    	if (uiVerbosity >= LOGGING_DEBUG_NORMAL)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG1, "%s:i2c_reset: entry (CTRREG 0x%X STSREG 0x%X)",
    				pszProgram, ctrl, status);
    
    	iMaster = 0;
    	iSlave = 0;
    	if ( ( ctrl & CTRREG_IEN ) && !( status & AM335x_I2C_RESET_ERROR ) && ( iReset++ < 100 ) )
    	{
    //		out16(dev->regbase + AM335x_I2C_CNT, 0);
    		out16( dev->regbase + AM335x_I2C_STAT, status & ( AM335x_I2C_ARDY | AM335x_I2C_NACK  | AM335x_I2C_AL | AM335x_I2C_BF ) );
        	nanospin_ns( 1000 );
    		int statusnew = in16(dev->regbase + I2C_STSREG_OFF);
    		if ( status != statusnew )
    		{
    			printf( "Clear Control 0x%X Status 0x%X to 0x%X\n", ctrl, status, statusnew  );
    			return;
    		}
    		if ( !( statusnew & AM335x_I2C_RESET_ERROR ) )
    		{
    			printf( "No Error Control 0x%X Status 0x%X so return\n", ctrl, statusnew  );
    			return;
    		}
    	}
    	iReset = 0;
    	printf( "Doing reset Control 0x%X Status 0x%X\n", ctrl, status );
    	// Disable interrupts
    //DoTwice:
    	out16(dev->regbase + AM335x_I2C_IE_CLR, 0x0FF); // clear interrupts
    	// Disable DMA
    	out16(dev->regbase + AM335x_I2C_BUF, 0);
    	// Disable test mode
    	out16(dev->regbase + AM335x_I2C_SYSTEST, 0);
    
    	if ( in16( dev->regbase + I2C_CTRREG_OFF) & CTRREG_IEN )
    		out16(dev->regbase + I2C_CTRREG_OFF, 0);
    	out16(dev->regbase + AM335x_I2C_STAT, 0x07FFF );  //in16(dev->regbase + I2C_STSREG_OFF) & AM335x_I2C_RESET );
    //	if ( first )
    	out16(dev->regbase + AM335x_I2C_SYSC, AM335x_I2C_SRST );
    	out16(dev->regbase + I2C_CTRREG_OFF, CTRREG_IEN );
        while ( !(in16(dev->regbase + AM335x_I2C_SYSS) & AM335x_I2C_SYSS_RDONE) && --timeout)
        {
        	nanospin_ns( 1000 );
        }
    	if(!timeout)
    	{
    		if (uiVerbosity >= LOGGING_ERRORS)
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_ERROR, "%s:i2c_reset: entry (CTRREG 0x%X STSREG 0x%X)",
    					pszProgram, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    		printf( "Timeout I2c from reset\n" );
    		exit(1);
    	}
    	out16(dev->regbase+AM335x_I2C_SYSC, AM335x_I2C_CLKACT_SYS | AM335x_I2C_IDLEMODE_SMART | AM335x_I2C_ENAWAKEUP | AM335x_I2C_AUTOIDLE ); //Smart idle mode, Fclock, Enable Wakeup, autoidle
    	/*
    	 * Enabling all wakup sources to stop I2C freezing on
    	 * WFI instruction.
    	 * REVISIT: Some wkup sources might not be needed.
    	 */
    	out16(dev->regbase + AM335x_I2C_WE, AM335x_I2C_WE_ALL );
    	out16(dev->regbase + I2C_CTRREG_OFF, 0 );
    
    	/* Set I2C bus speed */
    //	if ( first )
    	i2c_set_bus_speed( dev, dev->speed, NULL );
    
        /* Set Own Address */
    	out16(dev->regbase + I2C_ADRREG_OFF, dev->own_addr );
    	out16(dev->regbase + AM335x_I2C_SBLOCK, 0 );					// Tell it to only use OA0
    //	printf( "Enable I2c from reset\n" );
    /*
    	if ( first )
    	{
    		first = 0;
    		sleep( 30 );
    	}
    	if ( iDoTwice-- )
    		goto DoTwice;
    */
    	out16(dev->regbase + I2C_CTRREG_OFF, CTRREG_IEN );
    	dev->restart = 0;
    //	delay(10);
    	sleep(3);
    	if (uiVerbosity >= LOGGING_DEBUG_NORMAL)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG1, "%s:i2c_reset: exit (CTRREG 0x%X STSREG 0x%X)",
    				pszProgram, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    }
    
    int i2c_wait_bus_not_busy(i2c_dev_t *dev)
    {
        unsigned        tries = 1000000;
    	if (uiVerbosity >= LOGGING_DEBUG_FINE)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2, "%s:i2c_wait_bus_not_busy: entry (CTRREG 0x%X STSREG 0x%X)",
    				pszProgram, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    	if(dev->restart)
    	{
    		if (uiVerbosity >=  LOGGING_DEBUG_FINE)
    			slogf( _SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    					"%s:i2c_wait_bus_not_busy: dev->restart != 0 so return 0", pszProgram);
    		return 0;
    	}
    	while (in16(dev->regbase + I2C_STSREG_OFF) & STSREG_IBB)
    	{
    		if (tries-- == 0)
    		{
    			if (uiVerbosity >=  LOGGING_DEBUG_FINE)
    				slogf( _SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    						"%s:i2c_wait_bus_not_busy: wait bus idle failed (CTRREG 0x%X STSREG 0x%X)",
    						pszProgram, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    			/* reset the controller to see if it's able to recover*/
    			i2c_reset(dev);
    			//try again to see if it's OK now after reset
    			if(in16(dev->regbase + I2C_STSREG_OFF) & STSREG_IBB)
    			{
    //				delay(1);
    				if (uiVerbosity >=  LOGGING_DEBUG_FINE)
    					slogf( _SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    							"%s:i2c_wait_bus_not_busy: STSREG_IBB still set, return -1 (CTRREG 0x%X STSREG 0x%X)",
    							pszProgram, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    				return -1;
    			}
    			break;
    		}
    	}
    	if (uiVerbosity >= LOGGING_DEBUG_FINE)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2, "%s:i2c_wait_bus_not_busy: return 0 (CTRREG 0x%X STSREG 0x%X)",
    				pszProgram, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    	return 0;
    }
    
    #include <sys/time.h>
    #include <time.h>
    
    #ifdef sws
    uint32_t i2c_master_wait_status(i2c_dev_t *dev)
    {
    	uint16_t	status1;
    
    	iMaster = 1;
    	if (uiVerbosity >= LOGGING_DEBUG_FINE)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2, "%s:i2c_master_wait_status: entry (CTRREG 0x%X STSREG 0x%X)",
    				pszProgram, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    /*
        struct sigaction sa;
        int s, flags = 0;
        sigemptyset(&sa.sa_mask);
        sa.sa_flags = 0;
        sa.sa_handler = sigintHandler;
    */
        struct timespec start, stop, temp, request;
    	clock_gettime( CLOCK_MONOTONIC, &start);
    	do
    	{
    		//if ( (status = in16(dev->regbase + I2C_STSREG_OFF)) & STSREG_IIF )
    		if ( (status1 = in16(dev->regbase + I2C_STSREG_OFF)) & AM335x_I2C_STAT_MASK )
    		{
    			// Clear the interrupt
    //			out16(dev->regbase + I2C_STSREG_OFF, ( status1 & AM335x_I2C_INT_MASK ) );
    //			out16(dev->regbase + I2C_STSREG_OFF, status = in16(dev->regbase + I2C_STSREG_OFF) & ~(STSREG_IIF));
    //				InterruptUnmask(dev->intr, dev->master_iid);
    			if (uiVerbosity >= LOGGING_DEBUG_FINE)
    				slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2, "%s:i2c_master_wait_status: STSREG_IIF set return STSREG 0x%X (CTRREG 0x%X STSREG 0x%X)",
    						pszProgram, status1, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    //			timer_delete(timer_id);
    			iMaster = 0;
    			return status1;
    		}
    		request.tv_sec  = 0;
    		request.tv_nsec = 1000;
    //		clock_nanosleep(CLOCK_MONOTONIC, 0, &request, NULL);
    		clock_gettime( CLOCK_MONOTONIC, &stop);
    		if ((stop.tv_nsec-start.tv_nsec)<0)
    		{
    			temp.tv_sec = stop.tv_sec-start.tv_sec-1;
    			temp.tv_nsec = 1000000000+stop.tv_nsec-start.tv_nsec;
    		}
    		else
    		{
    			temp.tv_sec = stop.tv_sec-start.tv_sec;
    			temp.tv_nsec = stop.tv_nsec-start.tv_nsec;
    		}
    	} while( !temp.tv_sec && temp.tv_nsec < 250000000 );
    	//timeout case, we need reset
    //Timeout1:
    	if (uiVerbosity >=  LOGGING_ERRORS)
    		slogf( _SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_WARNING,
    				"%s:i2c_master_wait_status: Timeout, reset, return 0 (CTRREG 0x%X STSREG 0x%X)",
    				pszProgram, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    	i2c_reset(dev);
    	return 0;
    }
    #endif
    
    const char	szWrite[] = "write";
    const char	szRead[] = "read";
    
    uint32_t i2c_slave_wait_forever(i2c_dev_t *dev, int interrupt)
    {
    	int	status, ctrl;
    	int			iid, interr = EOK;
     //   int statusold = 0;
        char *	pszMode;
    
        if ( iSlave == interrupt )
        {
        	iSlave = 0;
        	out16(dev->regbase + I2C_CTRREG_OFF, CTRREG_IEN );
        }
        switch( interrupt )
        {
        case AM335x_I2C_XRDY:
        	iid = dev->slave_write_iid;
        	pszMode = szWrite;
        	break;
        case AM335x_I2C_RRDY:
        	iid = dev->slave_read_iid;
        	pszMode = szRead;
        	break;
        default:
        	return I2C_STATUS_ERROR;
    	}
    //	printf( "%s Status = 0x%X\n", pszMode, in16(dev->regbase + I2C_STSREG_OFF) );
    	/* Wait forever until we get an interrupt */
    	if (uiVerbosity >= LOGGING_DEBUG_FINE)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2, "%s:i2c_slave_wait_forever: %s entry iid %d (CTRREG 0x%X STSREG 0x%X)",
    				pszProgram, pszMode, iid, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    	/*Wait for an interrupt event */
    Retry:
    	while ( iSlave || !( ( status = in16(dev->regbase + I2C_STSREG_OFF)) & STSREG_IAAS) ||
    			!( ( ctrl  = in16(dev->regbase + I2C_CTRREG_OFF) ) & CTRREG_IEN) || iMaster ||
    			(ctrl & CTRREG_MSTA ) || !( status & interrupt ) )
    	{
    		struct timespec request;
    		request.tv_sec  = 0;
    		request.tv_nsec = 2000; // 2 microseconds (although it is always at least 3 milliseconds)
    		clock_nanosleep(CLOCK_MONOTONIC , 0, &request, NULL );
    /*
    		usleep(2);
    		interr = InterruptWait_r(0, NULL);
    		if (uiVerbosity >=  LOGGING_DEBUG_FINE)
    			slogf( _SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    					"%s:i2c_slave_wait_forever:InterruptWait_r: 0x%X %s", pszProgram, interr, strerror(interr));
    */
    		ctrl = in16(dev->regbase + I2C_CTRREG_OFF );
    		if ( iMaster || (ctrl & CTRREG_MSTA ) )
    		{
    			interr = EOK;
    			if (uiVerbosity >=  LOGGING_DEBUG_FINE)
    				slogf( _SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    						"%s:i2c_slave_wait_forever: %s Interrupt for master so retry", pszProgram, pszMode);
    			continue;
    		}
    		if ( !( ctrl & CTRREG_IEN) )
    			continue;
    		if ( !iMaster && !iSlave && ( status & AM335x_I2C_ERROR) )
    		{
    			if (uiVerbosity >= LOGGING_ERRORS)
    				slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_WARNING, "%s:i2c_slave_wait_forever: error return 0x%X", pszProgram, status);
    			i2c_reset( dev );
    			continue;
    		}
    /*
    		if ( statusold != status )
    		{
    			printf( "%s INTSET = 0x%X INTCLR = 0x%X Control = 0x%X Status = 0x%X\n", pszMode, in16(dev->regbase + AM335x_I2C_IE_SET), in16(dev->regbase + AM335x_I2C_IE_CLR), ctrl, statusold = status );
    			if ( ( status & AM335x_I2C_BB ) && !( ctrl & ( AM335x_MST | AM335x_TRX ) ) )
    			{
    				ctrl = in16(dev->regbase + AM335x_I2C_DATA ) & 0x0FF;
    				printf( "%s Just read 0x%X\n", pszMode, ctrl );
    				if ( !( in16( dev->regbase + AM335x_I2C_SBLOCK ) & AM335x_OAE0 ) )
    				{
    					printf( "%s OAE0 bit not set so setting\n", pszMode );
    //	       			out16(dev->regbase + AM335x_I2C_SBLOCK, 0 );			// Tell it to only use OA0
    	       			out16(dev->regbase + AM335x_I2C_SBLOCK, AM335x_OAE0 );			// Tell it to only use OA0
    	       		}
    	       	}
    		}
    */
    	}
    	/* Clear the interrupt */
    	/* If an interrupt is pending */
    //	InterruptUnmask(dev->intr, iid);
    //ss		out16(dev->regbase + I2C_STSREG_OFF, in16(dev->regbase + I2C_STSREG_OFF) & AM335x_I2C_INT_MASK );
    //		out16(dev->regbase + I2C_STSREG_OFF, in16(dev->regbase + I2C_STSREG_OFF) & AM335x_I2C_RESET ) ; //AM335x_I2C_INT_MASK );
    	//	out16(dev->regbase + I2C_STSREG_OFF, in16(dev->regbase + I2C_STSREG_OFF) & ~(STSREG_IIF));
    	if ( iSlave )
    		goto Retry;
    	iSlave = interrupt;
    	if (uiVerbosity >= LOGGING_DEBUG_FINE)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2, "%s:i2c_slave_wait_forever: %s return 0 (CTRREG 0x%X STSREG 0x%X)",
    				pszProgram, pszMode, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    	return 0;
    }
    
    static inline i2c_status_t i2c_wait_busy(i2c_dev_t *dev)
    {
    	//wait for 500us
    	int timeout = 5000;
    	if (uiVerbosity >= LOGGING_DEBUG_FINE)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2, "%s:i2c_wait_busy: entry (CTRREG 0x%X STSREG 0x%X)",
    				pszProgram, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    	while(!(in16(dev->regbase + I2C_STSREG_OFF) & STSREG_IBB) && timeout--)
    	{
    //		if (uiVerbosity >= LOGGING_DEBUG_FINE)			// This is overkill
    //			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2, "%s:i2c_wait_busy: STSREG 0x%X", pszProgram, reg);
    		nanospin_ns(100);
    	}
    	if(timeout<=0)
    	{
    		if (uiVerbosity >= LOGGING_DEBUG_FINE)
    			slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2,
    					"%s:i2c_wait_busy: timed out (CTRREG 0x%X STSREG 0x%X), reset and return I2C_STATUS_ERROR",
    					pszProgram, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF));
    		i2c_reset(dev);
    		return (I2C_STATUS_ERROR);
    	}
    	if (uiVerbosity >= LOGGING_DEBUG_FINE)
    		slogf(_SLOGC_SNELL_IQMIT_I2C_DRIVER, _SLOG_DEBUG2, "%s:i2c_wait_busy: (CTRREG 0x%X STSREG 0x%X) return 0",
    				pszProgram, in16(dev->regbase + I2C_CTRREG_OFF), in16(dev->regbase + I2C_STSREG_OFF) );
    	return (0);
    }
    
    __SRCVERSION( "$URL: http://svn/product/branches/6.5.0/trunk/hardware/i2c/i2c/wait.c $ $Rev: 408944 $" );
    

  • hi Brad
    I will be able to get the I2C_xxx registers dumped out shortly.

    But I tried to access these two:
    conf_i2c0_sda (0x44E10988)
    conf_i2c0_scl (0x44E1098C)
    but the QNX Momentix debugger shows ????? for these addresses. I may be missing some mapping ie mmap_device_io() etc?

    We can look at Lauterbach a this end tomorrow, I'm working remotely today.
  • just adding link to the interrupt based work I've been doing.
    e2e.ti.com/.../533394
  • I have got some of the register values after start up: SYSC=0x215 PSC=0xb SCLL=0xf SCLL=0xd

    I have not managed to read these values via either either in32(conf_i2c0_sda ); etc or *(conf_i2c0_sda ) (or in16() ) without segfault. Is th
    ere some example of reading these? All I can see in the BSP is a write access during pinmux setup. Perhaps I should try and read these from the BSP ?
  • Paul L said:
    SYSC=0x215

    There are a lot of power-management features activated in this configuration.  For the time being, I would like to disable those power management features so we can be sure they're not somehow related.  Please write SYSC=0x00000008.

    Paul L said:
    PSC=0xb

    This takes the 48 MHz input clock to the I2C and divides it by 12, resulting in 4 MHz as your prescaled clock.  However, Section 21.3.9 "Prescaler (SCLK/ICLK)" in the TRM recommends using ICLK = 24 MHz for F/S operation.  I recommend instead writing PSC=1 to achieve that.  Correspondingly you'll need to adjust your I2C_ICLK definition in bus_speed.c to update your calculation of SCLL and SCLH.

  • Hi, I managed to read out those registers

    (For ref:

    #define AM335X_CTRL_BASE                   0x44E10000
    #define AM335X_CTRL_BASE_SIZE              0x00002000
    #define conf_i2c0_scl                 0x098C
    #define conf_i2c0_sda                 0x0988

     mmap_device_memory(NULL,  AM335X_CTRL_BASE_SIZE...AM335X_CTRL_BASE  );  etc, then get the value via

     *(uint32_t*) (ctrlbase + conf_i2c0_sda) )

    conf_i2c0_sda=0x60

    conf_i2c0_scl=0x60

    0x60 :

    bit6==1 slow slew rate selected

    Bit5==1 (RX enabled)

    Bit4==0:Pulldown is selected.

    Bit3==0: Pullup/down is enabled.

    (I am a bit suprised the pin is set for pulldown on I2C pins, where the active level is LOW -this is the value inherited from the BSP.) However, we have 10k pullups on the board so guess the on chip pulls are much weaker so this is probably not an issue

    Also, is the slew control ok, given the clock speed is 100kHz?

    Regarding JTAG setup and CTT: I have installed CTT, and also got the LauterBach T32 tool ready for use. What we are missing is a header adaptor between our board (2mm pitch 20pin) and 2.54mm pitch of the LB pod connector. I have a HW guy here running around trying to get that connected for me.

    Until I get that, I will check the SYSC and PSC registers as per Brad's post.

  • Paul L said:
    bit6==1 slow slew rate selected


    Paul L said:
    Also, is the slew control ok, given the clock speed is 100kHz?

    All IOs should be used with fast slew rate. All the timings we provide in the data manual SPRS717J (see section 7.1.7 page 116) are for fast slew rate (ie slewctrl = 0).

    Paul L said:

    conf_i2c0_sda=0x60
    conf_i2c0_scl=0x60
    0x60 :
    bit6==1 slow slew rate selected
    Bit5==1 (RX enabled)
    Bit4==0:Pulldown is selected.
    Bit3==0: Pullup/down is enabled.

    From what I have see from the different Linux device tree for the different AM335x based board (BBB, EVM, SK, custom boards,..etc) the below settings were used for I2C0 (conf_i2c0_sda/conf_i2c0_scl):
    bit6== 0 fast slew rate selected
    Bit5==1 (RX enabled)
    Bit4==1:Pullup is selected.
    Bit3==0: Pullup/down is enabled.

    For example for Linux on BBB see:
    lxr.free-electrons.com/.../am335x-bone-common.dtsi
    lxr.free-electrons.com/.../am33xx.h

    A.

  • I completely agree with Anthony.  The pinmux registers for I2C0 should be set to 0x30.

  • Pinmux set to 0x30 now, from logs:-

    ~~~~~ i2c_send: conf_i2c0_sda=0x30 conf_i2c0_scl=0x30

    ~~~~~ i2c_send: SYSC=0x8 PSC=0x1 SCLL=0x73 SCLL=0x71

    I've checked clk is at 100kHz on scope.

    I don't know why the AM335x BSP has values of 0x60 for the pinmux, perhaps for some reason on BBB that was reqd (i2c0 is for the Board ID EEPROM 24LC32 device ). Thanks for confirming we need to change that, I will update our BSP and check that code in.

    With this change, running the polling driver (with verbosity 0) just now it looks like the original problem exists.

    I would now like to spend some time on the interrupt driver to see what happens there.

    ................

    read Status = 0x0
    In Byte 1 is 0x0E statraw 0x308 status 0x0...
    In Byte 2 is 0x23 statraw 0x208 status 0x0...
    In Byte 3 is 0x00 statraw 0x208 status 0x0...
    In Byte 4 is 0x02 statraw 0x208 status 0x0...
    In Byte 5 is 0x00 statraw 0x208 status 0x0...
    In Byte 6 is 0x05 statraw 0x208 status 0x0...
    In Byte 7 is 0x23 statraw 0x208 status 0x0...
    In Byte 8 is 0x00 statraw 0x208 status 0x0...
    In Byte 9 is 0x00 statraw 0x208 status 0x0...
    In Byte 10 is 0x23 statraw 0x208 status 0x0...
    In Byte 11 is 0x08 statraw 0x208 status 0x0...
    Slave Read Stop found after reading 11 bytes status 0x4   <<<<<<<<<<< ARDY
    read Status = 0x0
    In Byte 1 is 0x0E statraw 0x1308 status 0x1000...
    In Byte 2 is 0x23 statraw 0x308 status 0x0...
    In Byte 3 is 0x00 statraw 0x208 status 0x0...
    In Byte 4 is 0x02 statraw 0x208 status 0x0...
    In Byte 5 is 0x00 statraw 0x208 status 0x0...
    In Byte 6 is 0x05 statraw 0x208 status 0x0...
    In Byte 7 is 0x23 statraw 0x208 status 0x0...
    In Byte 8 is 0x00 statraw 0x1718 status 0x1400...  <<<<<<<<<<<<<<<<<<<<<<<<< bb| xudf|aas|bf |xrdy | rrdy   slave RX and TX together !!!!
    In Byte 9 is 0x00 statraw 0x1618 status 0x1400...
    In Byte 10 is 0x24 statraw 0x1618 status 0x1400...
    In Byte 11 is 0x08 statraw 0x1618 status 0x1400...
    Fake successful read of 11 bytes <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< missing slave read stop {PIL}
    No Error Control 0x8000 Status 0x1610 so return   <<<<<<<<<<<<<<<<<< BB | AAS | BF | XRDY
    No Error Control 0x8000 Status 0x1610 so return
    No Error Control 0x8000 Status 0x1610 so return
    No Error Control 0x8000 Status 0x1610 so return
    No Error Control 0x8000 Status 0x1610 so return

  • Whenever possible, these types of logs are far more useful/meaningful when provided along with a corresponding capture from a logic analyzer. I need the logic analyzer to have appropriate context of what's happening.
  • I strongly recommend against using the TI I²C peripheral in slave or multimaster mode if you care at all about reliability. I've done extensive testing with it and noticed that various kinds of protocol errors (the simplest being a negative pulse on SDA) cause its state machine to lock up. There's nothing visible about this in registers, and "bus free" will continue to track start and stop sequences, but it will not respond to any of its slave addresses nor start any new transaction in master mode.

    Note that TI is not exceptional here, I've noticed that I²C controllers from multiple manufacturers of microcontrollers and SoCs are buggy as *** (broadcom and ST come to mind).

  • I can't comment on the previous post, but it is an interesting observation.

    In the meantime, for a concrete example fo what we see, here is the log / screenshot showing the timing in question and where things go wrong - XRDY comes on during slave receive last couple of bytes. This is intermittent, but no recoverable and prevents us setting up our session with the gateway.

    I have send full logs and source code to TI directly by email, AnBer can pass this onto other TI staff if reqd. So I am not posting that here.

  • Is there any predictability with respect to exactly when the failures happen?  Or does it operate fine for some random period of time and then suddenly you see this behavior?

    Looking at the specific example you just posted, I see that Byte 10 indicates I2C_IRQSTATUS_RAW = 0x1718.  Bit 8 (Bus Free) is interesting, i.e. this indicates that the peripheral thinks it has observed a stop condition.  Now of course, I don't see anything like that in your logic analyzer.  Sometimes, however, these things need to be viewed on a scope.  Can you post a couple screenshots taken with a scope?  Please probe near the AM335x as much as possible.  A few random shots (i.e. ones that are working ok) are good for starters, but ideally I would love to get some scope screenshots from a failed transfer.

  • One other thought, just as a basic debug test, have you tried further reducing the bus frequency to see if that has any impact on this issue?
  • AnBer has a full set of logs + src code.

    Not tried slower clk speed yet, obtaining traces has consumed a lot of time.

    It doesn’t always trigger.

    There are 2 scenarios – clk line gets held low.

    -          One is the “fake” case where XRDY etc bits come on during slave RX. This is what we’ve been discussing so far. See “fake4_summary.PNG”

    -          The other is “nofake” where the xsaction seemed to finish, but clk is also held low . See scenario in No Fake in zip file.

     If there is anything specific you need from traces I can get it, given time. The tricky part is getting the scope to trigger just where we want to show details.

    I have set up 2 GPIO test points available  TI_24aug_scope_logs.zipfor this purpose, they can be triggered on any events we define in the driver code.

    Scope traces:

    yellow SCL
    grn SDA
    blu - TP22 (gpio) --> slav high after 1st byte: goes low next time while loop exited
    pink TP23 (gpio)   --> slav rd error triggered

    Pink pulse is where slave RX mucks up.

     

    Why does the clock stop here? This is SLV mode, so gateway is clocking, but what is the AM335x I2c doing here?

    Ch1 yellow = SCL

    Ch2 blue= TP22  set to 1 when 1st byte is read, ,reset when we exit the while slave read while polling

    Ch3 pink = TP23 set to 1 when we get “S-A-M problem” - reset to 0 upon timeout “faked….”

     

    i2c_slave_recv ()

    …..

            while ( iLen )

            {

                    while ( --timeout && ( ( ( status = in16(...STATRAW) ) & AM335x_I2C_SLV_RCV ) != AM335x_I2C_SLV_RCV &&

                                    !( status & ( AM335x_I2C_ERROR | AM335x_I2C_ARDY ) ) ) )

                                    { }

                    TP22_LOW;

                    If timed out (“fake”): TP23_LOW;

                    // read byte

    ….

                     If(send 1st byte)

                    {

                    TP22_HIGH;   // indicate start of SLV RD, 1st byte

                    }

                    char cByte = buf[iCount++] = in16(dev->regbase + I2C_DATREG_OFF) & 0xFF;

                     out16(dev->regbase + AM335x_I2C_STAT, status & ( AM335x_I2C_RRDY | AM335x_I2C_BF ) );

                    iLen--;

                     if(status & (AM335x_I2C_XRDY|AM335x_I2C_XUDF))

                                    {

                                     TP23_HIGH;  // SLV RX problem triggered

                                    }