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.

I2C tedious

Hi, folks,

I encountered a lot of bizarre problems and questions when using C2000's IIC module.

And after struggling for a long time, it's time to the conclusion...

1. 

I thought that, is the following statement stands when using IIC module, is it true?

At each session: start condition --> whatever else --> stop condition, afterwards, I must use IRS=0; IRS=1;, in order to start another new session?

2.

At least this IIC module, is out of normal, for example, although in a sense is reasonable to IC/register's point of view, but in another point of view of trying

to programming this IIC module, it's hard to overcome to let IIC work properly.

"TX interrupt is always preceding AAS interrupt to occur at the very beginning of enabling IIC, and no way to overcome by setting IIC registers, instead, software only".

How should I do?

3.

I performed a write and then a read: MOD=0x6E20, MOD=0x6C20.

But I still stuck on the problem: each time I issued a write:MOD=0x6E20, I have no idea why clock is still held low by master since stop condition didn't occur yielding the read:MOD=0x6C20 cannot execute. (NOTE. acks are issued, ack bit is low by slave and then high plus the last nack one, data bus high afterwards, but clock still low, 400KHz). Why inconsistency?

Is anybody kindly to help me this........and another curcial one:

4.

IIC module might sometimes halt in the course of IIC communication. It can sometimes run well in this "system communication test", but it will sometimes be bus lowed and stuck in the same test surroundings. why is it so vulnerable? How do I keep ti alive?

5. The interrupt code did occur: code 0, in which condition will it happen?

Another one, if events has priorities to report to user, that is, in ISR, multiple events queued and the most high priority will manifest/clear first.

If it were true, I suggest that we can have a better IIC module by without being programmable, i.e., ASIC type.

6. It's time to update the IIC datasheep to let it more readable and unambiguous.

. It is must have: some customers seriously suggested since philips' do.

The interrupt events table.

int \ event                     (Start)          (Addr)          (R/W)             (DAT)              (N / ACK)      (Restart / Stop)

AL                                    V                     V                   V                    V                        V                           x

NACK                            x

ARDY                     absolutely not

XRDY                       it depends

RRDY                    something like that

SCD

AAS

 

 

 

And BTW, till now, is there any C2000 I2C module's bugs or unreasonable registers/parameters usage were proposed?

Thanks in advance for your answers.

 

  • Hi, folks,

    I have so many questions about this IIC module.......

    7. NACK either told Master resend or told Slave stop to send.

    In the first case, how do I know which data got to resend when using FIFO? Moreover, how do I recover to resend the succeeding unsent data?

    In words, think about the answer, IIC module may automatically resend data without user intervention, is it right? Then, why should I need to know whether or not NACK,

    STOP  condition occurring or not takes care of that regarding what NACK reveals, isn't it?

    Thanks in advance again in that to help me clarify these questions.

     

     

  • 8.

    In non-FIFO mode, during Master transmission, Master got a NACK, which means resent the last byte you sent.

    2 considerations:

    a) if NACK INT is meaningful, which means I must prepare the lost byte and resent it again.

    Since COUNT was set at the outset and its content copied into internal counter, which means, I can't do anything recovery (e.g., add 1 to COUNT) since internal counter could be updated until the STOP condition occurred.

    b) So, IIC module automatically does the recovery is preferred, what NACK used for?

  •  

    Hi, all,

    This is a share.

    If it is not allowable to post an entire code here, please supervisor help me to remove it. Thanks.

    I post an IIC driver code (master&slave) for reference if you want to figure out how this IIC works and why is it so wierd.

    This code is rarely valuable because, only receivers may work fine and I have given up trying transmitters to work correctly.

    At least I thought, it may decrease your cost of time trying to find out reasons/workaround as to obtain a flawless running IIC.

    I thought, we usually use IIC for fault-tolerance data, e.g., temp, rpms, vol, ..., so, it's fine.

    I suggest that after reading the IIC module spec, before to write your code, you may trace this code to have more idea/awareness to write.

    The only reason here I dare to post and speak is that I cost a lot of time, office time, weekends, and midnights to beg it done. Hope that my time will be your cofactor.

     

     

    //
    // FILE:    IIC_MasterSlave.c
    //
    // TITLE:   DSP2802x IIC Master/Slave API

    #include ".\Instance_Common\DSP2802x_Examples.h"     // Device Headerfile and Examples Include File

    // I use piccolo as master, ezdsp as slave with the same code ("xxxxx" marked to altered).
    // FIFO doesn't work because spec says nothing
    // It's funny, to use gpios is far more simpler than use this module. Why i suffer this.
    // In Slave transmitter mode, fatal fault of the first one dirty data. Else, slave would halt, bus dead.
    // Slave transmission will soon terminated, why, no nack.

    interrupt void iic_int1a_isr(void);
    interrupt void iic_int2a_isr(void);
    void IIC_Driver(void);


    void main(void){
        InitSysCtrl();
        InitI2CGpio();
        DINT;
        InitPieCtrl();
        IER = 0x0000;
        IFR = 0x0000;
        InitPieVectTable();

        EALLOW; // This is needed to write to EALLOW protected registers

        PieVectTable.I2CINT1A = &iic_int1a_isr;
        PieVectTable.I2CINT2A = &iic_int2a_isr;

        EDIS;   // This is needed to disable write to EALLOW protected registers

        // Enable I2C interrupt 1/2 in the PIE: Group 8 interrupt 1/2
        PieCtrlRegs.PIEIER8.bit.INTx1 = 1;
        PieCtrlRegs.PIEIER8.bit.INTx2 = 1;

        // Enable CPU INT8 which is connected to PIE group 8
        IER |= M_INT8;
        EINT;

        // Start of the IIC Process
        IIC_Driver();
    }

     

    // Begin of IIC driver API =====================================================
    #define TX_MAX_LEN 0x0A                     // To define the IIC's (maximum) size of buffer for data transmission
    #define RX_MAX_LEN 0x20                     // To define the IIC's (maximum) size of buffer for data reception
    #define TIMEOUT 30000                        // at least 35ns delay for a count in 60MHz. (3000, 100us), (30000, 1ms)


    //-----------
    #if 0 // (0: piccolo, 1: ezdsp) // xxxxx
    #ifndef F280x
    #define F280x
    #endif
    #else
    #ifndef F2802x
    #define F2802x
    #endif
    #endif

    #ifdef F280x
    #define ARBL AL
    #define CLK_VAR 9
    #else
    #define CLK_VAR 5
    #endif
    //--------------


    #define IIC_MASTER_ADDR 0x2C//0x41 // xxxxx
    #define IIC_SLAVE_ADDR 0x2D//0x0C // xxxxx


    #if (!defined(bool) && !defined(true) && !defined(false))
        #define bool int
        #define true 1
        #define false 0
    #endif


    #if !defined(byte)
        #define byte unsigned char
    #endif


    #if !defined(size_t)
        #define size_t unsigned int
    #endif


    // variable number of commands with variable length (deterministic)
    // instead, using another generated table when using variable values
    const char* g_outgoing_data[]={
        // _______________________________________________________
        // ------------------- add commands here -----------------
        // _______________________________________________________

        "\x05\x01\x00\x01\x02\x03",             // {length, cmd1, no response, dat1, dat2, dat3}, length=5
        "\x05\x02\x01\x02\x04\x06",             // {length, cmd2, need response, dat1, dat2, dat3}, length=5
        "\x03\x03\x00\xff",                     // {length, cmd3, no response, dat1}, length=3
        "\x0A\x04\x09\x08\x07\x06\x05\x04\x03\x02\x01", // {length, cmd4, response, dat1~dat8}, length=10
        "\x00\x05",                             // {length, cmd4}, length=0
        "\xFF\x06"                              // {length, cmd5}, length is unknown
    };

    byte g_incoming_storage[RX_MAX_LEN];        // to store received data

    bool g_is_master=false;                     // true: master, false: slave
    bool g_is_slave_be_tx=false;                // it is a slave transmitter only if this variable is true
    bool g_use_fifo=false;                      // true: fifo, false: normal
    const byte *g_ping_space;                   // the commands pointer to be processed
    byte *g_pong_space=g_incoming_storage;      // the data pointer to be processed
    size_t g_ping_cnt=0, g_pong_cnt=0, g_ptr=0, g_tic_cnt=TIMEOUT, g_tr_session_flag=0; // the number of data & its index pointer to buffer

    bool g_isrst_arbl=false;                    // status for interrupts
    bool g_isrst_is_nack=false;
    bool g_irst_txdata_ready=false, g_isrst_data_done=false;

    bool g_dummy_read=true;                     // the conditions only read from slave since slave has stream data forwards

    size_t g_repeat_start=0;                    // nonzero to present data remains


    #define WAITING_ACTION(action, d_us) (action,DELAY_US(d_us))

    // MS: master & slave, LP: loop, MA: master, SL: slave, RM: repeat start mode, T: transmitter, R: receiver, F: fifo, N: not.
    #define MSLP_WAIT_BUS_IDLE  while(I2caRegs.I2CSTR.bit.BB)
    #define MS_CHECK_BUS_FREE   (I2caRegs.I2CSTR.bit.SCD)
    #define MS_TRY_RELEASE_BUS  (I2caRegs.I2CSTR.bit.BB=1) // doesn't mean bus hence free (held by opposite). uncertainty
    #define MS_IS_BUS_IDLE      (!I2caRegs.I2CSTR.bit.BB)
    #define MS_START_IIC_RUN    (I2caRegs.I2CMDR.all=0x0020) // Take I2C out of reset
    #define MS_STOP_IIC_RUN     (I2caRegs.I2CCNT=0,I2caRegs.I2CFFTX.all=0,I2caRegs.I2CFFRX.all=0,I2caRegs.I2CMDR.all=0x0000) // Pull up and hold and global reset the I2CSTR reg & the counter regs
    #define MS_IIC_TOTALLY_RESET (MS_STOP_IIC_RUN,MS_START_IIC_RUN)
    #define MST_TRANSMIT_FAILURE (I2caRegs.I2CMDR.bit.MST?I2caRegs.I2CSTR.bit.NACK:!I2caRegs.I2CSTR.bit.NACK)
    #define MST_MAR_NRM_SET_COUNTER(x) (I2caRegs.I2CCNT=(x))
    #define MALP_IS_FORCE_BUS_FREE_SUCCESS (WAITING_ACTION(I2caRegs.I2CMDR.bit.STP=1,50),!I2caRegs.I2CMDR.bit.STP)
    #define MA_END_OF_SESSION   (I2caRegs.I2CMDR.bit.STP=1) // end a session gracefully
    #define MA_TRANSMIT_MODE    (I2caRegs.I2CMDR.bit.TRX=1)
    #define MA_RECEIVE_MODE     (I2caRegs.I2CMDR.bit.TRX=0)
    #define MARMT_IS_A_BYTE_SENT (I2caRegs.I2CSTR.bit.ARDY)
    #define FT_FIFO_RESET       (I2caRegs.I2CFFTX.all=0x0040)
    #define FT_FIFO_BEGIN       (I2caRegs.I2CFFTX.all=0x4060,I2caRegs.I2CFFTX.bit.TXFFINTCLR=1)
    #define FT_FIFO_RUN         (I2caRegs.I2CFFTX.all=0x6060,I2caRegs.I2CFFTX.bit.TXFFINTCLR=1)
    #define FR_FIFO_RESET       (I2caRegs.I2CFFRX.all=0x0050)
    #define FR_FIFO_BEGIN       (I2caRegs.I2CFFRX.all=0x0070,I2caRegs.I2CFFRX.bit.RXFFINTCLR=1)
    #define FR_FIFO_RUN         (I2caRegs.I2CFFRX.all=0x2070,I2caRegs.I2CFFRX.bit.RXFFINTCLR=1)
    #define FT_EN_FIFO_INT      (I2caRegs.I2CFFTX.bit.TXFFIENA=1, I2caRegs.I2CFFTX.bit.TXFFINTCLR=1)
    #define FT_DEN_FIFO_INT     (I2caRegs.I2CFFTX.bit.TXFFIENA=0)
    #define EN_ALL_INT          (I2caRegs.I2CIER.all=0x7F/*,I2caRegs.I2CFFTX.bit.TXFFIENA=1,I2caRegs.I2CFFRX.bit.RXFFIENA=1*/)
    #define DEN_ALL_INT         (I2caRegs.I2CIER.all=0x00/*,I2caRegs.I2CFFTX.bit.TXFFIENA=0,I2caRegs.I2CFFRX.bit.RXFFIENA=0*/)
    #define EN_AL_INT           (I2caRegs.I2CIER.bit.ARBL=1) // 280x: AL, 2802x: ARBL.
    #define DEN_AL_INT          (I2caRegs.I2CIER.bit.ARBL=0) // 280x: AL, 2802x: ARBL.
    #define EN_NACK_INT         (I2caRegs.I2CIER.bit.NACK=1)
    #define DEN_NACK_INT        (I2caRegs.I2CIER.bit.NACK=0)
    #define EN_ARDY_INT         (I2caRegs.I2CIER.bit.ARDY=1)
    #define DEN_ARDY_INT        (I2caRegs.I2CIER.bit.ARDY=0)
    #define NF_EN_RECEIVE_INT   (I2caRegs.I2CIER.bit.RRDY=1)
    #define NF_DEN_RECEIVE_INT  (I2caRegs.I2CIER.bit.RRDY=0)
    #define NF_EN_TRANSMIT_INT  (I2caRegs.I2CIER.bit.XRDY=1)
    #define NF_DEN_TRANSMIT_INT (I2caRegs.I2CIER.bit.XRDY=0)
    #define EN_SCD_INT          (I2caRegs.I2CIER.bit.SCD=1)
    #define DEN_SCD_INT         (I2caRegs.I2CIER.bit.SCD=0)
    #define EN_SLAVE_INT        (I2caRegs.I2CIER.bit.AAS=1)
    #define DEN_SLAVE_INT       (I2caRegs.I2CIER.bit.AAS=0)
    #define IS_IIC_ENABLED      (I2caRegs.I2CMDR.bit.IRS)
    #define IS_IT_SLAVE         (I2caRegs.I2CSTR.bit.AAS || !I2caRegs.I2CMDR.bit.MST/* || !g_is_master*/)
    #define IS_TX_BE_SLAVE      (I2caRegs.I2CSTR.bit.SDIR/* || g_is_slave_be_tx*/)
    #define IS_TX_BE_MASTER     (I2caRegs.I2CMDR.bit.TRX)
    #define MASTER_TX           (I2caRegs.I2CMDR.all=0x6E20) // FREE, STT, STP, MST, TRX, IRS, (STB). Try Master to dummy start
    #define MASTER_RX           (I2caRegs.I2CMDR.all=0x6C20) // FREE, STT, STP, MST, (TRX), IRS, (STB).
    #define MASTER_STAY         while(I2caRegs.I2CMDR.bit.STP||!I2caRegs.I2CIER.bit.ARDY)
    #define RESET_TIMER(x)      ((x)=TIMEOUT)


    void IIC_ReStart(void){                     // invoked internally
        MS_STOP_IIC_RUN;
        EN_ALL_INT;                             // enable all interrupts
        FT_FIFO_RESET;
        FR_FIFO_RESET;

        if (g_use_fifo){
            NF_DEN_TRANSMIT_INT;
            NF_DEN_RECEIVE_INT;
            FT_FIFO_BEGIN;
            FR_FIFO_BEGIN;
        }
        else {
            NF_EN_RECEIVE_INT;
            NF_EN_TRANSMIT_INT;
        }

        MS_START_IIC_RUN;
    }


    bool IIC_SetMode(bool is_fifo){             // true: fifo, false: normal
        if (MS_IS_BUS_IDLE){
            g_use_fifo=is_fifo;
            IIC_ReStart();
            return true;
        }
        return false;
    }


    void IIC_Init(void){ // Initialize IIC
        MS_STOP_IIC_RUN;

    ///#if     (CPU_FRQ_40MHZ)
    ///    I2caRegs.I2CPSC.all = 4;                // Prescaler - need 7-12 Mhz on module clk
    ///#elif   (CPU_FRQ_60MHZ)
        I2caRegs.I2CPSC.all = CLK_VAR;                // Prescaler - need 7-12 Mhz on module clk
    ///#endif

        I2caRegs.I2CCLKL = 10;                  // NOTE: must be non zero
        I2caRegs.I2CCLKH = 5;                   // NOTE: must be non zero

        I2caRegs.I2COAR = IIC_MASTER_ADDR;      // Own address
        I2caRegs.I2CSAR = IIC_SLAVE_ADDR;       // Slave address - Device control code

        IIC_SetMode(g_use_fifo);
        I2caRegs.I2CDXR=0x0f;///////////////////////////////////////////////////////////////////////////////////////
    }


    bool IIC_CheckTimeOut(void){
        if (g_tic_cnt--) return false;
        RESET_TIMER(g_tic_cnt);
        return true;
    }


    void IIC_PingPong(const byte *cmd, size_t cmd_len, byte *rcv_buf, size_t rcv_len){
        // note that both storages must be static variable spaces.
        // both processed length must be known in advance.
        // both of the storages must be untouched before IIC_IsInProgress() return false;
        // afterwards, rcv_buf can be accessed.
        g_is_master=true;
        g_ptr=0;
        g_ping_space=cmd;
        g_pong_space=rcv_buf;
        g_ping_cnt=cmd_len;
        g_pong_cnt=rcv_len;
        MST_MAR_NRM_SET_COUNTER(cmd_len? cmd_len: rcv_len);
        g_irst_txdata_ready=true;
        MASTER_STAY;///while (I2caRegs.I2CSTR.bit.BB);///while (!I2caRegs.I2CSTR.bit.ARDY);///
        I2caRegs.I2CMDR.all=cmd_len? 0x6E20: 0x6C20;
        RESET_TIMER(g_tic_cnt);
    }


    void IIC_PongPing(byte idef){               // determine the behavior of the slave transmission (***replace it***)
        if (idef>6) idef=1; // do not exceed
        g_ping_space=(const byte*)(g_outgoing_data[idef-1]);
        g_ptr=0;
        g_ping_cnt=TX_MAX_LEN;
        MST_MAR_NRM_SET_COUNTER(0);
        g_ping_space++;                         // point to cmdx item
        g_irst_txdata_ready=true;
    }


    void IIC_PongGetStreamData(void){           // for slave only (***replace it***)
        if (g_dummy_read){                      /// notifies that the stream data from slave presents
            g_dummy_read=false;                 ///
            g_ping_space=(const byte*)(*g_outgoing_data); /// point to a dynamic storage
            g_pong_space[0]=0x05;               /// the sent back value (remove)
        }
    }


    bool IIC_IsInProgress(void){                // use this function to check whether if transmission was success
    if (g_use_fifo){////////////////////////////
    FR_FIFO_RUN;/////////////////////////////////
    FT_FIFO_RUN;/////////////////////////////////////
    g_use_fifo=0;//////////////////////////////////
    }///////////////////////////////////////////////

        if (g_repeat_start){                    // but not really repeat start, it contains stop
            MST_MAR_NRM_SET_COUNTER(g_repeat_start);
            MASTER_STAY;
            I2caRegs.I2CMDR.all=0x6C20;
            g_repeat_start=0;
            return true;
        }
        if (\
            (
                g_is_master &&\
                (I2caRegs.I2CSTR.bit.ARBL || I2caRegs.I2CSTR.bit.AAS || I2caRegs.I2CSTR.bit.NACK)\
            ) ||\
                !MS_IS_BUS_IDLE\
           ){
            if (0 && IIC_CheckTimeOut()){
                g_is_master=false;
                g_ptr=0;
                RESET_TIMER(g_tic_cnt);
                MS_IIC_TOTALLY_RESET;
                return false;
            }
            return true;
        }
        else RESET_TIMER(g_tic_cnt);
        return (g_isrst_data_done? g_ptr=0, g_is_master=false, (g_isrst_data_done=false): true);

        /*
        // failed polling
        if (I2caRegs.I2CSTR.bit.AAS || !I2caRegs.I2CMDR.bit.MST){ // if slave
            if (I2caRegs.I2CSTR.bit.ARBL){      // arbitration failed during data transmission
                I2caRegs.I2CSTR.bit.ARBL=1;
                while (1);
            }
            if (g_tr_session_flag){             // in transmission
                if (g_use_fifo) i=I2caRegs.I2CFFRX.bit.RXFFST;
                else i=(I2caRegs.I2CSTR.bit.RRDY? I2caRegs.I2CSTR.bit.RRDY=1: 0);
                while (g_ptr<g_pong_cnt && i--) g_pong_space[g_ptr++]=I2caRegs.I2CDRR;
                if (!I2caRegs.I2CSTR.bit.BB){
                    if (g_is_slave_be_tx){
                        g_tr_session_flag=2;
                        g_is_slave_be_tx=0;
                        g_ptr=0;
                        IIC_PongPing(*g_incoming_storage);
                    }
                    else return false;
                }
                if (g_tr_session_flag==2){
                    if (g_use_fifo) i=0x10-I2caRegs.I2CFFTX.bit.TXFFST;
                    else i=(I2caRegs.I2CSTR.bit.XRDY? I2caRegs.I2CSTR.bit.XRDY=1: 0);
                    while (!I2caRegs.I2CSTR.bit.NACK && g_ptr<g_ping_cnt && i--) I2caRegs.I2CDXR=g_ping_space[g_ptr++];
                    if (I2caRegs.I2CSTR.bit.NACK){
                        g_tr_session_flag=0;
                        return false;
                    }
                }
            }
            else {
                if (!I2caRegs.I2CMDR.bit.MST && !I2caRegs.I2CSTR.bit.BB) return false;
                g_tr_session_flag=1;            // first, receive preparation
                g_ptr=0;
                g_pong_cnt=(size_t)(-1);
                g_pong_space=g_incoming_storage;
                if (I2caRegs.I2CSTR.bit.SDIR) g_is_slave_be_tx=1;
            }
        }
        else {                                  // master
            if (IS_TX_BE_MASTER){               // master tx
                if (g_use_fifo) i=0x10-I2caRegs.I2CFFTX.bit.TXFFST;
                else i=(I2caRegs.I2CSTR.bit.XRDY? I2caRegs.I2CSTR.bit.XRDY=1: 0);
                while (g_ptr<g_ping_cnt && i--) I2caRegs.I2CDXR=g_ping_space[g_ptr++];
                if (g_ptr==g_ping_cnt){
                    MA_END_OF_SESSION;          // send stop bit
                    g_ptr=0;                    // reset data counter
                    if (g_pong_cnt) MA_RECEIVE_MODE; // enter receive mode
                    ///////////NF_DEN_TRANSMIT_INT;        // disable transmission int
                    else return false;
                }
            }
            else {                              // master rx
                if (g_use_fifo) i=I2caRegs.I2CFFRX.bit.RXFFST;
                else i=(I2caRegs.I2CSTR.bit.RRDY? I2caRegs.I2CSTR.bit.RRDY=1: 0);
                while (g_ptr<g_pong_cnt && i--) g_pong_space[g_ptr++]=I2caRegs.I2CDRR;
                if (g_ptr==g_pong_cnt){
                    MA_END_OF_SESSION;          // send stop bit
                    g_ptr=0;                    // reset data counter
                    /////////////NF_DEN_TRANSMIT_INT;        // disable transmission int
                }
            }
        }
        return true;*/
    }


    interrupt void iic_int1a_isr(void){         // I2C-1A
        byte a=0xaa;

        g_isrst_is_nack=I2caRegs.I2CSTR.bit.NACK;
        switch (I2caRegs.I2CISRC.bit.INTCODE & 0x7){
            case I2C_NO_ISRC:   // =0
                // if it is the reason that INTFx was set and not yet served,
                // and will be served,
                // but the corresponding STRx were clearred by other events,
                // then, C2000 IIC module is a G. D. deterministic failure of implementation.
                asm("   ESTOP0"); // Halt on invalid number.
                break;

            case I2C_ARB_ISRC:  // =1
                g_isrst_arbl=true;              // could be failure at anytime of transmission
                break;

            case I2C_NACK_ISRC: // =2
                // should manually resend the missing data?
                // NACK only occurs at AL or slave inactive, how is it?

                if (g_isrst_is_nack){           // to prevent repeat start, but how?
                    g_isrst_is_nack=false;
                    if (g_is_slave_be_tx){
                        g_is_slave_be_tx=false;
                        g_isrst_data_done=true;
                        g_irst_txdata_ready=false;
                    }
                }
                break;

            case I2C_ARDY_ISRC: // =3
                break;

            case I2C_RX_ISRC:   // =4
                ///slave should block reception before new message taken away
                g_pong_space[g_ptr++]=I2caRegs.I2CDRR;
                break;

            case I2C_TX_ISRC:   // =5
                if ((I2caRegs.I2CSTR.bit.SDIR ^ g_is_slave_be_tx) && !g_ptr){ // slave tx 1st time
                    g_is_slave_be_tx=true;
                    IIC_PongGetStreamData();
                    IIC_PongPing(*g_pong_space);
                }
                if (!g_irst_txdata_ready) break;
                if (g_is_slave_be_tx){          // slave transmission
                    if (g_ptr<g_ping_cnt) a=g_ping_space[g_ptr++];
                }
                else a=g_ping_space[g_ptr++];   // master transmission
                I2caRegs.I2CDXR=a;
                break;

            case I2C_SCD_ISRC:  // =6
                g_irst_txdata_ready=false;
                if (g_is_master){
                    if (g_pong_cnt){            // master transmission done and then enter receive mode. or master rx only.
                        if (g_ping_cnt){        // successor
                            g_repeat_start=g_pong_cnt;
                        }
                        else g_isrst_data_done=true; // only read
                    }
                    else g_isrst_data_done=true;
                }
                else g_isrst_data_done=true;
                g_ping_cnt=0;
                g_pong_cnt=0;
                g_ptr=0;
                break;

            case I2C_AAS_ISRC:  // =7
                if (g_isrst_arbl) g_isrst_arbl=false;
    //            if (g_ptr) I2caRegs.I2CMDR.bit.NACKMOD=1;
                break;

            default:
                asm("   ESTOP0"); // Halt on invalid number.
        }
        // Enable future I2C (PIE Group 8) interrupts
        PieCtrlRegs.PIEACK.all=PIEACK_GROUP8;
    }


    interrupt void iic_int2a_isr(void){         // I2C-2A
        byte a=0x55, b=0;

        switch (I2caRegs.I2CISRC.bit.INTCODE & 0x7){
            case 0:   // =0, transmit
                if (I2caRegs.I2CSTR.bit.SDIR ^ g_is_slave_be_tx && !g_ptr){
                    g_is_slave_be_tx=true;
                    IIC_PongGetStreamData();
                    IIC_PongPing(*g_pong_space);
                }
                if (!g_irst_txdata_ready) break;
                b=0x10-I2caRegs.I2CFFTX.bit.TXFFST;
                if (g_is_slave_be_tx){
                    while (g_ptr<g_ping_cnt && b--) I2caRegs.I2CDXR=g_ping_space[g_ptr++];
                    while (b-->0) I2caRegs.I2CDXR=a;
                }
                else while (g_ptr<g_ping_cnt && b-->0) I2caRegs.I2CDXR=g_ping_space[g_ptr++];
                break;

            case 1:  // =1, receive
                b=I2caRegs.I2CFFRX.bit.RXFFST;
                while (b--) g_pong_space[g_ptr++]=I2caRegs.I2CDRR;
                break;

            default:
                asm("   ESTOP0"); // Halt on invalid number.
        }
        // Enable future I2C (PIE Group 8) interrupts
        PieCtrlRegs.PIEACK.all=PIEACK_GROUP8;
    }


    void IIC_Driver(void){
        int i=0, j=0;

        #define SELECT_CASE 0x33 // xxxxx
        g_use_fifo=false; ////////////////////////////////////////////////////////////

        IIC_Init();

        while (1){

        #if (SELECT_CASE==0x00)                                                 // dummy read a byte master

            g_dummy_read=true;
            IIC_PingPong(g_incoming_storage, 0, g_incoming_storage, 1);
            while (IIC_IsInProgress());

        #elif (SELECT_CASE==0x11)                                               // dummy send a byte slave

            g_dummy_read=true;
            while (IIC_IsInProgress());

        #elif (SELECT_CASE==0x22)                                               // sequence master

            g_dummy_read=false;
            g_incoming_storage[0]=10;
            g_incoming_storage[1]=4;
            for (i=2; i<11; i++) g_incoming_storage[i]=j++;
            IIC_PingPong(g_incoming_storage, 10, g_incoming_storage, 10);
            while (IIC_IsInProgress());

        #elif (SELECT_CASE==0x33)                                               // sequence slave

            g_dummy_read=false;
            while (IIC_IsInProgress());

        #elif (SELECT_CASE==0x44)                                               // master

            g_dummy_read=false;
            IIC_PingPong((const byte*)(g_outgoing_data[0]), 5, g_incoming_storage, 5);
            while (IIC_IsInProgress());

        #elif (SELECT_CASE==0x55)                                               // slave

            g_dummy_read=false;
            while (IIC_IsInProgress());

        #endif

        }
    }