Hot!I2C Interrupt problem using PIC16F1509

Author
iskhu
New Member
  • Total Posts : 15
  • Reward points : 0
  • Joined: 2018/10/10 15:18:44
  • Location: 0
  • Status: offline
2018/12/30 03:36:00 (permalink)
0

I2C Interrupt problem using PIC16F1509

Hi,

I have one problem in I2C communication, and really need advice from all of you here.
 
Here are detail of my project:
- PIC16F1509
- PICKIT3
- XC8 v1.45
- MPLAB X IDE v4.05
- MCC v3.55.1 (Library version 1.65.2)
 
Target device -> RTC DS1307, with I2C freq 100Khz.
 
Program flow:
1. Write value to memory in RTC, then read it.
2. after a while, do step 1 again.
 
Problem: Success in step 1, but failed in step 2.
When success, I can see I2C signal using Oscilloscope, and I can write data to and read data from RTC memory.
when failed, I can not see any signal in Oscilloscope, and off course, can not write data to and read data from RTC memory.
Both steps use same command -> just call Read_RTC_Data() function.
 
Here are list of function inside the program.
1. Read_RTC_Data() call function no. 2 below:
2. - DS1307_Write() call function no. 3 below:
3. - I2C_MasterWrite() call function no. 4 then no. 5 below:
4.    -  I2C_MasterWriteTRBBuild()
5.    -  I2C_MasterTRBInsert() call function no. 6 below:
6.      - I2C_WaitForLastPacketToComplete() do some setting here, then interrupt happen and call function no. 7 then no. 8 below.
7.                    - INTERRUPT_InterruptManager()
8.                       - I2C_ISR()
 
When failed, interrupt never happen, so program never go to function no 7 and 8 above.
Program just go ahead, and stuck in this line:
 
while(status == I2C_MESSAGE_PENDING);
 
this line is inside function no. 2 above (DS1307_Write()), after finish calling function no. 3 (it means, including finish executing function no. 4, 5 and 6).
 
I think this is because interrupt never happen, so variable "status" is never updated.
 
The question is, why interrupt never happen here?
 
Need advice from all of you here.
 
Here I attach screenshot of SFR register, when succeed and when failed. (see attachment below).
 
Also, here I put my source code for all related functions.
 
Source code:

function no 1.

void Read_RTC_Data(void)
{
    I2C_MESSAGE_STATUS Wstatus, Rstatus;
    uint8_t I2C_Result_W;
    uint8_t address[8]={0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
    uint8_t shift;

    shift=0;
    NOP(); NOP(); NOP();
    
    //Write
    I2C_Result_W = DS1307_Write(DS1307_RTC_FIRST_ADDRESS,I2C_RTC_WriteData, 8); <--- call DS1307_Write() here.


    // FOR READ, MUST READ ONE BYTE
    // so we make loop here
    
    for(shift=0; shift<8;shift++)
    {
        //Write before Read
        I2C_MasterWrite(&address[shift], 1, DS1307_ADDRESS,&Wstatus);
           while(Wstatus == I2C_MESSAGE_PENDING);

        //Read
        I2C_MasterRead(&I2C_RTC_ReadData[shift], 1, DS1307_ADDRESS,&Rstatus);
        while(Rstatus == I2C_MESSAGE_PENDING);
    }

.
.
.

-
function no 2.

uint8_t DS1307_Write(
                                uint16_t address,
                                uint8_t *pData,
                                uint16_t nCount)
{
    uint16_t dataAddress;
    uint8_t *pD, ret, result[8];
    uint16_t counter, timeOut, counterWrite;
    uint8_t writeBuffer[3];
    
    I2C_MESSAGE_STATUS status = I2C_MESSAGE_PENDING;

    dataAddress = address; // starting EEPROM address
    pD = pData; // initialize the source of the data
    ret = 1;

    
    counterWrite=0;
    
    for (counter = 0; counter < nCount; counter++)
    {
        result[counter]=0;
        
        // build the write buffer first
        // starting address of the EEPROM memory
        writeBuffer[0] = (uint8_t)(dataAddress); // low low address

        // data to be written
        writeBuffer[1] = *pD;

        // Now it is possible that the slave device will be slow.
        // As a work around on these slaves, the application can
        // retry sending the transaction
        timeOut = 0;
        while(status != I2C_MESSAGE_FAIL)
        {
            counterWrite++;
            // write one byte to EEPROM (3 is the number of bytes to write)
            I2C_MasterWrite( writeBuffer, <--- call I2C_MasterWrite() here.
                                    2,
                                    DS1307_ADDRESS,
                                    &status);

            // wait for the message to be sent or status has changed.
            while(status == I2C_MESSAGE_PENDING); <--- when failed, stuck here.

            if (status == I2C_MESSAGE_COMPLETE)
            {
                result[counter]=2;
                ret = 2;
                break;
            }

            // if status is I2C_MESSAGE_ADDRESS_NO_ACK,
            // or I2C_DATA_NO_ACK,
            // The device may be busy and needs more time for the last
            // write so we can retry writing the data, this is why we
            // use a while loop here

            // check for max retry and skip this byte
            if (timeOut == DS1307_RETRY_MAX)
            {
                result[counter]=3;
                ret = 3;
                break;
            }
            else
                timeOut++;
        }

        if (status == I2C_MESSAGE_FAIL)
        {
            result[counter]=1;
            ret = 0;
            break;
        }
        pD++;
        dataAddress++;

    }
    return (ret);
}

-
function no 3.

void I2C_MasterWrite(
                                uint8_t *pdata,
                                uint8_t length,
                                uint16_t address,
                                I2C_MESSAGE_STATUS *pflag)
{
    static I2C_TRANSACTION_REQUEST_BLOCK trBlock;

    // check if there is space in the queue
    if (i2c_object.trStatus.s.full != true)
    {
        I2C_MasterWriteTRBBuild(&trBlock, pdata, length, address); <--- call I2C_MasterWriteTRBBuild() here.
        I2C_MasterTRBInsert(1, &trBlock, pflag); <--- call I2C_MasterTRBInsert() here.
    }
    else
    {
        *pflag = I2C_MESSAGE_FAIL;
    }

}

-
function no 4.

void I2C_MasterWriteTRBBuild(
                                I2C_TRANSACTION_REQUEST_BLOCK *ptrb,
                                uint8_t *pdata,
                                uint8_t length,
                                uint16_t address)
{
    ptrb->address = address << 1;
    ptrb->length = length;
    ptrb->pbuffer = pdata;
}


-
function no 5.

void I2C_MasterTRBInsert(
                                uint8_t count,
                                I2C_TRANSACTION_REQUEST_BLOCK *ptrb_list,
                                I2C_MESSAGE_STATUS *pflag)
{

    // check if there is space in the queue
    if (i2c_object.trStatus.s.full != true)
    {
        *pflag = I2C_MESSAGE_PENDING;

        i2c_object.pTrTail->ptrb_list = ptrb_list;
        i2c_object.pTrTail->count = count;
        i2c_object.pTrTail->pTrFlag = pflag;
        i2c_object.pTrTail++;

        // check if the end of the array is reached
        if (i2c_object.pTrTail == (i2c_tr_queue + I2C_CONFIG_TR_QUEUE_LENGTH))
        {
            // adjust to restart at the beginning of the array
            i2c_object.pTrTail = i2c_tr_queue;
        }

        // since we added one item to be processed, we know
        // it is not empty, so set the empty status to false
        i2c_object.trStatus.s.empty = false;

        // check if full
        if (i2c_object.pTrHead == i2c_object.pTrTail)
        {
            // it is full, set the full status to true
            i2c_object.trStatus.s.full = true;
        }

    }
    else
    {
        *pflag = I2C_MESSAGE_FAIL;
    }

    // for interrupt based
    if (*pflag == I2C_MESSAGE_PENDING)
    {
        I2C_WaitForLastPacketToComplete(); <--- call I2C_WaitForLastPacketToComplete() here.
        
        // The state machine has to be started manually because it runs only in the ISR.
        // If we called the ISR function here function duplication would double the code size
        // because this function would be called both from interrupt and from mainline code.
        PIR1bits.SSP1IF = true;

    } // block until request is complete

}

-
function no 6.

inline void I2C_WaitForLastPacketToComplete()
{
    while(i2c_state != S_MASTER_IDLE)
    {
        // If your code gets stuck here it is because the last packet is never completing
        // Most likely cause is that your interrupt is not firing as it should. Check if you have
        // correctly enabled all MSSP, Peripheral and GIE interrupt settings.
    }
}

-
function no 7.

void interrupt INTERRUPT_InterruptManager (void)
{
    // interrupt handler
    if(INTCONbits.TMR0IE == 1 && INTCONbits.TMR0IF == 1)
    {
        TMR0_ISR();
    }
    else if(INTCONbits.INTE == 1 && INTCONbits.INTF == 1)
    {
        INT_ISR();
    }
    else if(INTCONbits.PEIE == 1)
    {
        if(PIE2bits.BCL1IE == 1 && PIR2bits.BCL1IF == 1)
        {
            I2C_BusCollisionISR();
        }
        else if(PIE1bits.SSP1IE == 1 && PIR1bits.SSP1IF == 1)
        {
            I2C_ISR();
        }
        else
        {
            //Unhandled Interrupt
        }
    }
    else
    {
        //Unhandled Interrupt
    }
}

-
function no 8.

void I2C_ISR ( void )
{
  
    static uint8_t *pi2c_buf_ptr;
    static uint16_t i2c_address = 0;
    static uint8_t i2c_bytes_left = 0;
    static uint8_t i2c_10bit_address_restart = 0;

    PIR1bits.SSP1IF = 0;
    
    // Check first if there was a collision.
    // If we have a Write Collision, reset and go to idle state */
    if(I2C_WRITE_COLLISION_STATUS_BIT)
    {
        // clear the Write colision
        I2C_WRITE_COLLISION_STATUS_BIT = 0;
        i2c_state = S_MASTER_IDLE;
        *(p_i2c_current->pTrFlag) = I2C_MESSAGE_FAIL;

        // reset the buffer pointer
        p_i2c_current = NULL;

        return;
    }

    /* Handle the correct i2c state */
    switch(i2c_state)
    {
        case S_MASTER_IDLE: /* In reset state, waiting for data to send */

            if(i2c_object.trStatus.s.empty != true)
            {
                // grab the item pointed by the head
                p_i2c_current = i2c_object.pTrHead;
                i2c_trb_count = i2c_object.pTrHead->count;
                p_i2c_trb_current = i2c_object.pTrHead->ptrb_list;

                i2c_object.pTrHead++;

                // check if the end of the array is reached
                if(i2c_object.pTrHead == (i2c_tr_queue + I2C_CONFIG_TR_QUEUE_LENGTH))
                {
                    // adjust to restart at the beginning of the array
                    i2c_object.pTrHead = i2c_tr_queue;
                }

                // since we moved one item to be processed, we know
                // it is not full, so set the full status to false
                i2c_object.trStatus.s.full = false;

                // check if the queue is empty
                if(i2c_object.pTrHead == i2c_object.pTrTail)
                {
                    // it is empty so set the empty status to true
                    i2c_object.trStatus.s.empty = true;
                }

                // send the start condition
                I2C_START_CONDITION_ENABLE_BIT = 1;
                
                // start the i2c request
                i2c_state = S_MASTER_SEND_ADDR;
            }

            break;

        case S_MASTER_RESTART:

            /* check for pending i2c Request */

            // ... trigger a REPEATED START
            I2C_REPEAT_START_CONDITION_ENABLE_BIT = 1;

            // start the i2c request
            i2c_state = S_MASTER_SEND_ADDR;

            break;

        case S_MASTER_SEND_ADDR_10BIT_LSB:

            if(I2C_ACKNOWLEDGE_STATUS_BIT)
            {
                i2c_object.i2cErrors++;
                I2C_Stop(I2C_MESSAGE_ADDRESS_NO_ACK);
            }
            else
            {
                // Remove bit 0 as R/W is never sent here
                I2C_TRANSMIT_REG = (i2c_address >> 1) & 0x00FF;

                // determine the next state, check R/W
                if(i2c_address & 0x01)
                {
                    // if this is a read we must repeat start
                    // the bus to perform a read
                    i2c_state = S_MASTER_10BIT_RESTART;
                }
                else
                {
                    // this is a write continue writing data
                    i2c_state = S_MASTER_SEND_DATA;
                }
            }

            break;

        case S_MASTER_10BIT_RESTART:

            if(I2C_ACKNOWLEDGE_STATUS_BIT)
            {
                i2c_object.i2cErrors++;
                I2C_Stop(I2C_MESSAGE_ADDRESS_NO_ACK);
            }
            else
            {
                // ACK Status is good
                // restart the bus
                I2C_REPEAT_START_CONDITION_ENABLE_BIT = 1;

                // fudge the address so S_MASTER_SEND_ADDR works correctly
                // we only do this on a 10-bit address resend
                i2c_address = 0x00F0 | ((i2c_address >> 8) & 0x0006);

                // set the R/W flag
                i2c_address |= 0x0001;

                // set the address restart flag so we do not change the address
                i2c_10bit_address_restart = 1;

                // Resend the address as a read
                i2c_state = S_MASTER_SEND_ADDR;
            }

            break;

        case S_MASTER_SEND_ADDR:

            /* Start has been sent, send the address byte */

            /* Note:
                On a 10-bit address resend (done only during a 10-bit
                device read), the original i2c_address was modified in
                S_MASTER_10BIT_RESTART state. So the check if this is
                a 10-bit address will fail and a normal 7-bit address
                is sent with the R/W bit set to read. The flag
                i2c_10bit_address_restart prevents the address to
                be re-written.
             */
            if(i2c_10bit_address_restart != 1)
            {
                // extract the information for this message
                i2c_address = p_i2c_trb_current->address;
                pi2c_buf_ptr = p_i2c_trb_current->pbuffer;
                i2c_bytes_left = p_i2c_trb_current->length;
            }

            // check for 10-bit address
            if(!I2C_7bit && (0x0 != i2c_address))
            {
                if (0 == i2c_10bit_address_restart)
                {
                    // we have a 10 bit address
                    // send bits<9:8>
                    // mask bit 0 as this is always a write
                    I2C_TRANSMIT_REG = 0xF0 | ((i2c_address >> 8) & 0x0006);
                    i2c_state = S_MASTER_SEND_ADDR_10BIT_LSB;
                }
                else
                {
                    // resending address bits<9:8> to trigger read
                    I2C_TRANSMIT_REG = i2c_address;
                    i2c_state = S_MASTER_ACK_ADDR;
                    // reset the flag so the next access is ok
                    i2c_10bit_address_restart = 0;
                }
            }
            else
            {
                // Transmit the address
                I2C_TRANSMIT_REG = i2c_address;
                if(i2c_address & 0x01)
                {
                    // Next state is to wait for address to be acked
                    i2c_state = S_MASTER_ACK_ADDR;
                }
                else
                {
                    // Next state is transmit
                    i2c_state = S_MASTER_SEND_DATA;
                }
            }
            break;

        case S_MASTER_SEND_DATA:

            // Make sure the previous byte was acknowledged
            if(I2C_ACKNOWLEDGE_STATUS_BIT)
            {
                // Transmission was not acknowledged
                i2c_object.i2cErrors++;

                // Reset the Ack flag
                I2C_ACKNOWLEDGE_STATUS_BIT = 0;

                // Send a stop flag and go back to idle
                I2C_Stop(I2C_DATA_NO_ACK);

            }
            else
            {
                // Did we send them all ?
                if(i2c_bytes_left-- == 0U)
                {
                    // yup sent them all!

                    // update the trb pointer
                    p_i2c_trb_current++;

                    // are we done with this string of requests?
                    if(--i2c_trb_count == 0)
                    {
                        I2C_Stop(I2C_MESSAGE_COMPLETE);
                    }
                    else
                    {
                        // no!, there are more TRB to be sent.
                        //I2C_START_CONDITION_ENABLE_BIT = 1;

                        // In some cases, the slave may require
                        // a restart instead of a start. So use this one
                        // instead.
                        I2C_REPEAT_START_CONDITION_ENABLE_BIT = 1;

                        // start the i2c request
                        i2c_state = S_MASTER_SEND_ADDR;

                    }
                }
                else
                {
                    // Grab the next data to transmit
                    I2C_TRANSMIT_REG = *pi2c_buf_ptr++;
                }
            }
            break;

        case S_MASTER_ACK_ADDR:

            /* Make sure the previous byte was acknowledged */
            if(I2C_ACKNOWLEDGE_STATUS_BIT)
            {

                // Transmission was not acknowledged
                i2c_object.i2cErrors++;

                // Send a stop flag and go back to idle
                I2C_Stop(I2C_MESSAGE_ADDRESS_NO_ACK);

                // Reset the Ack flag
                I2C_ACKNOWLEDGE_STATUS_BIT = 0;
            }
            else
            {
                I2C_RECEIVE_ENABLE_BIT = 1;
                i2c_state = S_MASTER_ACK_RCV_DATA;
            }
            break;

        case S_MASTER_RCV_DATA:

            /* Acknowledge is completed. Time for more data */

            // Next thing is to ack the data
            i2c_state = S_MASTER_ACK_RCV_DATA;

            // Set up to receive a byte of data
            I2C_RECEIVE_ENABLE_BIT = 1;

            break;

        case S_MASTER_ACK_RCV_DATA:

            // Grab the byte of data received and acknowledge it
            *pi2c_buf_ptr++ = I2C_RECEIVE_REG;

            // Check if we received them all?
            if(--i2c_bytes_left)
            {

                /* No, there's more to receive */

                // No, bit 7 is clear. Data is ok
                // Set the flag to acknowledge the data
                I2C_ACKNOWLEDGE_DATA_BIT = 0;

                // Wait for the acknowledge to complete, then get more
                i2c_state = S_MASTER_RCV_DATA;
            }
            else
            {

                // Yes, it's the last byte. Don't ack it
                // Flag that we will nak the data
                I2C_ACKNOWLEDGE_DATA_BIT = 1;

                I2C_FunctionComplete();
            }

            // Initiate the acknowledge
            I2C_ACKNOWLEDGE_ENABLE_BIT = 1;
            break;

        case S_MASTER_RCV_STOP:
        case S_MASTER_SEND_STOP:

            // Send the stop flag
            I2C_Stop(I2C_MESSAGE_COMPLETE);
            break;

        default:

            // This case should not happen, if it does then
            // terminate the transfer
            i2c_object.i2cErrors++;
            I2C_Stop(I2C_LOST_STATE);
            break;

    }
}


--
for your reference, here I put source code of I2C_Initialize() also.
Off course this function is called during starting, and I2C succeed.
Before executing Read_RTC_Data() for the 2nd time (when failed), I don't call this initialization function.
For testing purpose, I call this function initialization before executing Read_RTC_Data() for the 2nd time, but the result is same -> failed.

void I2C_Initialize(void)
{
    i2c_object.pTrHead = i2c_tr_queue;
    i2c_object.pTrTail = i2c_tr_queue;
    i2c_object.trStatus.s.empty = true;
    i2c_object.trStatus.s.full = false;

    i2c_object.i2cErrors = 0;

    // R_nW write_noTX; P stopbit_notdetected; S startbit_notdetected; BF RCinprocess_TXcomplete; SMP Standard Speed; UA dontupdate; CKE disabled; D_nA lastbyte_address;
    SSP1STAT = 0x80;
    // SSPEN enabled; WCOL no_collision; CKP Idle:Low, Active:High; SSPM FOSC/4_SSPxADD_I2C; SSPOV no_overflow;
    SSP1CON1 = 0x28;
    // ACKTIM ackseq; SBCDE disabled; BOEN disabled; SCIE disabled; PCIE disabled; DHEN disabled; SDAHT 300ns; AHEN disabled;
    SSP1CON3 = 0x08;
    // ADD 39;
    SSP1ADD = 0x27;
    
    // clear the interrupt flags
    PIR1bits.SSP1IF = 0;
    PIR2bits.BCL1IF = 0;
 
    // enable the interruptsisr
    PIE1bits.SSP1IE = 1;
    PIE2bits.BCL1IE = 1;
    
}

Attached Image(s)

#1

16 Replies Related Threads

    Mysil
    Super Member
    • Total Posts : 3214
    • Reward points : 0
    • Joined: 2012/07/01 04:19:50
    • Location: Norway
    • Status: online
    Re: I2C Interrupt problem using PIC16F1509 2018/12/30 12:30:57 (permalink)
    +2 (2)
    Hi,
    The problem code provided in message #1 is incomplete and inconsistent.
    #include statements, macro definitions and configuration settings are missing. 
     
    Code seem to be a mixup of fragments from MCC and application level code derived from MCC examples.
     
    To avoid having to recreate everything you have done, and probably ending up with something completely different,
    you should provide a complete compilable problem program,
    containing all source code, both application and mcc_generated_files.
    There is a tool in MPLAB X, to 'Package' all files needed to restore a problem project.
     
        Mysil
    #2
    iskhu
    New Member
    • Total Posts : 15
    • Reward points : 0
    • Joined: 2018/10/10 15:18:44
    • Location: 0
    • Status: offline
    Re: I2C Interrupt problem using PIC16F1509 2018/12/30 19:50:34 (permalink)
    +1 (1)
     
    Mysil,
    sure. Here is my complete source code.
    It will be a great support if you can help me to solve this problem.
     
     
    #3
    AMPS
    Super Member
    • Total Posts : 347
    • Reward points : 0
    • Status: offline
    Re: I2C Interrupt problem using PIC16F1509 2018/12/30 20:27:52 (permalink)
    0
    i think used MSSP1[PIC10/PIC12/PIC16] instead of MSSP1[foundation service library] I think you should try with other library and complete code
    Below code not used library but its staraight forward in MSSP1 foundation libarry


    void wait_mssp(void)
    {
    while(!PIR3bits.SSPIF);
    PIR3bits.SSPIF=0;
    }
    void ds1307_write(unsigned char addr ,unsigned char data)
    {
    SSP1CON2bits.SEN =1; //Start bit
    wait_mssp();
    SSP1BUF = 0b11010000; //slave address(address of ds1307) + write bit
    wait_mssp();
    SSP1BUF=addr;
    wait_mssp();
    SSP1BUF = data;
    wait_mssp();
    SSP1CON2bits.PEN =1; //stop bit
    wait_mssp();
    }
    unsigned int ds1307_read(unsigned char addr)
    {
    SSP1CON2bits.RSEN =1;
    wait_mssp();
    SSP1BUF =0b11010000; //slave address(address of ds1307) + write bit;
    wait_mssp();
    SSP1BUF =addr;
    wait_mssp();
    SSP1CON2bits.RSEN =1;
    wait_mssp();
    SSP1BUF =0b11010001; //slave address(address of ds1307) + read bit;
    wait_mssp();
    SSP1CON2bits.RCEN =1;
    wait_mssp ();
    SSP1CON2bits.ACKDT=1;
    SSP1CON2bits.ACKEN =1;
    SSP1CON2bits.PEN=1;
    wait_mssp ();
    x = SSP1BUF;
    return (x);
    }

    void i2c_Init()
    {
    SSP1CON1=0X3;
    SSP1CON2=0X00;
    SSP1ADD=19;
    SSP1STATbits.CKE=1;
    SSP1STATbits.SMP=1;
    PIR3bits.BCLIF=0;
    ds1307_write(0,0x00);
    }
     
     
     


    Amps
    *.*.*.*.*.*.*.*.*.*.*.*.*
    #4
    iskhu
    New Member
    • Total Posts : 15
    • Reward points : 0
    • Joined: 2018/10/10 15:18:44
    • Location: 0
    • Status: offline
    Re: I2C Interrupt problem using PIC16F1509 2018/12/30 22:32:12 (permalink)
    0
    ajitnayak87
    i think used MSSP1[PIC10/PIC12/PIC16] instead of MSSP1[foundation service library] I think you should try with other library and complete codeBelow code not used library but its staraight forward in MSSP1 foundation libarry
    </p>
    <p>
    void wait_mssp(void)
    {
    while(!PIR3bits.SSPIF);
    PIR3bits.SSPIF=0;
    }</p>
    <p>void ds1307_write(unsigned char addr ,unsigned char data)
    {
    SSP1CON2bits.SEN =1; //Start bit
    wait_mssp();
    SSP1BUF = 0b11010000; //slave address(address of ds1307) + write bit
    wait_mssp();
    SSP1BUF=addr;
    wait_mssp();
    SSP1BUF = data;
    wait_mssp();
    SSP1CON2bits.PEN =1; //stop bit
    wait_mssp();
    }</p>
    <p>unsigned int ds1307_read(unsigned char addr)
    {
    SSP1CON2bits.RSEN =1;
    wait_mssp();
    SSP1BUF =0b11010000; //slave address(address of ds1307) + write bit;
    wait_mssp();
    SSP1BUF =addr;
    wait_mssp();
    SSP1CON2bits.RSEN =1;
    wait_mssp();
    SSP1BUF =0b11010001; //slave address(address of ds1307) + read bit;
    wait_mssp();
    SSP1CON2bits.RCEN =1;
    wait_mssp ();
    SSP1CON2bits.ACKDT=1;
    SSP1CON2bits.ACKEN =1;
    SSP1CON2bits.PEN=1;
    wait_mssp ();
    x = SSP1BUF;
    return (x);
    }</p>
    <p>
    void i2c_Init()
    {
    SSP1CON1=0X3;
    SSP1CON2=0X00;
    SSP1ADD=19;
    SSP1STATbits.CKE=1;
    SSP1STATbits.SMP=1;
    PIR3bits.BCLIF=0;
    ds1307_write(0,0x00);
    }</p>
    <p> </p>
    <p> </p>
    <p> </p>
    <p>



    Hi AMPS,
    How to use MSSP1[foundation service library] ?
    We can use it from MCC?
    Should I change some setting in MCC?
    #5
    AMPS
    Super Member
    • Total Posts : 347
    • Reward points : 0
    • Status: offline
    Re: I2C Interrupt problem using PIC16F1509 2018/12/30 23:31:22 (permalink)
    0
    In MCC, if you goto MSSP setting you could find  2 setting. 
     
    1 MSSP1[PIC10/PIC12/PIC16] 
    2 MSSP1[foundation service library]
     
    you just need to use MSSP1[foundation service library] for your application and its pretty straight forward . Where you can use any example code done with DS1307.
     
     

    Attached Image(s)


    Amps
    *.*.*.*.*.*.*.*.*.*.*.*.*
    #6
    iskhu
    New Member
    • Total Posts : 15
    • Reward points : 0
    • Joined: 2018/10/10 15:18:44
    • Location: 0
    • Status: offline
    Re: I2C Interrupt problem using PIC16F1509 2018/12/31 01:28:44 (permalink)
    0
    ajitnayak87
    In MCC, if you goto MSSP setting you could find  2 setting. 
     
    1 MSSP1[PIC10/PIC12/PIC16] 
    2 MSSP1[foundation service library]
     
    you just need to use MSSP1[foundation service library] for your application and its pretty straight forward . Where you can use any example code done with DS1307.
     



    I see.
    Thanks for your reply.
     
    Anyway, what is different between these two?
    1 MSSP1[PIC10/PIC12/PIC16] 
    2 MSSP1[foundation service library]
     
    I think both of them should work.
     
    if possible, I want to use current MSSP library, to minimize source code change.
    #7
    AMPS
    Super Member
    • Total Posts : 347
    • Reward points : 0
    • Status: offline
    Re: I2C Interrupt problem using PIC16F1509 2018/12/31 04:00:45 (permalink)
    0
    2 MSSP1[foundation service library] uses old supportive  function. 1 MSSP1[PIC10/PIC12/PIC16]  uses PIC specified library. I have tried 1 MSSP1[PIC10/PIC12/PIC16]  before i used to get in correct data even all setting are correct . Later i tested with MSSP1[foundation service library] and got proper data and clock pulse.

    Amps
    *.*.*.*.*.*.*.*.*.*.*.*.*
    #8
    baileyb
    Junior Member
    • Total Posts : 32
    • Reward points : 0
    • Joined: 2015/10/19 09:41:51
    • Location: 0
    • Status: offline
    Re: I2C Interrupt problem using PIC16F1509 2019/01/01 10:52:01 (permalink)
    +3 (3)
    The MSSP in Foundation Services library is meant to be used in conjunction with I2CMASTER and I2CSIMPLE (which can be found in the Libraries->Foundation Services section of the Device Resource window. If you load I2CSIMPLE it will automatically load I2CMASTER and the MSSP. I2CSIMPLE provides a simple read/write API that sits on top of the MSSP. I would highly recommend using this one. 
    Check out one of the Mikro Clicks (such as the EEPROM Click) for some examples on how to use the API. 
    #9
    Mysil
    Super Member
    • Total Posts : 3214
    • Reward points : 0
    • Joined: 2012/07/01 04:19:50
    • Location: Norway
    • Status: online
    Re: I2C Interrupt problem using PIC16F1509 2019/01/01 22:57:04 (permalink)
    +2 (2)
    Hi iskhu,
     
    There is some questionable design in your problem program from message #3:
    Inside a Interrupt handler: TMR0_ISR(void){...},
    there is call to a function: Loop10ms(),
    which contain a large state-machine with calls to a number of different functions, including I2C driver application interface.
    This may cause any number of strange race conditions, and a number of warnings from linker.
     
    I suggest to Disable interrupts for TMR0,
    remove calls to: I2C_Initialize();  and  Read_RTC_Data(); from functions called inside interrupt handler,
    and debug:  Read_RTC_Data(); as called from main()
    until you are able to communicate with RTC DS1307.
    Note, that GIE and PEIE must still be enabled before Read_RTC_Data(); is called.
     
    A more conventional approach for a microcontroller application,
    is for TMR0_ISR() to set a global flag variable, and leave the ISR. 
    Then, in processing loop of main program, to call the: Loop10ms(); function with state machine logic.
     
        Mysil
    post edited by Mysil - 2019/01/01 23:34:19
    #10
    iskhu
    New Member
    • Total Posts : 15
    • Reward points : 0
    • Joined: 2018/10/10 15:18:44
    • Location: 0
    • Status: offline
    Re: I2C Interrupt problem using PIC16F1509 2019/01/03 06:12:36 (permalink)
    0
    ajitnayak87
    2 MSSP1[foundation service library] uses old supportive  function. 1 MSSP1[PIC10/PIC12/PIC16]  uses PIC specified library. I have tried 1 MSSP1[PIC10/PIC12/PIC16]  before i used to get in correct data even all setting are correct . Later i tested with MSSP1[foundation service library] and got proper data and clock pulse.


    Thanks for your information.
    It is new information for me.
    I will consider it.
    #11
    iskhu
    New Member
    • Total Posts : 15
    • Reward points : 0
    • Joined: 2018/10/10 15:18:44
    • Location: 0
    • Status: offline
    Re: I2C Interrupt problem using PIC16F1509 2019/01/03 06:13:44 (permalink)
    0
    baileyb
    The MSSP in Foundation Services library is meant to be used in conjunction with I2CMASTER and I2CSIMPLE (which can be found in the Libraries->Foundation Services section of the Device Resource window. If you load I2CSIMPLE it will automatically load I2CMASTER and the MSSP. I2CSIMPLE provides a simple read/write API that sits on top of the MSSP. I would highly recommend using this one. Check out one of the Mikro Clicks (such as the EEPROM Click) for some examples on how to use the API. 


    Hi Baileyb,
    This is new information for me. I will consider it.
    Thanks for your information.
    #12
    iskhu
    New Member
    • Total Posts : 15
    • Reward points : 0
    • Joined: 2018/10/10 15:18:44
    • Location: 0
    • Status: offline
    Re: I2C Interrupt problem using PIC16F1509 2019/01/03 06:29:43 (permalink)
    0
    Mysil
    Hi iskhu, There is some questionable design in your problem program from message #3:Inside a Interrupt handler: TMR0_ISR(void){...},there is call to a function: Loop10ms(),which contain a large state-machine with calls to a number of different functions, including I2C driver application interface.This may cause any number of strange race conditions, and a number of warnings from linker. I suggest to Disable interrupts for TMR0,remove calls to: I2C_Initialize();  and  Read_RTC_Data(); from functions called inside interrupt handler,and debug:  Read_RTC_Data(); as called from main()until you are able to communicate with RTC DS1307.Note, that GIE and PEIE must still be enabled before Read_RTC_Data(); is called. A more conventional approach for a microcontroller application,is for TMR0_ISR() to set a global flag variable, and leave the ISR. Then, in processing loop of main program, to call the: Loop10ms(); function with state machine logic.     Mysil


    Hi Mysil

    You can read my source code until detail, you must have long experience in microcontroller.

    Yes, I am designing simple system, and it will loop every 50ms. Off course, I have to make sure that all loop will finish within 50 ms. Sorry, I forgot to rename its function name, it should be Loop50ms(), not Loop10ms().

    Your idea seems good. I will try to disable some part, to check Read_RTC_Data() again. Thanks for your help.

    Anyway, I don't have any idea about main loop, and prefer to use periodical function like Loop50ms(), using interrupt.
    Until here, I think I have to check interrupt priority also. I2C interrupt should have higher priority than TMR0 interrupt. I will check it.

    By the way, other reason that I don't want to use main loop is, I don't want to burden the microcontroller. In fact, I should think about how to ask microcontroller to take rest, and not doing useless loop during waiting next TMR0 interrupt to call Loop50ms().
    Do you have any idea about this?
    #13
    qhb
    Superb Member
    • Total Posts : 9236
    • Reward points : 0
    • Joined: 2016/06/05 14:55:32
    • Location: One step ahead...
    • Status: offline
    Re: I2C Interrupt problem using PIC16F1509 2019/01/03 07:00:31 (permalink)
    +3 (3)
    iskhu
    ...
    Anyway, I don't have any idea about main loop, and prefer to use periodical function like Loop50ms(), using interrupt.

    You should learn to prefer things that work.
     

    Until here, I think I have to check interrupt priority also. I2C interrupt should have higher priority than TMR0 interrupt.

    There is no "interrupt priority" in PIC16F devices.
    The only control you have is which order you check them in, in your one and only interrupt service routine.
     

    By the way, other reason that I don't want to use main loop is, I don't want to burden the microcontroller. In fact, I should think about how to ask microcontroller to take rest, and not doing useless loop during waiting next TMR0 interrupt to call Loop50ms().

    Throw this idea away, and design something that actually works first.
    #14
    iskhu
    New Member
    • Total Posts : 15
    • Reward points : 0
    • Joined: 2018/10/10 15:18:44
    • Location: 0
    • Status: offline
    Re: I2C Interrupt problem using PIC16F1509 2019/01/12 03:27:52 (permalink)
    0
    Mysil
    A more conventional approach for a microcontroller application,
    is for TMR0_ISR() to set a global flag variable, and leave the ISR. 
    Then, in processing loop of main program, to call the: Loop10ms(); function with state machine logic.
        Mysil



    Mysil, finally I found the root-cause.
    I activate I2C interrupt and wait for its interrupt, but actually I am still inside TMR0 interrupt process (Loop50ms()) wh has higher priority than I2C interrrupt.
    So, I2C interrupt will never happen, because TMR0 interrupt process also still not finish.
     
    I moved I2C interrrupt activation to mainloop and wait for its interrupt there.
    Then, everything become ok.
     
    So the root-cause is -> calling interrupt process from other interrupt process with higher priority.
     
    note: priority here is based one order of checking inside interrupt main function.
     
    thanks for you advise.
     
     
    #15
    iskhu
    New Member
    • Total Posts : 15
    • Reward points : 0
    • Joined: 2018/10/10 15:18:44
    • Location: 0
    • Status: offline
    Re: I2C Interrupt problem using PIC16F1509 2019/01/12 03:31:53 (permalink)
    0
    qhb
    There is no "interrupt priority" in PIC16F devices.
    The only control you have is which order you check them in, in your one and only interrupt service routine.

     
    OK, thanks for your advise.
    I forgot about this priority, after I check, then I found the root-cause. See my message above this  message.
     
    qhb 
    Throw this idea away, and design something that actually works first.

     
    now, everythings work well, as I expected.
     
    thanks.
     
    #16
    JorgeF
    Super Member
    • Total Posts : 3340
    • Reward points : 0
    • Joined: 2011/07/09 11:56:58
    • Location: PT/EU @ Third rock from the Sun
    • Status: offline
    Re: I2C Interrupt problem using PIC16F1509 2019/01/12 07:55:02 (permalink)
    0
    Hi
    iskhu
    ..........
    Anyway, I don't have any idea about main loop, and prefer to use periodical function like Loop50ms(), using interrupt.
    ..........
    By the way, other reason that I don't want to use main loop is, I don't want to burden the microcontroller. In fact, I should think about how to ask microcontroller to take rest, and not doing useless loop during waiting next TMR0 interrupt to call Loop50ms().

    The usual way is to put the PIC to sleep at the end of the mainloop, after it had scanned all tasks, and let it be wakened up by an interrupt, the periodical one or other.
     
    post edited by JorgeF - 2019/01/12 07:56:07

    Best regards
    Jorge
     
    I'm here http://picforum.ric323.com too!
    And it works better....
    #17
    Jump to:
    © 2019 APG vNext Commercial Version 4.5