• AVR Freaks

Hot!PIC32MZ I2C Bit Bang Driver and I2C3 missing on Rev A3

Author
campbellCustom
Starting Member
  • Total Posts : 65
  • Reward points : 0
  • Joined: 2014/08/30 14:35:35
  • Location: 0
  • Status: offline
2019/01/17 11:30:36 (permalink)
0

PIC32MZ I2C Bit Bang Driver and I2C3 missing on Rev A3

Does the harmony I2C bit bang driver work with I2C3 on PIC32MZ?
 
MPLAB X v5.05, Harmony 2.06, PIC32MZ2048EFH064 Rev A3
 
I have found myself sitting in front of some REV A3 silicon on a circuit board that utilizes an I2C EEPROM on the pins for the peripheral I2C3. Looking at the errata it appears I’m in a bit of trouble here. Looking at the harmony framework it appears I’m in more trouble.
 
I have used this same I2C EEPROM [24LC512] with the PIC32MX series successfully, and wrote an application that deals with my NVM needs at the PLIB level, this effort was necessary due to issues in early versions of Harmony. Since that time I’ve had experience dealing with both static and dynamic drivers, but have kept my EEPROM handler by hacking it into new products via a static driver.
 
In my first attempt to migrate to MZ, after a few wasted hours, I was surprised when the SFRs showed all 0x00000000 on I2C3. It seems this peripheral was removed in revision A3, with a single note in the errata in the work around section. It also appears the other instances of I2C are unreliable, and needing a watchdog timer, so my legacy code is out.
 
It looks like someone implemented a 'bit bang' application that was then adapted to harmony as a driver. I have tried setting this up to run a test, however I don’t see any wiggle on the SCL and SDA lines. Looks like even the bit bang driver is making calls using the PLIB_I2C_xxxxx functions. So is this a hybrid peripheral / bit bang driver? Or is this an error? When debugging with I2C3, it’s still showing all 0x00000000 SFRs, so unless the debugger [ICD3] is gas lighting me, I don’t see a reason for this to work.
 
Perhaps I’ve missed a check box some place? Generated bad code? (yes the I2C bit bang box is checked, and I have tried to generate with and without interrupt mode checked)
 
I tried generating with and without the pins set in the pin manager, both as digital I/O and I2C3.
 
I have tried adding in timer 9 in the drivers section (this gives a conflict, which I found surprising… it looks like the Bit Bang driver doesn’t have it’s timer ISR in the system interrupt file)
 
So I’m stuck, fooled twice, seemingly putting good time after bad, and on this forum asking for guidance on what to try next. Or maybe a link to a thread where all of this has been solved? Anyone?
 
#1

12 Replies Related Threads

    NKurzman
    A Guy on the Net
    • Total Posts : 17233
    • Reward points : 0
    • Joined: 2008/01/16 19:33:48
    • Location: 0
    • Status: offline
    Re: PIC32MZ I2C Bit Bang Driver and I2C3 missing on Rev A3 2019/01/17 11:56:43 (permalink)
    0
    Bit banged I2C is not tied to hardware periperials. I can tell you bit banging will work. If the Harmony driver does not work you would need to code it your self.
    You should have timeouts ( not a WDT) in all I2c Hardware calls. They can lock.
    The hardware I2C works within the limits of the Errata. I am having no issues.
    post edited by NKurzman - 2019/01/17 12:01:17
    #2
    campbellCustom
    Starting Member
    • Total Posts : 65
    • Reward points : 0
    • Joined: 2014/08/30 14:35:35
    • Location: 0
    • Status: offline
    Re: PIC32MZ I2C Bit Bang Driver and I2C3 missing on Rev A3 2019/01/17 12:04:51 (permalink)
    0
    Bit banged I2C is not tied to hardware periperials.

     
    Right? So wouldn't a driver named for bit banging not call PLIB_I2C_xxxx functions?
    #3
    qhb
    Superb Member
    • Total Posts : 9954
    • Reward points : 0
    • Joined: 2016/06/05 14:55:32
    • Location: One step ahead...
    • Status: online
    Re: PIC32MZ I2C Bit Bang Driver and I2C3 missing on Rev A3 2019/01/17 12:17:42 (permalink)
    0
    It wouldn't have to.
    Bit banging can work on any two pins, although their software may restrict you to the ones that were originally connected to the peripheral.
     
    #4
    campbellCustom
    Starting Member
    • Total Posts : 65
    • Reward points : 0
    • Joined: 2014/08/30 14:35:35
    • Location: 0
    • Status: offline
    Re: PIC32MZ I2C Bit Bang Driver and I2C3 missing on Rev A3 2019/01/17 12:32:07 (permalink)
    0
    The system_config.h settings have port/bit config as well as a peripheral ID:
     
     
    /* I2C Driver Configuration Options
    */
    #define BB_ENABLED
    #define DRV_I2C_INTERRUPT_MODE true
    #define DRV_I2C_CLIENTS_NUMBER 1
    #define DRV_I2C_INSTANCES_NUMBER 1

    #define DRV_I2C_PERIPHERAL_ID_IDX0 I2C_ID_3
    #define DRV_I2C_OPERATION_MODE_IDX0 DRV_I2C_MODE_MASTER
    #define DRV_SCL_PORT_IDX0 PORT_CHANNEL_D
    #define DRV_SCL_PIN_POSITION_IDX0 PORTS_BIT_POS_3
    #define DRV_SDA_PORT_IDX0 PORT_CHANNEL_D
    #define DRV_SDA_PIN_POSITION_IDX0 PORTS_BIT_POS_2
    #define DRV_I2C_BIT_BANG_IDX0 true
    #define DRV_I2C_BIT_BANG_BAUD_RATE_IDX0 50000
    #define DRV_I2C_BIT_BANG_TMR_MODULE_IDX0 TMR_ID_9
    #define DRV_I2C_BIT_BANG_INT_SRC_IDX0 INT_SOURCE_TIMER_9
    #define DRV_I2C_STOP_IN_IDLE_IDX0 false
    #define DRV_I2C_SMBus_SPECIFICATION_IDX0 false
    #define DRV_I2C_BAUD_RATE_IDX0
    #define DRV_I2C_BRG_CLOCK_IDX0
    #define DRV_I2C_SLEW_RATE_CONTROL_IDX0 false
    #define DRV_I2C_POWER_STATE_IDX0
    #define DRV_I2C_INTERRUPT_MODE true

    #5
    LostInSpace
    Super Member
    • Total Posts : 226
    • Reward points : 0
    • Joined: 2016/03/11 22:47:59
    • Location: 0
    • Status: offline
    Re: PIC32MZ I2C Bit Bang Driver and I2C3 missing on Rev A3 2019/01/17 12:57:45 (permalink)
    0
    I wrote my own I2C to solve these issues. That won't help you but....
     
    On that I2C driver you have been trying - it is twiddling ports directly, not through the I2C hardware. 
    So in the ports configurator make sure that the pins are set as Pins, not wired through the I2C hardware. This is a common source of confusion.
     
    For instance on my driver I have to set the pins as: Digital Output, Open Collector. Then I have to tell the driver what pins it is to use for SDC and SCL (via #defines). Then it works.
     
    If I wire up the pins to the I2C peripheral module, naturally this module takes over the pins and it won't work, as then you can't twiddle the pins directly anymore.
     
    My bit bang driver uses "PLIB_PORTS_xxxx" commands to move the pins as required, as this is the "PIC32 Portable" way to manage pin writes and reads.
     
    Also see this post,
     
    https://www.microchip.com/forums/m983159.aspx

     
    HTH
     
     
    Also a note: Just because "system_config.h" has 'stuff' in it doesn't mean it works on actual hardware or the actual hardware works. They put the stuff in there whether the hardware works or not at the current rev, because everyone will assume that the hardware will work someday (or some version of the chip). As you have found Rev A3 fixes some bugs (yeah).
    post edited by LostInSpace - 2019/01/17 13:01:25
    #6
    campbellCustom
    Starting Member
    • Total Posts : 65
    • Reward points : 0
    • Joined: 2014/08/30 14:35:35
    • Location: 0
    • Status: offline
    Re: PIC32MZ I2C Bit Bang Driver and I2C3 missing on Rev A3 2019/01/17 14:42:01 (permalink)
    0
    As you have found Rev A3 fixes some bugs (yeah).

     
    Rev A1 had a buggy I2C3, Rev A3 has removed I2C3, making my problem much worse. Both revs have issues with all of the I2C peripherals having phantom errors. It looks like the next rev may fix the peripherals, but clearly my supplier is not using the next rev yet.
     
    I understand that the framework will not be aware of the revision.
    I had seen the post on the general Pic32 forum concerning the i2c_bitbang_isr files. Sadly the link to the source in that thread is dead.

    https://www.microchip.com/forums/m983159.aspx

     
    I expect the project that thread references contains the stuff that Harmony ported into a driver. I’m guessing based on the non-standard-for-harmony opening comments, that call a specific peripheral amongst other things. The opening comments mention: i2c_bitbang_isr.h which is a file that does not exist in harmony…
    The Harmony port has an init and a task that once generated are trying to be like a standard harmony driver, I’m hoping this generation is an error, because I’m near certain it won’t work for I2C3 … I can actually get a valid handle and attempt a write or read using the dynamic driver functions, just no wiggle at the output. I have tried this both ways (GPIO and I2C3, but thanks for heads up about not setting the peripheral through PPS)
    Here are the init and task code:

    /* Function:
        SYS_MODULE_OBJ DRV_I2C_Initialize ( const SYS_MODULE_INDEX  index,
                                           const SYS_MODULE_INIT * const init )
     
      Summary:
        Initializes hardware and data for the given instance of the I2C module
     
      Description:
        This routine initializes hardware for the instance of the I2C module,
        using the hardware initialization given data.  It also initializes all
        necessary internal data.
     
      Parameters:
        index           - Identifies the driver instance to be initialized
     
        init            - Pointer to the data structure containing all data
                          necessary to initialize the hardware. This pointer may
                          be null if no data is required and static initialization
                          values are to be used.
     
      Returns:
        If successful, returns a valid handle to a driver instance object.
        Otherwise, it returns SYS_MODULE_OBJ_INVALID.
     */
     
    SYS_MODULE_OBJ DRV_I2C_Initialize(const SYS_MODULE_INDEX drvIndex,
                                      const SYS_MODULE_INIT * const init) {
        DRV_I2C_INIT * i2cInit;
        I2C_MODULE_ID i2cId;
        /* Validate the driver index */
        if (drvIndex >= DRV_I2C_INSTANCES_NUMBER) {
            return SYS_MODULE_OBJ_INVALID;
        }
        DRV_I2C_OBJ *dObj = _DRV_I2C_INSTANCE_GET(drvIndex);
        /* Cheap dead man's mutex during initialization to make sure two different
           tasks don't try to initialize the same driver at the same time.*/
     
        if (dObj->inUse) {
            return SYS_MODULE_OBJ_INVALID;
        }
     
        if (i2cNumInited == 0) {
            memset(gDrvI2CClientObj, 0, sizeof (gDrvI2CClientObj));
        }
     
        i2cNumInited++;
     
        /* Assign to the local pointer the init data passed */
        i2cInit = (DRV_I2C_INIT *) init;
     
        /* Object is valid, set it in use */
        dObj->inUse = true;
     
        /* Save the index of the driver. Important to know this
        as we are using reference based accessing */
        dObj->drvIndex = drvIndex;
     
        /* Update the I2C Module Index */
        dObj->i2cId = i2cInit->i2cId;
     
        /* Update the I2C Module Index */
        dObj->i2cPerph = i2cInit->i2cPerph;
     
        /* assign SCL and SDA ports for bit banging purposes*/
        dObj->portSCL = i2cInit->portSCL;
        dObj->pinSCL = i2cInit->pinSCL;
        dObj->portSDA = i2cInit->portSDA;
        dObj->pinSDA = i2cInit->pinSDA;
     
        /* Enable the I2C module */
        if (DRV_I2C_BIT_BANG == i2cInit->i2cPerph) {
     
            dObj->tmrSource = i2cInit->tmrSource;
            dObj->tmrInterruptSource = i2cInit->tmrInterruptSource;
     
            //GJV
    #ifdef  BB_ENABLED
            DRV_I2C_BB_Initialize(dObj, i2cInit);
    #endif
        }
     
        /* Speed up accessing, take it to a local variable */
        i2cId = dObj->i2cId;
     
        /* Setup the Hardware */
        _DRV_I2C_SetupHardware(i2cId, dObj, i2cInit);
     
        /* Reset the number of clients */
        dObj->numClients = 0;
     
        /* Reset the locally used variables */
        dObj->lastClientHandle = DRV_I2C_CLIENTS_NUMBER + 1;
     
        dObj->operationStarting = i2cInit->operationStarting;
     
        /* Interrupt flag cleared on the safer side */
     
        _DRV_I2C_InterruptSourceClear(dObj->mstrInterruptSource);
        _DRV_I2C_InterruptSourceClear(dObj->slaveInterruptSource);
        _DRV_I2C_InterruptSourceClear(dObj->errInterruptSource);
     
        /* Set the current driver state */
        dObj->status = SYS_STATUS_READY;
     
        dObj->interruptNestingCount = 0;
     
        /* Create the hardware instance mutex. */
        if (OSAL_MUTEX_Create(&(dObj->mutexDriverInstance)) != OSAL_RESULT_TRUE) {
            return SYS_MODULE_OBJ_INVALID;
        }
     
        /* Check if the global mutexes have been created. If not
        then create these. */
     
        if (!gDrvI2CCommonDataObj.membersAreInitialized) {
            /* This means that mutexes where not created. Create them. */
            if (OSAL_MUTEX_Create(&(gDrvI2CCommonDataObj.mutexClientObjects)) != OSAL_RESULT_TRUE) {
                return SYS_MODULE_OBJ_INVALID;
            }
            if (OSAL_MUTEX_Create(&(gDrvI2CCommonDataObj.mutexBufferQueueObjects)) != OSAL_RESULT_TRUE) {
                return SYS_MODULE_OBJ_INVALID;
            }
            /* Set this flag so that global mutexes get allocated only once */
            gDrvI2CCommonDataObj.membersAreInitialized = true;
        }
     
    #if defined  __PIC32MZ &&  (__PIC32_FEATURE_SET0 == 'E') && (__PIC32_FEATURE_SET1 == 'C')
        if (DRV_I2C_PERIPHERAL == i2cInit->i2cPerph) {
            PLIB_PORTS_PinClear(PORTS_ID_0, dObj->portSDA, dObj->pinSDA); //SDA low
            PLIB_PORTS_PinSet(PORTS_ID_0, dObj->portSCL, dObj->pinSCL); //SCL high
            PLIB_PORTS_PinDirectionOutputSet(PORTS_ID_0, dObj->portSDA, dObj->pinSDA); //SDA output
            PLIB_PORTS_PinDirectionInputSet(PORTS_ID_0, dObj->portSCL, dObj->pinSCL); //SCL input
        }
    #endif
     
        /* Enable the I2C module */
        if (DRV_I2C_PERIPHERAL == i2cInit->i2cPerph) {
            PLIB_I2C_Enable(i2cId);
        } else {
            PLIB_I2C_Disable(i2cId);
        }
        /* Return the driver handle */
        return ( (SYS_MODULE_OBJ) dObj);
    } /* DRV_I2C_Initialize */
     
     
    /* Function:
        void DRV_I2C_Tasks ( SYS_MODULE_OBJ object )
     
      Summary:
        Used to maintain the driver's state machine and implement its ISR
     
      Description:
        This routine is used to maintain the driver's internal state machine and
        implement its ISR for interrupt-driven implementations.
     
      Parameters:
        object          - Identifies the Driver Object returned by the Initialize
                          interface
     
      Returns:
        None.
     */
     
    void DRV_I2C_Tasks(SYS_MODULE_OBJ object) {
        DRV_I2C_OBJ *dObj = (DRV_I2C_OBJ*) object;
        DRV_I2C_BUFFER_OBJECT *lBufferObj = dObj->taskLObj;
        //    uint8_t                 dummy           = 0xFF;
        I2C_MODULE_ID i2cId = dObj->i2cId;
        DRV_I2C_CLIENT_OBJ *lClientObj = NULL;
        //    static unsigned char bytecounter = 0;
        if (object == SYS_MODULE_OBJ_INVALID) {
            //SYS_ASSERT( " Handle is invalid " );
            return;
        }
        switch (dObj->task) {
            case DRV_I2C_TASK_SEND_DEVICE_ADDRESS:
     
                /* Pop the first element from the queue */
                if ((_DRV_I2C_OPERATION_MODE_GET(dObj->i2cMode)) == DRV_I2C_MODE_MASTER) {
                    if ((dObj->queueHead != NULL)) {
                        /* This should be a global variable since the control could
                        go out of this function */
     
                        dObj->taskLObj = _DRV_I2C_QueuePop(dObj);
     
                        /* Take it to a local variable to avoid multiple referencing and to speed up */
                        lBufferObj = dObj->taskLObj;
     
                        lClientObj = (DRV_I2C_CLIENT_OBJ *) lBufferObj->clientHandle;
     
                        /*  We need not do this all the time but when the request from a
                            new client  */
                        _DRV_I2C_CLIENT_SWITCH_CLIENT();
     
                        /* Update the task state as per the operation */
                        dObj->task = lBufferObj->operation + DRV_I2C_TASK_PROCESS_WRITE_ONLY;
     
                        if (lBufferObj->operation == DRV_I2C_OP_READ) {
                            _DRV_I2C_CLIENT_OBJ(lBufferObj, status) = 0;
                            _DRV_I2C_CLIENT_OBJ(lBufferObj, status) |=
                                    DRV_I2C_BUFFER_SLAVE_READ_REQUESTED;
                            dObj->modulemainstate = DRV_I2C_MASTER_RX_FROM_SLAVE;
                            PLIB_I2C_TransmitterByteSend(i2cId, (DRV_I2C_OP_READ | lBufferObj->slaveaddresshighbyte));
                            dObj->task = DRV_I2C_TASK_SET_RCEN_ONLY;
                        } else {
                            _DRV_I2C_CLIENT_OBJ(lBufferObj, status) = 0;
                            _DRV_I2C_CLIENT_OBJ(lBufferObj, status) |=
                                    DRV_I2C_BUFFER_SLAVE_WRITE_REQUESTED;
                            PLIB_I2C_TransmitterByteSend(i2cId, lBufferObj->slaveaddresshighbyte);
                        }
                    }
                } else if ((_DRV_I2C_OPERATION_MODE_GET(dObj->i2cMode)) == DRV_I2C_MODE_SLAVE) {
                    /* master writing data to slave when R/W = 0 and Address is detected */
                    dObj->task = DRV_I2C_TASK_SEND_DEVICE_ADDRESS;
     
                    /* Slave is accepting data from Master */
                    if ((!PLIB_I2C_SlaveReadIsRequested(i2cId)) && (PLIB_I2C_SlaveAddressIsDetected(i2cId))) {
                        /* slave is set to accept data from master */
                        dObj->modulemainstate = DRV_I2C_SLAVE_READY_TO_RX_FROM_MASTER;
     
                        if (lBufferObj) {
                            lBufferObj->inUse = false;
                        }
     
                        if (dObj->operationStarting) {
                            dObj->operationStarting(DRV_I2C_BUFFER_SLAVE_READ_REQUESTED, 0);
                        }
     
                        /* This should be a global variable since the control could
                            go out of this function */
                        dObj->taskLObj = _DRV_I2C_QueuePop(dObj);
     
                        /* Take it to a local variable to avoid multiple referencing and to speed up */
                        lBufferObj = dObj->taskLObj;
     
                        lBufferObj->actualtransfersize = 0;
     
                        Nop();
     
                        lClientObj = (DRV_I2C_CLIENT_OBJ *) lBufferObj->clientHandle;
     
                        Nop();
     
                        _DRV_I2C_CLIENT_SWITCH_CLIENT();
     
                        /* do a dummy read so that I2CxRCV is cleared and not clobbered with data */
                        PLIB_I2C_ReceivedByteGet(i2cId);
                        PLIB_I2C_SlaveClockRelease(i2cId);
                    }                    /*  Slave is sending data back to the Master    */
                    else if ((PLIB_I2C_SlaveReadIsRequested(i2cId)) && (PLIB_I2C_SlaveAddressIsDetected(i2cId))) {
     
                        PLIB_I2C_ReceivedByteGet(i2cId);
     
                        PLIB_I2C_SlaveClockHold(i2cId);
     
                        dObj->modulemainstate = DRV_I2C_SLAVE_READY_TO_TX_TO_MASTER;
                        if (lBufferObj) {
                            lBufferObj->inUse = false;
                        }
     
                        if (dObj->operationStarting) {
                            dObj->operationStarting(DRV_I2C_BUFFER_SLAVE_WRITE_REQUESTED, 0);
                        }
                        lBufferObj = dObj->taskLObj = _DRV_I2C_QueuePop(dObj);
     
                        lBufferObj->actualtransfersize = 0;
     
                        lClientObj = (DRV_I2C_CLIENT_OBJ *) lBufferObj->clientHandle;
     
                        _DRV_I2C_CLIENT_SWITCH_CLIENT();
     
                        // transmit first byte
                        PLIB_I2C_TransmitterByteSend(_DRV_I2C_PERIPHERAL_ID_GET(i2cId), *lBufferObj->txBuffer++);
                        lBufferObj->actualtransfersize++;
                        PLIB_I2C_SlaveClockRelease(i2cId);
                        PLIB_PORTS_PinSet(PORTS_ID_0, lClientObj->irqSelectPort, lClientObj->irqSelectBitPos); //Pull-High IRQ
                    } else if ((!PLIB_I2C_SlaveReadIsRequested(i2cId)) && PLIB_I2C_SlaveDataIsDetected(i2cId)) {
                        /*        Master sends data to the slave        */
                        if (dObj->modulemainstate == DRV_I2C_SLAVE_READY_TO_RX_FROM_MASTER) {
                            PLIB_I2C_SlaveClockRelease(i2cId);
     
                            if (lBufferObj->actualtransfersize < lBufferObj->transferSize) {
                                *lBufferObj->rxBuffer++ = PLIB_I2C_ReceivedByteGet(i2cId);
                                lBufferObj->actualtransfersize++;
                                _DRV_I2C_CLIENT_OBJ(lBufferObj, status) = 0;
                                _DRV_I2C_CLIENT_OBJ(lBufferObj, status) |=
                                        DRV_I2C_BUFFER_SLAVE_READ_BYTE;
     
                                /*  Call the event handler. Increment the interrupt nesting
                                    count which lets the driver functions that are called
                                    from the event handler know that an interrupt context
                                    is active.
                                 */
     
                                dObj->interruptNestingCount++;
     
                                if (_DRV_I2C_CLIENT_OBJ(((DRV_I2C_CLIENT_OBJ *) lBufferObj->clientHandle), callback) != NULL) {
                                    _DRV_I2C_CLIENT_OBJ(((DRV_I2C_CLIENT_OBJ *) lBufferObj->clientHandle),
                                            callback)(DRV_I2C_BUFFER_SLAVE_READ_BYTE, (DRV_I2C_BUFFER_HANDLE) lBufferObj, 0x00);
                                }
     
                                dObj->interruptNestingCount--;
                            } else {
                                _DRV_I2C_CLIENT_OBJ(lBufferObj, status) = 0;
                                _DRV_I2C_CLIENT_OBJ(lBufferObj, status) |=
                                        DRV_I2C_BUFFER_EVENT_ERROR;
     
                                PLIB_I2C_ReceivedByteGet(i2cId);
     
                                if (_DRV_I2C_CLIENT_OBJ(((DRV_I2C_CLIENT_OBJ *) lBufferObj->clientHandle), callback) != NULL) {
                                    _DRV_I2C_CLIENT_OBJ(((DRV_I2C_CLIENT_OBJ *) lBufferObj->clientHandle),
                                            callback)(DRV_I2C_BUFFER_EVENT_ERROR, (DRV_I2C_BUFFER_HANDLE) lBufferObj, 0x00);
                                }
                            }
                        }
                    } else if (PLIB_I2C_SlaveReadIsRequested(i2cId) && PLIB_I2C_SlaveDataIsDetected(i2cId)) {
                        PLIB_I2C_SlaveClockHold(i2cId);
     
                        if (PLIB_I2C_TransmitterByteWasAcknowledged(i2cId)) {
                            if (lBufferObj->actualtransfersize < lBufferObj->transferSize) {
                                PLIB_I2C_SlaveClockRelease(i2cId);
                                PLIB_I2C_TransmitterByteSend(_DRV_I2C_PERIPHERAL_ID_GET(i2cId), *lBufferObj->txBuffer++);
                                lBufferObj->actualtransfersize++;
                                lBufferObj->inUse = false;
     
                                _DRV_I2C_CLIENT_OBJ(lBufferObj, status) = 0;
                                _DRV_I2C_CLIENT_OBJ(lBufferObj, status) |=
                                        DRV_I2C_BUFFER_SLAVE_WRITE_BYTE;
     
                                /*  Call the event handler. Increment the interrupt nesting
                                    count which lets the driver functions that are called
                                    from the event handler know that an interrupt context
                                    is active.
                                 */
     
                                dObj->interruptNestingCount++;
     
                                if (_DRV_I2C_CLIENT_OBJ(((DRV_I2C_CLIENT_OBJ *) lBufferObj->clientHandle), callback) != NULL) {
                                    _DRV_I2C_CLIENT_OBJ(((DRV_I2C_CLIENT_OBJ *) lBufferObj->clientHandle),
                                            callback)(DRV_I2C_BUFFER_SLAVE_WRITE_BYTE, (DRV_I2C_BUFFER_HANDLE) lBufferObj, 0x00);
                                }
     
                                dObj->interruptNestingCount--;
                            } else {
                                _DRV_I2C_CLIENT_OBJ(lBufferObj, status) = 0;
                                _DRV_I2C_CLIENT_OBJ(lBufferObj, status) |=
                                        DRV_I2C_BUFFER_EVENT_ERROR;
     
                                /* Have a check here because DRV_I2C_ClientSetup function call is optional */
                                if (_DRV_I2C_CLIENT_OBJ(((DRV_I2C_CLIENT_OBJ *) lBufferObj->clientHandle), callback) != NULL) {
                                    /* Give an indication to the higher layer upon successful transmission */
                                    _DRV_I2C_CLIENT_OBJ(((DRV_I2C_CLIENT_OBJ *) lBufferObj->clientHandle), callback)
                                            (DRV_I2C_BUFFER_EVENT_ERROR, (DRV_I2C_BUFFER_HANDLE) lBufferObj, 0x00);
                                }
                                /* dummy write - pad with zeros - cases where master requests more data than what is in buffer */
                                PLIB_I2C_TransmitterByteSend(_DRV_I2C_PERIPHERAL_ID_GET(i2cId), 0);
                            }
                        } else if (!PLIB_I2C_TransmitterByteWasAcknowledged(i2cId)) {
     
                            _DRV_I2C_CLIENT_OBJ(lBufferObj, status) = 0;
                            _DRV_I2C_CLIENT_OBJ(lBufferObj, status) |=
                                    DRV_I2C_BUFFER_EVENT_COMPLETE;
     
                            dObj->interruptNestingCount++;
     
                            /* Have a check here because DRV_I2C_ClientSetup function call is optional */
                            if (_DRV_I2C_CLIENT_OBJ(((DRV_I2C_CLIENT_OBJ *) lBufferObj->clientHandle), callback) != NULL) {
                                /* Give an indication to the higher layer upon successful transmission */
                                _DRV_I2C_CLIENT_OBJ(((DRV_I2C_CLIENT_OBJ *) lBufferObj->clientHandle), callback)
                                        (DRV_I2C_BUFFER_EVENT_COMPLETE, (DRV_I2C_BUFFER_HANDLE) lBufferObj, 0x00);
                            }
     
                            dObj->interruptNestingCount--;
                        }
                    }
                }
                break;
            case DRV_I2C_SEND_RANDOM_READ_DEVICE_ADDRESS:
                dObj->modulemainstate = DRV_I2C_MASTER_RX_FROM_SLAVE;
                PLIB_I2C_TransmitterByteSend(i2cId, (DRV_I2C_OP_READ | lBufferObj->slaveaddresshighbyte));
                dObj->task = DRV_I2C_TASK_SET_RCEN_ONLY;
                break;
            case DRV_I2C_TASK_PROCESS_READ_ONLY:
                /* Read I2CxRCV register for received data */
                if ((_DRV_I2C_OPERATION_MODE_GET(dObj->i2cMode)) == DRV_I2C_MODE_MASTER) {
                    if (lBufferObj->transferSize) {
                        dObj->modulemainstate = DRV_I2C_MASTER_RX_FROM_SLAVE;
     
                        if (PLIB_I2C_ReceivedByteIsAvailable(i2cId)) {
                            /* If all but one reception is complete */
                            if (lBufferObj->transferSize > 1) {
                                *lBufferObj->rxBuffer++ = PLIB_I2C_ReceivedByteGet(i2cId);
                                lBufferObj->transferSize--;
                                dObj->task = DRV_I2C_TASK_SET_RCEN_ONLY;
                                if (PLIB_I2C_MasterReceiverReadyToAcknowledge(i2cId)) {
                                    PLIB_I2C_ReceivedByteAcknowledge(i2cId, true);
                                }
                            } else {
                                lBufferObj->transferSize--;
     
                                //                                lBufferObj->inUse = false;
     
                                *lBufferObj->rxBuffer++ = PLIB_I2C_ReceivedByteGet(i2cId);
                                if (PLIB_I2C_MasterReceiverReadyToAcknowledge(i2cId)) {
                                    PLIB_I2C_ReceivedByteAcknowledge(i2cId, false);
                                }
     
                                dObj->task = DRV_I2C_BUS_SILENT;
                            }
                        } else {
                            // Do not block in any case
                            break;
                        }
                    }
                }
                break;
            case DRV_I2C_TASK_PROCESS_WRITE_ONLY:
            case DRV_I2C_TASK_PROCESS_WRITE_READ:
     
                if ((_DRV_I2C_OPERATION_MODE_GET(dObj->i2cMode)) == DRV_I2C_MODE_MASTER) {
                    /* Loop till the transmit size, do not block though */
                    if (lBufferObj->transferSize) {
                        if (PLIB_I2C_TransmitterByteHasCompleted(_DRV_I2C_PERIPHERAL_ID_GET(i2cId))) {
                            if (PLIB_I2C_TransmitterByteWasAcknowledged(_DRV_I2C_PERIPHERAL_ID_GET(i2cId))) {
     
                                //                                lBufferObj->inUse = false;
     
                                /* Handle the overflow */
                                if (lBufferObj->transferSize > 1) {
                                    PLIB_I2C_TransmitterByteSend(_DRV_I2C_PERIPHERAL_ID_GET(i2cId), *lBufferObj->txBuffer++);
                                    lBufferObj->transferSize--;
                                } else {
                                    lBufferObj->transferSize--;
     
                                    //                                    /* Hold the buffer till the completion of the operation */
                                    //                                    lBufferObj->inUse = false;
     
                                    PLIB_I2C_TransmitterByteSend(_DRV_I2C_PERIPHERAL_ID_GET(i2cId), *lBufferObj->txBuffer++);
     
                                    dObj->task = DRV_I2C_BUS_SILENT;
     
                                }
                            } else {
     
    #if defined  __PIC32MZ &&  (__PIC32_FEATURE_SET0 == 'E') && (__PIC32_FEATURE_SET1 == 'C')
                                /*   Errata for PIC32MZ which requires reset of I2C module */
     
                                dObj->task = DRV_I2C_TASK_SEND_DEVICE_ADDRESS;
     
                                /* alternate method to do STOP (previous errata note) */
     
    #ifdef MZ_EC_ERRATA_25_BB_STOP               //GJV
                                /* Bit bang procedure for STOP */
     
                                starttime = ReadCoreTimer();
                                while (ReadCoreTimer() - starttime < BRG_1_TIME_0);
     
                                /* Disable I2C */
                                PLIB_I2C_Disable(i2cId);
     
                                /* Wait 2 BRG */
                                starttime = ReadCoreTimer();
                                while (ReadCoreTimer() - starttime < BRG_1_TIME_0);
     
                                /* Set SDA as I/P */
                                PLIB_PORTS_PinDirectionInputSet(PORTS_ID_0, dObj->portSDA, dObj->pinSDA);
     
                                /* Wait 3 BRG */
                                starttime = ReadCoreTimer();
                                while (ReadCoreTimer() - starttime < BRG_1_TIME_0);
     
                                PLIB_I2C_Enable(i2cId);
                                PLIB_PORTS_PinClear(PORTS_ID_0, dObj->portSDA, dObj->pinSDA);
                                PLIB_PORTS_PinSet(PORTS_ID_0, dObj->portSCL, dObj->pinSCL);
                                PLIB_PORTS_PinDirectionOutputSet(PORTS_ID_0, dObj->portSDA, dObj->pinSDA);
                                PLIB_PORTS_PinDirectionInputSet(PORTS_ID_0, dObj->portSCL, dObj->pinSCL);
     
                                /* End-of-Bit-Bang procedure for STOP */
    #else                                                   //GJV
                                PLIB_I2C_Disable(i2cId);
                                PLIB_I2C_Enable(i2cId);
    #endif                                                  //GJV
     
                                if (lBufferObj) {
                                    lBufferObj->inUse = false;
                                }
     
                                /*clear any previous status flags */
                                _DRV_I2C_CLIENT_OBJ(lBufferObj, status) = 0;
     
                                /* set status to buffer event complete */
                                _DRV_I2C_CLIENT_OBJ(lBufferObj, status) |=
                                        DRV_I2C_BUFFER_EVENT_COMPLETE;
     
                                /* Have a check here because DRV_I2C_ClientSetup function call is optional */ //Issue Callback for STOP event
                                if (_DRV_I2C_CLIENT_OBJ(((DRV_I2C_CLIENT_OBJ *) lBufferObj->clientHandle), callback) != NULL) {
                                    /* Give an indication to the higher layer upon successful transmission */
                                    _DRV_I2C_CLIENT_OBJ(((DRV_I2C_CLIENT_OBJ *) lBufferObj->clientHandle), callback)
                                            (DRV_I2C_SEND_STOP_EVENT, (DRV_I2C_BUFFER_HANDLE) lBufferObj, 0x00);
                                }
    #else
                                dObj->task = DRV_I2C_TASK_PROCESS_STOP;
                                PLIB_I2C_MasterStop(i2cId);
    #endif
     
                            }
                        } else {
                            /* Do not block in any case */
                            break;
                        }
                    }
                }
                break;
            case DRV_I2C_BUS_SILENT:
     
                /*  The Bus is Silent/Idle when the last byte is either ACK'ed  OR
                    in the event of slave unexpectedly aborting operation, check
                    if transmission is complete and NACK is received   */
     
                if (PLIB_I2C_TransmitterByteWasAcknowledged(_DRV_I2C_PERIPHERAL_ID_GET(i2cId)) ||
                        (PLIB_I2C_TransmitterByteHasCompleted(_DRV_I2C_PERIPHERAL_ID_GET(i2cId)) &&
                        (!PLIB_I2C_TransmitterByteWasAcknowledged(_DRV_I2C_PERIPHERAL_ID_GET(i2cId))))) {
                    if (lBufferObj->operation == DRV_I2C_OP_WRITE_READ) {
     
                        SYS_INT_SourceStatusClear(dObj->mstrInterruptSource);
     
                        //                        dObj->task = DRV_I2C_TASK_SEND_DEVICE_ADDRESS;          //Go to START condition
                        dObj->task = DRV_I2C_SEND_RANDOM_READ_DEVICE_ADDRESS;
     
                        lBufferObj->operation = DRV_I2C_OP_READ;
     
                        lBufferObj->transferSize = lBufferObj->readtransferSize; //Assign # of bytes to be read into transfer size
     
                        //                        _DRV_I2C_QueuePush( dObj, lBufferObj);
     
                        _DRV_I2C_CLIENT_OBJ(lBufferObj, status) = 0;
     
                        _DRV_I2C_CLIENT_OBJ(lBufferObj, status) |=
                                DRV_I2C_SEND_RESTART_EVENT;
     
                        PLIB_I2C_MasterStartRepeat(dObj->i2cId);
                    } else {
    #if defined  __PIC32MZ &&  (__PIC32_FEATURE_SET0 == 'E') && (__PIC32_FEATURE_SET1 == 'C')
                        _DRV_I2C_InterruptSourceDisable(_DRV_I2C_INT_SRC_GET(dObj->mstrInterruptSource));
                        dObj->task = DRV_I2C_TASK_SEND_DEVICE_ADDRESS;
    #else
                        dObj->task = DRV_I2C_TASK_PROCESS_STOP;
    #endif
     
    #if defined  __PIC32MZ &&  (__PIC32_FEATURE_SET0 == 'E') && (__PIC32_FEATURE_SET1 == 'C')
                        /*   Errata for PIC32MZ which requires reset of I2C module */
     
    #ifdef MZ_EC_ERRATA_25_BB_STOP               //GJV
                        /* Bit bang procedure for STOP */
     
                        starttime = ReadCoreTimer();
                        while (ReadCoreTimer() - starttime < BRG_1_TIME_0);
     
                        /* Disable I2C */
                        PLIB_I2C_Disable(i2cId);
     
                        /* Wait 2 BRG */
                        starttime = ReadCoreTimer();
                        while (ReadCoreTimer() - starttime < BRG_1_TIME_0);
     
                        /* Set SDA as I/P */
                        PLIB_PORTS_PinDirectionInputSet(PORTS_ID_0, dObj->portSDA, dObj->pinSDA);
     
                        /* Wait 3 BRG */
                        starttime = ReadCoreTimer();
                        while (ReadCoreTimer() - starttime < BRG_1_TIME_0);
     
                        PLIB_I2C_Enable(i2cId);
                        PLIB_PORTS_PinClear(PORTS_ID_0, dObj->portSDA, dObj->pinSDA);
                        PLIB_PORTS_PinSet(PORTS_ID_0, dObj->portSCL, dObj->pinSCL);
                        PLIB_PORTS_PinDirectionOutputSet(PORTS_ID_0, dObj->portSDA, dObj->pinSDA);
                        PLIB_PORTS_PinDirectionInputSet(PORTS_ID_0, dObj->portSCL, dObj->pinSCL);
    #else
                        /* alternate method to do STOP (previous errata note) */
                        PLIB_I2C_Disable(i2cId);
                        PLIB_I2C_Enable(i2cId);
    #endif
     
                        /* End-of-Bit-Bang procedure for STOP */
     
                        if (lBufferObj) {
                            lBufferObj->inUse = false;
                        }
     
                        /* set buffer event complete status and callback here instead of STOP condition
                        because STOP condition is PIC32MZ-EC is bit-banged and would not generate an interrupt  */
                        dObj->task = DRV_I2C_TASK_SEND_DEVICE_ADDRESS;
     
                        /*clear any previous status flags */
                        _DRV_I2C_CLIENT_OBJ(lBufferObj, status) = 0;
     
                        /* set status to buffer event complete */
                        _DRV_I2C_CLIENT_OBJ(lBufferObj, status) |=
                                DRV_I2C_BUFFER_EVENT_COMPLETE;
     
                        if (_DRV_I2C_CLIENT_OBJ(((DRV_I2C_CLIENT_OBJ *) lBufferObj->clientHandle), callback) != NULL) {
                            /* Give an indication to the higher layer upon successful transmission */
                            _DRV_I2C_CLIENT_OBJ(((DRV_I2C_CLIENT_OBJ *) lBufferObj->clientHandle), callback)
                                    (DRV_I2C_BUFFER_EVENT_COMPLETE, (DRV_I2C_BUFFER_HANDLE) lBufferObj, 0x00);
                        }
    #else
                        PLIB_I2C_MasterStop(i2cId);
    #endif
                    }
                }
                break;
            case DRV_I2C_TASK_SET_RCEN_ONLY:
                if ((PLIB_I2C_TransmitterByteWasAcknowledged(i2cId)) ||
                        ((PLIB_I2C_ReceiverByteAcknowledgeHasCompleted(i2cId) == true))) {
                    PLIB_I2C_MasterReceiverClock1Byte(i2cId);
                    dObj->task = DRV_I2C_TASK_PROCESS_READ_ONLY;
                } else {
                    dObj->task = DRV_I2C_TASK_PROCESS_STOP;
                    _DRV_I2C_CLIENT_OBJ(lBufferObj, status) |=
                            DRV_I2C_SEND_STOP_EVENT;
                    /* Have a check here because DRV_I2C_ClientSetup function call is optional */
                    if (_DRV_I2C_CLIENT_OBJ(((DRV_I2C_CLIENT_OBJ *) lBufferObj->clientHandle), callback) != NULL) {
                        /* Give an indication to the higher layer upon successful transmission */
                        _DRV_I2C_CLIENT_OBJ(((DRV_I2C_CLIENT_OBJ *) lBufferObj->clientHandle), callback)
                                (DRV_I2C_SEND_STOP_EVENT, (DRV_I2C_BUFFER_HANDLE) lBufferObj, 0x00);
                    }
                }
                break;
            case DRV_I2C_TASK_PROCESS_STOP:
     
    #if defined (DRV_I2C_INTERRUPT_MODE) && (DRV_I2C_INTERRUPT_MODE == true)
                _DRV_I2C_InterruptSourceDisable(_DRV_I2C_INT_SRC_GET(dObj->mstrInterruptSource));
    #endif
                if (lBufferObj) {
                    lBufferObj->inUse = false;
                }
     
                dObj->task = DRV_I2C_TASK_SEND_DEVICE_ADDRESS;
                _DRV_I2C_CLIENT_OBJ(lBufferObj, status) = 0;
     
     
                _DRV_I2C_CLIENT_OBJ(lBufferObj, status) |=
                        DRV_I2C_BUFFER_EVENT_COMPLETE;
     
                /* Have a check here because DRV_I2C_ClientSetup function call is optional */
                if (_DRV_I2C_CLIENT_OBJ(((DRV_I2C_CLIENT_OBJ *) lBufferObj->clientHandle), callback) != NULL) {
                    /* Give an indication to the higher layer upon successful transmission */
                    _DRV_I2C_CLIENT_OBJ(((DRV_I2C_CLIENT_OBJ *) lBufferObj->clientHandle), callback)
                            (DRV_I2C_BUFFER_EVENT_COMPLETE, (DRV_I2C_BUFFER_HANDLE) lBufferObj, 0x00);
                }
     
                break;
            default:
                break;
     
        }
     
        /* This state is encountered when an error interrupt has occurred.
           or an error has occurred during read */
     
        if (true == _DRV_I2C_InterruptSourceStatusGet(dObj->errInterruptSource)) {
            /* Check for the overflow error */
            if (PLIB_I2C_ReceiverOverflowHasOccurred(i2cId)) {
                if (PLIB_I2C_ExistsReceiverOverflow(i2cId)) {
                    PLIB_I2C_ReceiverOverflowClear(i2cId);
                }
            }
     
            _DRV_I2C_InterruptSourceClear(dObj->errInterruptSource);
        }
     
        if (SYS_INT_SourceStatusGet(dObj->mstrInterruptSource)) {
            SYS_INT_SourceStatusClear(dObj->mstrInterruptSource);
        }
        if (SYS_INT_SourceStatusGet(dObj->slaveInterruptSource)) {
            SYS_INT_SourceStatusClear(dObj->slaveInterruptSource);
            PLIB_I2C_SlaveClockRelease(i2cId);
        }
        if (SYS_INT_SourceStatusGet(dObj->errInterruptSource)) {
            SYS_INT_SourceStatusClear(dObj->errInterruptSource);
        }
     
        if ((dObj->queueHead != NULL) && (_DRV_I2C_CLIENT_OBJ(lBufferObj, status) == DRV_I2C_BUFFER_EVENT_COMPLETE)) {
            _DRV_I2C_InterruptSourceEnable(dObj->mstrInterruptSource);
     
            if (PLIB_I2C_BusIsIdle(dObj->i2cId)) {
                PLIB_I2C_MasterStart(dObj->i2cId);
                Nop();
            }
        }
     
    } /* DRV_I2C_TASKS */

     
    My concern is mostly about how this stuff got ported into Harmony, what the intent of the bit bang library is (and at this point I think they wanted to do a hybrid of both using the peripheral and the GPIO, which would fix issues with all the I2C peripherals that aren’t #3) and I’m trying to do something portable (in terms of moving forward). I’ve been hesitant to move to MZ because I wanted to wait long enough for the kinks to be worked out.
     
    The way this has been going, starting over at a lower abstraction level brings me to the logical conclusion that I’ll be writing machine code NVM handlers in 2023. (joking kind of)
    #7
    LostInSpace
    Super Member
    • Total Posts : 226
    • Reward points : 0
    • Joined: 2016/03/11 22:47:59
    • Location: 0
    • Status: offline
    Re: PIC32MZ I2C Bit Bang Driver and I2C3 missing on Rev A3 2019/01/18 15:23:02 (permalink)
    0
    Well, the Errata suggests that I2C has been fixed for MZ parts in rev: B2 Silicon. You may be able to call DigiKey and request a certain rev of Silicon (you need to know the magic date code, which Microchip knows and DigiKey probably knows also).
     
    And yes - the compiler has no way of knowing which chip rev you will eventually be burning.
     
    Yes, that link is incomplete (darn) - somehow I found the file somewhere though on the interwebs - I have t here on my disk. I did not use it because it uses ISR's, I did not want that mode of operation. I just wrote my own from the Philips / NXP application notes.
     
    HTH
     
    #8
    campbellCustom
    Starting Member
    • Total Posts : 65
    • Reward points : 0
    • Joined: 2014/08/30 14:35:35
    • Location: 0
    • Status: offline
    Re: PIC32MZ I2C Bit Bang Driver and I2C3 missing on Rev A3 2019/01/18 17:32:04 (permalink)
    0
    It may come to being picky about production I guess. 
     
    Still couldn't scare up that project file... looked around the website and the google.
     
    My application is running the TCPIP stack in a co-operative task loop and sending quite a bit of data out of a couple of SPI ports. I'd love to hack in a blocking routine... but... not really an option. I think I'll be ok with a timer interrupting at the bit-rate if I take some care with when the NVM stuff happens.
     
    On the Harmony front, I think the ISR based software in that previous thread is shoe-horned into the drv_i2c_bb.c framework file, which is then wrapped in a semi-harmony-compliant set of functions in drv_i2c_bb_a.c 
     
    The _a file is the one that seems to still be calling the PLIB_I2C_xxxxx stuff, which may or may not matter if the calls to the other file are behaving. (or perhaps there is a code generation problem... could very well be the check boxes I've chosen... or... ???)
     
    The drv_i2c_bb.c (without the _a) is only working with Ports calls, and makes no reference to the peripheral(good news). It may be a matter of figuring out where to tweak the init, task, and ISR functions to stick with what is in the non _a file (as of now I am not using an RTOS... so things like OSAL don't matter)
     
    The trouble is I can't find the ISR. It seems like it wants the ISR task function in drv_i2c_bb.c to be called from a timer interrupt. Harmony has a MHC drag down to choose a timer. Normally a timer driver's ISR would be in system_interrupt.c ... but nothing there (still maybe a code generation problem?) If I need to register an alarm call back or something I could do it, but once you turn on a separate timer driver in MHC (TMR_9 in my case)there is a red error indication on both redundant fields. I take this to mean the bit bang driver will generate an ISR someplace other than the standard place... but where?
     
    I'm thinking about putting in a different timer, and calling the state machine from there. Can't tell if this is time well spent, or just go for the DIY bit bang (I'm sure you're all happy with your libraries :) I just don't have one... and may be forced into an RTOS in the long run...)
     
    Anyway, someone spent some time on putting this stuff in there. It'd be nice to see it work. Nicer to see it work with standard function calls I can use when I2C isn't broken on the next chip upgrade... (a person can dream! right?)
     
    If I get it working I'll post back here. 
     
    Thanks all
     
    #9
    LostInSpace
    Super Member
    • Total Posts : 226
    • Reward points : 0
    • Joined: 2016/03/11 22:47:59
    • Location: 0
    • Status: offline
    Re: PIC32MZ I2C Bit Bang Driver and I2C3 missing on Rev A3 2019/01/18 21:38:24 (permalink)
    5 (1)
    Well, lets see if I can attach the Bit Bang Code file for you.
     
    Hope this works....
     
    Hey look! It looks like it worked.... Wow - It's 2019 and I can attach files to posts. Will wonders never cease!  ;-)
    post edited by LostInSpace - 2019/01/18 21:40:06
    #10
    campbellCustom
    Starting Member
    • Total Posts : 65
    • Reward points : 0
    • Joined: 2014/08/30 14:35:35
    • Location: 0
    • Status: offline
    Re: PIC32MZ I2C Bit Bang Driver and I2C3 missing on Rev A3 2019/01/21 12:26:47 (permalink)
    4 (1)
    Many thanks for the post and project. My suspicions are confirmed that the older project was adapted to harmony. I didn't check if it's possible to run the harmony version as a task rather than an ISR, as I'm going the ISR route... but I've finally got some bit wiggle on the data and clock lines. Yay!
     
    The I2C -> Use I2C Driver? -> I2C Driver Instance X -> Interrupt Mode [Check Box]
    is directly linked to the lines of code in system_interrupt.c

    void __ISR(_TIMER_9_VECTOR, ipl3AUTO) _IntHandlerDrvI2CMasterInstance0(void)
    {
    DRV_I2C_BB_Tasks(sysObj.drvI2C0);
    PLIB_INT_SourceFlagClear(INT_ID_0, INT_SOURCE_TIMER_9);
    }

     
    The timer init does not require additional check boxes (such as in the timer driver check box section). The I2C harmony driver sort of hijacks timer 9 as a default. I started a new project and confirmed this. I'm not sure why I wasn't seeing the ISR in the previous project, either I messed up something in the MHC file during my many check box tests, or I was being sloppy with the merging tool. (still could be PICNIC bug...)
     
    Additionally the GPIO settings in the pin manager are set as open drain GPIO inputs, rather than I2C peripheral. 
     
    I used these functions to get some bit wiggle:
    DRV_I2C_Open
    DRV_I2C_MasterBufferRead
     
    It looks like there are some functions ending in XE that support the extended addressing 
     
    Hope this thread saves someone some time... 
     
    Thanks all
    #11
    LostInSpace
    Super Member
    • Total Posts : 226
    • Reward points : 0
    • Joined: 2016/03/11 22:47:59
    • Location: 0
    • Status: offline
    Re: PIC32MZ I2C Bit Bang Driver and I2C3 missing on Rev A3 2019/02/01 19:16:07 (permalink)
    0
    I found the Microchip link to the bit bang code for the PIC32MZ. Well I stumbled across it once again....
     
    If you look at a PIC32MZ2048EFH064 data page for example. Scroll down to Code Examples, then you will find this description and link....
     
    I2C Master Bit Bang software emulation example *Non Harmony
     
    Also just looking around MHC today, I believe the Bit Bang check mark option only shows up when you select the Dynamic I2C drivers.
    #12
    Paul PortSol
    Super Member
    • Total Posts : 430
    • Reward points : 0
    • Joined: 2015/07/03 11:52:03
    • Location: Newfoundland, Canada
    • Status: offline
    Re: PIC32MZ I2C Bit Bang Driver and I2C3 missing on Rev A3 2019/02/04 11:48:06 (permalink)
    0
    Useful: create a fresh dummy project and use the "generate app code" option at the top of MHC when declaring tasks, then do normal MHC generate. Compare the whole generated project tree versus one without the "generated app" option to see what MHC added. Careful, most of those add a BSP, simply disable the BSP option for this compare.
     
    Doing that is how I got most modules to work in HarmonyV2xx.
     
    Paul
    #13
    Jump to:
    © 2019 APG vNext Commercial Version 4.5