Post Go back to editing

max32660 as I2C slave problem

Category: Datasheet/Specs
Product Number: MAX32660

Hello,

I am new to the max32660 so please forgive me if I am missing something silly.

I am trying to develop and application where both I2C interfaces of the max32660 will be used: one as cotroller (I2C0), one as client (I2C1).

To begin with, I started by modifying the I2C example program, removing everything linked to the controller (see code below). I am then using an external mcu to as i2c controller to write 4 bytes to the max32660.

The problem I am facing is that on the first communication, the max32660 acknowledges the first byte and then holds the clock low, missing the remaining 7 bytes. After this first "failed" attempt, the communication happens without problems (see image below). The clock being held low happens even if I disable the clock stretching functionality (as in the code below). I have also tried checking the program flow by debugging, but I don't see differences between the first run and successive ones.

My setup is the following:

    - Eclipse Version: 2022-12 (4.26.0)

    - Maxim Micros SDK 1.0.1 (Windows)

    - Max32660 Evsys Rev. B

    - 10k pullup resistors to 3.3V on SDA and SCL (P0.3 and P0.2)

I am really lost at this point. Any help would be greatly appreciated.

/**
 * @file        main.c
 * @brief       I2C Master-Slave Transaction Demo
 * @details     This example uses the I2C Master to read/write from/to the I2C Slave. 
 *              For this example, user must connect I2C Master SCL pin to I2C Slave SCL 
 *              pin and I2C Master SDA pin to I2C Slave SDA pin. User must also connect
 *              the pull-up jumpers to the proper I/O voltage. Refer UART messages for
 *              more information.
 * @note        Other devices on the EvKit might be using the same I2C bus. While 
 *              combining this example with other examples, make sure I2C pins are not
 *              being used in other examples of any other function (like GPIO).
 */

/***** Includes *****/

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "mxc_device.h"
#include "mxc_delay.h"
#include "mxc_errors.h"
#include "nvic_table.h"
#include "i2c.h"
#include "dma.h"

/***** Definitions *****/

//#define MASTERDMA //Comment this line out if standard I2C transaction is required

#define I2C_SLAVE MXC_I2C1

#define I2C_FREQ 100000
#define I2C_SLAVE_ADDR (0x51)
#define I2C_BYTES 8

/***** Globals *****/

static uint8_t Stxdata[I2C_BYTES];
static uint8_t Srxdata[I2C_BYTES];

volatile int I2C_FLAG = 0;
volatile int txnum = 0;
volatile int txcnt = 0;
volatile int rxnum = 0;

/***** Functions *****/

//Slave interrupt handler
void I2C1_IRQHandler(void)
{
    MXC_I2C_AsyncHandler(I2C_SLAVE);
}

//I2C callback function
void I2C_Callback(mxc_i2c_req_t *req, int error)
{
    I2C_FLAG = error;
}

int slaveHandler(mxc_i2c_regs_t *i2c, mxc_i2c_slave_event_t event, void *data)
{
    switch (event) {
    case MXC_I2C_EVT_MASTER_WR:
        // If we're being written to
        // Clear bytes written
        rxnum = 0;
        break;

    case MXC_I2C_EVT_MASTER_RD:
        txnum = I2C_BYTES;
        txcnt = 0;
        i2c->intfl0 = MXC_F_I2C_INTFL0_TXLOI | MXC_F_I2C_INTFL0_AMI;
        break;

    case MXC_I2C_EVT_RX_THRESH:
    case MXC_I2C_EVT_OVERFLOW:
        rxnum += MXC_I2C_ReadRXFIFO(i2c, &Srxdata[rxnum], MXC_I2C_GetRXFIFOAvailable(i2c));
        if (rxnum == I2C_BYTES) {
            i2c->inten0 |= MXC_F_I2C_INTEN0_AMIE;
        }

        break;

    case MXC_I2C_EVT_TX_THRESH:
    case MXC_I2C_EVT_UNDERFLOW:
        // Write as much data as possible into TX FIFO
        // Unless we're at the end of the transaction (only write what's needed)
        if (txcnt >= txnum) {
            break;
        }

        int num = MXC_I2C_GetTXFIFOAvailable(i2c);
        num = (num > (txnum - txcnt)) ? (txnum - txcnt) : num;
        txcnt += MXC_I2C_WriteTXFIFO(i2c, &Stxdata[txcnt], num);
        break;

    default:
        if (*((int *)data) == E_COMM_ERR) {
            printf("I2C Slave Error!\n");
            printf("i2c->intfl0 = 0x%08x\n", i2c->intfl0);
            printf("i2c->status = 0x%08x\n", i2c->status);
            I2C_Callback(NULL, E_COMM_ERR);
            return 1;

        } else if (*((int *)data) == E_NO_ERROR) {
            rxnum += MXC_I2C_ReadRXFIFO(i2c, &Srxdata[rxnum], MXC_I2C_GetRXFIFOAvailable(i2c));
            I2C_Callback(NULL, E_NO_ERROR);
            return 1;
        }
    }

    return 0;
}

// *****************************************************************************
int main()
{
    int error;

    //Setup the I2CS
    error = MXC_I2C_Init(I2C_SLAVE, 0, I2C_SLAVE_ADDR);
    if (error != E_NO_ERROR) {
        return error;
    }
    error=MXC_I2C_SetClockStretching(I2C_SLAVE, 0);
	if (error != E_NO_ERROR) {
		return error;
	}

    MXC_NVIC_SetVector(I2C1_IRQn, I2C1_IRQHandler);
    NVIC_EnableIRQ(I2C1_IRQn);
    __enable_irq();


    MXC_I2C_SetFrequency(I2C_SLAVE, I2C_FREQ);

    I2C_FLAG = 1;

    //Setup slave async. The function internally sets RXThreshold = 1
    if ((error = MXC_I2C_SlaveTransactionAsync(I2C_SLAVE, slaveHandler)) != 0) {
    	return error;
    }

    if (error != E_NO_ERROR) {
    		return error;
        }
    while(1){
    	// Resetting slave async if previous communication ended ok
    	if(I2C_FLAG != 1){
    		if(I2C_FLAG != E_NO_ERROR){
    			break;
    		}
    		I2C_FLAG=1;
    		if ((error = MXC_I2C_SlaveTransactionAsync(I2C_SLAVE, slaveHandler)) != 0) {
				break;
			}
    	}
    }
    MXC_I2C_Shutdown(I2C_SLAVE);

    return E_NO_ERROR;
}