This thread has been locked.

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

CCS/EK-TM4C129EXL: Write data goes missing

Part Number: EK-TM4C129EXL


Tool/software: Code Composer Studio

I working on a project to communicate with Max30101 sensor to read SP02 data. However using the scope. I realised that 1byte from the write data goes missing during the I2CSend . The code looks as below.

klib1.h is the modified version of https://github.com/sparkfun/SparkFun_MAX3010x_Sensor_Library/blob/master/src/MAX30105.cpp. For instance when  I attempted "I2CSend(I2CDEVICE_ADDR, 2,MAX30105_LED1_PULSEAMP , 0x01);", at times  I am able to turn on the Red Led as expected. But this is not always the case. Majority of the time, "MAX30105_LED1_PULSEAMP" will go missing and hence the Red Led is not turned on.

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "inc/hw_i2c.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "driverlib/i2c.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"
#include "sensorlib/klib1.h"

uint32_t ui32SysClock;
uint32_t RxData;
uint32_t delay = 25000000/3; //1 sec delay. Divide 3 cz 3 clk cycles.

static unsigned long WaitI2CDone( unsigned int long ulBase){
    // Wait until done transmitting
    while( I2CMasterBusy(I2C0_BASE));
    // Return I2C error code
    return I2CMasterErr(I2C0_BASE);
}

//I2C SEND function
//sends an I2C command to the specified slave
//eg: I2CSend(LCD_SLAVE_ADDR, 3, LCD_CMD, 0x50, contrast);
void I2CSend(uint8_t slave_addr, uint8_t num_of_args, ...)
{
	uint8_t i = 0;
    // Tell the master module what address it will place on the bus when
    // communicating with the slave.
    I2CMasterSlaveAddrSet(I2C0_BASE, slave_addr, false);

    //stores list of variable number of arguments
    va_list vargs;

    //specifies the va_list to "open" and the last fixed argument
    //so vargs knows where to start looking
    va_start(vargs, num_of_args);

    //put data to be sent into FIFO
    I2CMasterDataPut(I2C0_BASE, va_arg(vargs, uint32_t));

    //if there is only one argument, we only need to use the
    //single send I2C function
    if(num_of_args == 1)
    {
        //Initiate send of data from the MCU
        I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND);

        // Wait until MCU is done transferring.
        while(I2CMasterBusy(I2C0_BASE));

        //"close" variable argument list
        va_end(vargs);
    }

    //otherwise, we start transmission of multiple bytes on the
    //I2C bus
    else
    {
        //Initiate send of data from the MCU
        I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);

        // Wait until MCU is done transferring.
        while(I2CMasterBusy(I2C0_BASE));

        //send num_of_args-2 pieces of data, using the
        //BURST_SEND_CONT command of the I2C module
        for(i = 1; i < (num_of_args - 1); i++)
        {
            //put next piece of data into I2C FIFO
            I2CMasterDataPut(I2C0_BASE, va_arg(vargs, uint32_t));
            //send next data that was just placed into FIFO
            I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);

            // Wait until MCU is done transferring.
            while(I2CMasterBusy(I2C0_BASE));
        }

        //put last piece of data into I2C FIFO
        I2CMasterDataPut(I2C0_BASE, va_arg(vargs, uint32_t));
        //send next data that was just placed into FIFO
        I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
        // Wait until MCU is done transferring.
        while(I2CMasterBusy(I2C0_BASE));

        //"close" variable args list
        va_end(vargs);
    }
}

//I2C RECEIVE function
//read specified register on slave device
uint32_t I2CReceive(uint32_t slave_addr, uint8_t reg)
{
	uint8_t data = 0;
	int16_t i2c_err = I2C_MASTER_ERR_NONE;
    //specify that we are writing (a register address) to the
    //slave device
    I2CMasterSlaveAddrSet(I2C0_BASE, slave_addr, false);

    //specify register to be read
    I2CMasterDataPut(I2C0_BASE, reg);

    //send control byte and register address byte to slave device
    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);

    //wait for MCU to finish transaction
    while(I2CMasterBusy(I2C0_BASE));

    //specify that we are going to read from slave device
    I2CMasterSlaveAddrSet(I2C0_BASE, slave_addr, true);

    //send control byte and read from the register we
    //specified
    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);

    if(i2c_err != WaitI2CDone( I2C0_BASE)){
        data = I2CMasterDataGet(I2C0_BASE);
    	UARTprintf("Read error in data: %x\n", data);
    }

    //wait for MCU to finish transaction
    while(I2CMasterBusy(I2C0_BASE));

    //return data pulled from the specified register
    return I2CMasterDataGet(I2C0_BASE);
}

void bitMask(uint8_t reg, uint8_t mask, uint8_t thing)
{
  // Grab current register context
  uint8_t originalContents = I2CReceive(I2CDEVICE_ADDR, reg);

  // Zero-out the portions of the register we're interested in
  originalContents = originalContents & mask;

  // Change contents
  I2CSend(I2CDEVICE_ADDR, 2, reg, originalContents | thing);
}

void setFIFOAverage(uint8_t numberOfSamples) {
  bitMask(MAX30105_FIFOCONFIG, MAX30105_SAMPLEAVG_MASK, numberOfSamples);
}

void enableFIFORollover(void) {
  bitMask(MAX30105_FIFOCONFIG, MAX30105_ROLLOVER_MASK, MAX30105_ROLLOVER_ENABLE);
}

void setLEDMode(uint8_t mode) {
  // Set which LEDs are used for sampling -- Red only, RED+IR only, or custom.
  // See datasheet, page 19
  bitMask(MAX30105_MODECONFIG, MAX30105_MODE_MASK, mode);
}

void setADCRange(uint8_t adcRange) {
  // adcRange: one of MAX30105_ADCRANGE_2048, _4096, _8192, _16384
  bitMask(MAX30105_PARTICLECONFIG, MAX30105_ADCRANGE_MASK, adcRange);
}

void setSampleRate(uint8_t sampleRate) {
  // sampleRate: one of MAX30105_SAMPLERATE_50, _100, _200, _400, _800, _1000, _1600, _3200
  bitMask(MAX30105_PARTICLECONFIG, MAX30105_SAMPLERATE_MASK, sampleRate);
}

void setPulseWidth(uint8_t pulseWidth) {
  // pulseWidth: one of MAX30105_PULSEWIDTH_69, _188, _215, _411
  bitMask(MAX30105_PARTICLECONFIG, MAX30105_PULSEWIDTH_MASK, pulseWidth);
}

// NOTE: Amplitude values: 0x00 = 0mA, 0x7F = 25.4mA, 0xFF = 50mA (typical)
// See datasheet, page 21
void setPulseAmplitudeRed(uint8_t amplitude) {
  I2CSend(I2CDEVICE_ADDR, 2, MAX30105_LED1_PULSEAMP, amplitude);
}

void setPulseAmplitudeIR(uint8_t amplitude) {
  I2CSend(I2CDEVICE_ADDR, 2, MAX30105_LED2_PULSEAMP, amplitude);
}

void setPulseAmplitudeGreen(uint8_t amplitude) {
  I2CSend(I2CDEVICE_ADDR, 2, MAX30105_LED3_PULSEAMP, amplitude);
}

void setPulseAmplitudeProximity(uint8_t amplitude) {
  I2CSend(I2CDEVICE_ADDR, 2, MAX30105_LED_PROX_AMP, amplitude);
}

void setProximityThreshold(uint8_t threshMSB) {
  // Set the IR ADC count that will trigger the beginning of particle-sensing mode.
  // The threshMSB signifies only the 8 most significant-bits of the ADC count.
  // See datasheet, page 24.
  I2CSend(I2CDEVICE_ADDR, 2, MAX30105_PROXINTTHRESH, threshMSB);
}

//Given a slot number assign a thing to it
//Devices are SLOT_RED_LED or SLOT_RED_PILOT (proximity)
//Assigning a SLOT_RED_LED will pulse LED
//Assigning a SLOT_RED_PILOT will ??
void enableSlot(uint8_t slotNumber, uint8_t device) {
  switch (slotNumber) {
    case (1):
      bitMask(MAX30105_MULTILEDCONFIG1, MAX30105_SLOT1_MASK, device);
      break;
    case (2):
      bitMask(MAX30105_MULTILEDCONFIG1, MAX30105_SLOT2_MASK, device << 4);
      break;
    case (3):
      bitMask(MAX30105_MULTILEDCONFIG2, MAX30105_SLOT3_MASK, device);
      break;
    case (4):
      bitMask(MAX30105_MULTILEDCONFIG2, MAX30105_SLOT4_MASK, device << 4);
      break;
    default:
      //Shouldn't be here!
      break;
  }
}

void clearFIFO(void) {
	I2CSend(I2CDEVICE_ADDR, 2, MAX30105_FIFOWRITEPTR, 0);
	I2CSend(I2CDEVICE_ADDR, 2, MAX30105_FIFOOVERFLOW, 0);
	I2CSend(I2CDEVICE_ADDR, 2, MAX30105_FIFOREADPTR, 0);
}

void softReset(void) {
  bitMask(MAX30105_MODECONFIG, MAX30105_RESET_MASK, MAX30105_RESET);
  while (1)
  {
    uint8_t response = I2CReceive(I2CDEVICE_ADDR, MAX30105_MODECONFIG);
    if ((response & MAX30105_RESET) == 0) break; //We're done!
    SysCtlDelay(delay); //Let's not over burden the I2C bus
  }
  // Put some delay here
}

void Sensorsetup(uint8_t powerLevel, uint8_t sampleAverage, uint8_t ledMode, int sampleRate, int pulseWidth, int adcRange) {
  softReset(); //Reset all configuration, threshold, and data registers to POR values

  //FIFO Configuration
  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  //The chip will average multiple samples of same type together if you wish
  if (sampleAverage == 1) setFIFOAverage(MAX30105_SAMPLEAVG_1); //No averaging per FIFO record
  else if (sampleAverage == 2) setFIFOAverage(MAX30105_SAMPLEAVG_2);
  else if (sampleAverage == 4) setFIFOAverage(MAX30105_SAMPLEAVG_4);
  else if (sampleAverage == 8) setFIFOAverage(MAX30105_SAMPLEAVG_8);
  else if (sampleAverage == 16) setFIFOAverage(MAX30105_SAMPLEAVG_16);
  else if (sampleAverage == 32) setFIFOAverage(MAX30105_SAMPLEAVG_32);
  else setFIFOAverage(MAX30105_SAMPLEAVG_4);

  //setFIFOAlmostFull(2); //Set to 30 samples to trigger an 'Almost Full' interrupt
  enableFIFORollover(); //Allow FIFO to wrap/roll over
  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

  //Mode Configuration
  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  if (ledMode == 3) setLEDMode(MAX30105_MODE_MULTILED); //Watch all three LED channels
  else if (ledMode == 2) setLEDMode(MAX30105_MODE_REDIRONLY); //Red and IR
  else setLEDMode(MAX30105_MODE_REDONLY); //Red only
  //activeLEDs = ledMode; //Used to control how many bytes to read from FIFO buffer
  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

  //Particle Sensing Configuration
  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  if(adcRange < 4096) setADCRange(MAX30105_ADCRANGE_2048); //7.81pA per LSB
  else if(adcRange < 8192) setADCRange(MAX30105_ADCRANGE_4096); //15.63pA per LSB
  else if(adcRange < 16384) setADCRange(MAX30105_ADCRANGE_8192); //31.25pA per LSB
  else if(adcRange == 16384) setADCRange(MAX30105_ADCRANGE_16384); //62.5pA per LSB
  else setADCRange(MAX30105_ADCRANGE_2048);

  if (sampleRate < 100) setSampleRate(MAX30105_SAMPLERATE_50); //Take 50 samples per second
  else if (sampleRate < 200) setSampleRate(MAX30105_SAMPLERATE_100);
  else if (sampleRate < 400) setSampleRate(MAX30105_SAMPLERATE_200);
  else if (sampleRate < 800) setSampleRate(MAX30105_SAMPLERATE_400);
  else if (sampleRate < 1000) setSampleRate(MAX30105_SAMPLERATE_800);
  else if (sampleRate < 1600) setSampleRate(MAX30105_SAMPLERATE_1000);
  else if (sampleRate < 3200) setSampleRate(MAX30105_SAMPLERATE_1600);
  else if (sampleRate == 3200) setSampleRate(MAX30105_SAMPLERATE_3200);
  else setSampleRate(MAX30105_SAMPLERATE_50);

  //The longer the pulse width the longer range of detection you'll have
  //At 69us and 0.4mA it's about 2 inches
  //At 411us and 0.4mA it's about 6 inches
  if (pulseWidth < 118) setPulseWidth(MAX30105_PULSEWIDTH_69); //Page 26, Gets us 15 bit resolution
  else if (pulseWidth < 215) setPulseWidth(MAX30105_PULSEWIDTH_118); //16 bit resolution
  else if (pulseWidth < 411) setPulseWidth(MAX30105_PULSEWIDTH_215); //17 bit resolution
  else if (pulseWidth == 411) setPulseWidth(MAX30105_PULSEWIDTH_411); //18 bit resolution
  else setPulseWidth(MAX30105_PULSEWIDTH_69);
  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

  //LED Pulse Amplitude Configuration
  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  //Default is 0x1F which gets us 6.4mA
  //powerLevel = 0x02, 0.4mA - Presence detection of ~4 inch
  //powerLevel = 0x1F, 6.4mA - Presence detection of ~8 inch
  //powerLevel = 0x7F, 25.4mA - Presence detection of ~8 inch
  //powerLevel = 0xFF, 50.0mA - Presence detection of ~12 inch

  setPulseAmplitudeRed(powerLevel);
  setPulseAmplitudeIR(powerLevel);
  setPulseAmplitudeGreen(powerLevel);
  setPulseAmplitudeProximity(powerLevel);
  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

  //Multi-LED Mode Configuration, Enable the reading of the three LEDs
  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  enableSlot(1, SLOT_RED_LED);
  if (ledMode > 1) enableSlot(2, SLOT_IR_LED);
  if (ledMode > 2) enableSlot(3, SLOT_GREEN_LED);
  //enableSlot(1, SLOT_RED_PILOT);
  //enableSlot(2, SLOT_IR_PILOT);
  //enableSlot(3, SLOT_GREEN_PILOT);
  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

  clearFIFO(); //Reset the FIFO before we begin checking the sensor
}

// convert an hexa or number to binary. Read frm last digit.
void binary(n){
	while (n) {
	    if (n & 1)
	    	UARTprintf("1");
	    else
	    	UARTprintf("0");

	    n >>= 1;
	}
	UARTprintf("\n");
}

//initialize I2C module 0
//Slightly modified version of TI's example code
void InitI2C0(void)
{
    //enable I2C module 0
    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);

    //reset module
    //SysCtlPeripheralReset(SYSCTL_PERIPH_I2C0);

    //enable GPIO peripheral that contains I2C 0
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

    //Added-wait for peripherals to be ready for programming
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOB));

    // Configure the pin muxing for I2C0 functions on port B2 and B3.
    GPIOPinConfigure(GPIO_PB2_I2C0SCL);
    GPIOPinConfigure(GPIO_PB3_I2C0SDA);

    // Select the I2C function for these pins.
    GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2); //I2C0 SCL
    GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3); //I2C0 SCL

    // Enable and initialize the I2C0 master module.  Use the system clock for
    // the I2C0 module.  The last parameter sets the I2C data transfer rate.
    // If false the data rate is set to 100kbps and if true the data rate will
    // be set to 400kbps.
    #if defined(TARGET_IS_TM4C129_RA0) ||                                     \
    defined(TARGET_IS_TM4C129_RA1) ||                                         \
    defined(TARGET_IS_TM4C129_RA2)
    I2CMasterInitExpClk(I2C0_BASE, ui32SysClock, false);
	#else
    I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), false);
	#endif

    //clear I2C FIFOs
    //HWREG(I2C0_BASE + I2C_O_FIFOCTL) = 80008000;
}

void InitConsole(void){
    // Enable GPIO port A which is used for UART0 pins.
    // TODO: change this to whichever GPIO port you are using.
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    // Configure the pin muxing for UART0 functions on port A0 and A1.
    // This step is not necessary if your part does not support pin muxing.
    // TODO: change this to select the port/pin you are using.
    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);
    // Enable UART0 so that we can configure the clock.
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    // Use the internal 16MHz oscillator as the UART clock source.
    UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    // Select the alternate (UART) function for these pins.
    // TODO: change this to select the port/pin you are using.
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    // Initialize the UART for console I/O.
    UARTStdioConfig(0, 115200, 16000000);
}

void main(){
	ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
	                SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |
	                SYSCTL_CFG_VCO_480), 120000000);
	InitConsole();
	InitI2C0();

	//Sensorsetup(0xFF,4,2,100,411,4096);
	softReset();
	I2CSend(I2CDEVICE_ADDR, 2, MAX30105_MODECONFIG , 0x02); // Heart rate
	SysCtlDelay(delay);
	I2CSend(I2CDEVICE_ADDR, 2,MAX30105_LED1_PULSEAMP , 0x01); // turn on red led with 118us.


	while(1){
		RxData = I2CReceive(I2CDEVICE_ADDR , MAX30105_PARTID );
		UARTprintf("Part id is: %x\n", RxData);
		SysCtlDelay(5*delay);
	}
}

Attached is the scope view for I2CSend(I2CDEVICE_ADDR, 2,MAX30105_LED1_PULSEAMP , 0x01)

  • Hi,
    You didn't tell what I2CDEVICE_ADDR is equal to and I have to assume the slave address + write bit is equal to 0xAE or your slave address is 0x53, correct? Looking at your scope it looks like the slave is trying to assert a NACK for the 9th bit. However, the ack/nack is not even a full clock pulse. If the slave really wants to reply NACK then it means the address is perhaps incorrect. Can you look into this first on your slave device? You said it didn't work when calling I2CSend(I2CDEVICE_ADDR, 2,MAX30105_LED1_PULSEAMP , 0x01). Did it work when you call I2CSend(I2CDEVICE_ADDR, 2, MAX30105_MODECONFIG , 0x02)?

    Your program looks complex. Can you start with a simple program like the TivaWare i2c examples to transmit and receive a few data?

    Also what pullup resistors did you use on the SCL and SCA bus?
  • Charles Tsai said:
    Your program looks complex.

    Hi Charles,

    So "true that" - poster's code IS highly complex - AND very long.

    Yet - is not that "complexity a "result" - and NOT the "REAL/TRUE CAUSE?"

    Might the cause stem from poster's, "Starting w/a highly complex device" - rather than a far-simpler - "vastly easier to MAKE WORK, one?"     (i.e. somehow a small capacity EEProm "springs to mind!")

    Such "incremental, simplified, infinitely more successful" approach - indeed has a name!     (banned here - we must assume)

    Note that poster admits to "borrowing code" from an external source - thus was not, "So much of his "Learning Process" compromised - by the, "unwise Rush to Completion?"    (which most always "substitutes (minimal) thought, "Cut/Paste" for, "Slowed, Specific, Incremental LEARNING!      (i.e. Highly Reinforced Learning!)      aka "KISS..."

    Further - poster's are never/ever prompted to report their "specific Experience Level" - thus all diagnosis (too) is made overly complex...     Surely, "Degree of Difficulty" must enter into consideration - yet (apparently) ALL Projects are "welcomed" (at every level).     We note that you suggest a "simple project" - yet NONE appear here - do they?    ("Loop back" - which forces one I2C port to serve as slave - is hardly "simple!"    In the past - a small capacity EEProm was (properly) presented...)

    Poster's "Headline/Subject" reports, "Write Data goes Missing" - more accurately, "Rejection of simplicity (HAS) caused, "understanding/project success to go missing!"

  • Hi Charles,

    I am extremely sure that my slave address and the addresses of the respective registers are correct. You may check the data sheet for Max30101 on your own and also the link to the header file that I hv provided. 

    For your question : "Did it work when you call I2CSend(I2CDEVICE_ADDR, 2, MAX30105_MODECONFIG , 0x02) ?" Please refer to : "For instance when  I attempted "I2CSend(I2CDEVICE_ADDR etc." in my post. 

    SDA & SCL is pull-ed up by 4.7k Ohm resistors, supplied with 5V. I have also tried this with 3.3V.

    Well it is not complex at all if you have already looked into the datasheet and yup, I hv already tried those simple programs that you have suggested long long time ago.

    P.S: I would really appreciate if you stick to the topic my fren (Write data goes missing).

  • Hi. Thanks for the moral support. It was hilarious. But I would appreciate also if you contribute to the post.
  • Vendor/friend Amit Ashara had past produced a detailed App Note - directed toward vendor's, "MCU, I2C implementation." (it had been "sticky" - I don't know its current where-about.)

    Your complex slave likely demands your full & precise grasp of "all" API functions which you employ. As an example - my firm lists the key/critical peripheral functions - provides a detailed narrative explanation - and "backs that" w/directly appropriate "scope-caps" - which (both) illustrate & clarify the MCU's signal outputs - in response to EACH API function!

    As always - if you have "good understanding" of, "simpler I2C programs" (best firm/I found - and (still) teach - is transacting w/small capacity (256 byte max) EEprom) - then your, "Systematic Test-Verify" - of each/every step in the transaction process - (all documented via proper scope caps) - and then viewed by "multiple (schooled) sets of eyes" - most always, "leads to success."

    As "KISS" dictates - never "start" w/higher than minimal (100kbps) - your objective is to give your transaction "EVERY CHANCE" to succeed. The separation between slave & master should be minimal - and you must insure that the slave is fully/properly powered - and that the ground of slave & master is indeed, common!

    Slow, carefully (and properly) monitored, individual transactions ARE required when such, "complex slaves" are attached. Firm/I do not "believe" in short-cuts - your presentation of clear scope-caps (after your thorough review/study) of each/every stage of the transaction sequence - appears the optimal means to, "lure/intrigue others - to join your hunt..." (maybe)

  • Hi, you did mention that "never "start" w/higher than minimal (100kbps) ". Thats true, but in my code I believe I hv also used 100kbps. Did I miss anything ?
    Regarding "you must insure that the slave is fully/properly powered - and that the ground of slave & master is indeed, common!", Good suggestiong & I will double check on that.
    But from my code, I2CRead works perfectly fine. I can read the PARTID (MAX30105_PARTID) and other registers without any issues at all. Just that I hv issues with my I2CSend, which works intermittently (but only 10% of the time).

  • Hi,

    1. You stated "Attached is the scope view for I2CSend(I2CDEVICE_ADDR, 2,MAX30105_LED1_PULSEAMP , 0x01)". This is why I asked what about "Did it work when you call I2CSend(I2CDEVICE_ADDR, 2, MAX30105_MODECONFIG , 0x02) " I don't think there is anything wrong with asking such a question.

    2. I said there looks like a NACK replied by the slave on the 9th bit on the scope. Did you have a chance to investigate this? A NACK can cause the master the STOP. When you said the I2CRead was OK, what does the 9th bit looks like on the scope?

    3. I will suggest you to try replacing below one line with two lines as shown. For experiment you can also try SysCtlDelay(10) instead of while(!I2CMasterBusy(I2C0_BASE));

    while(I2CMasterBusy(I2C0_BASE));

    with 

    while(!I2CMasterBusy(I2C0_BASE));

    while(I2CMasterBusy(I2C0_BASE));

    4. I'm not clear with your code. In I2CSend(I2CDEVICE_ADDR, 2,MAX30105_LED1_PULSEAMP , 0x01) you pass 2 as the number of arguments to the function. But inside the function you have for(i = 1; i < (num_of_args - 1); i++). What is inside the loop is not executed, isn't? Doesn't it just finish with the one transmit data after you call I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH).

    5. When you said the I2CSend() works 10% of the time, what does it mean? Do you keep running the identical program and 10% of the time the I2CSend(I2CDEVICE_ADDR, 2,MAX30105_LED1_PULSEAMP , 0x01) will work and the other 90% of time it will not work? It makes me feel that you should investigate the NACK. Check the I2C status register and see if the NACK was detected by the master.

  • May I "urge again" the presentation of "scope-caps" and the exact user code which produced them - covering ALL "Send" functions.

    All too often - single set of eyes MISS - that which "fresh eyes" quickly/easily detect!     (especially when those "fresh eyes" are (properly) motivated!)

    Indeed - as vendor Charles has (repeatedly) noted - "any" NAK disturbs - and makes your code, timing, interconnect - all suspect!

    Exercising those here - w/out your proper confirmation of: proper power to the slave (maintained DURING transactions); "closeness of MCU to Slave" (requested - but not described); and RECENT Scope Caps - dulls the motivation of your "helpers" to (untiringly) further assist...

    None here "caused your issue" - we ARE (very much) trying to guide & assist...

  • Hi cb1,
    The NACK looks narrow. As long as it does not change while the SCL is high then it should not be sampled. However, it does look suspicious to look at. It is the reason I want to see the 9th bit waveform on a I2CRead as it is working according to the poster.
  • Hi Charles,

    While I appreciate your (bit singular) NAK concern - that is an EFFECT (not a cause) - is that not so?

    Thus - our time/effort is gravely discounted via "limited concern" - which explains my request for, "Scope-Caps" (tied directly to their actuating code) for the "entirety" of poster's (suspect/MISSING) Slave writes!

    Note that I (often) strive for a "General Solution" - which throws off BENEFITS FAR BEYOND a single post - or poster!
    Scope-Caps which reveal poster's code - MCU's output - AND Slave's Response - by FAR - prove best to "RESOLVE!" (they ARE "KISS" - of course.)
  • After futher investigation, the I2CREAD was not working perfectly either. Similar to I2CWrite it worked intermittently. However I have discovered, by removing the " while(I2CMasterBusy(I2C0_BASE)); " and replacing them with a 100ms delay, I am able to read the registers without any issues. However by looking into the scope cap for I2C read, the "Repeat Start" condition seems to be very long.

    Attached the screen shot and modified I2CRead.

    P.S: This method does not solve the problem for I2CWrite.

    "Repeat Start" condition:

    Modified I2CRead condition:

    static unsigned long WaitI2CDone( unsigned int long ulBase){
        // Wait until done transmitting
        //while( I2CMasterBusy(I2C0_BASE));
    	SysCtlDelay(my_delay);
    
        // Return I2C error code
        return I2CMasterErr(I2C0_BASE);
    }
    
    //read specified register on slave device
    uint32_t I2CReceive(uint32_t slave_addr, uint8_t reg)
    {
    	UARTprintf("Entered Receive \n");
    	uint8_t data = 0;
    	int16_t i2c_err = I2C_MASTER_ERR_NONE;
        //specify that we are writing (a register address) to the
        //slave device
        I2CMasterSlaveAddrSet(I2C0_BASE, slave_addr, false);
    
        //specify register to be read
        I2CMasterDataPut(I2C0_BASE, reg);
    
        //send control byte and register address byte to slave device
        I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);
    
        //wait for MCU to finish transaction
        SysCtlDelay(my_delay);
    
        //specify that we are going to read from slave device
        I2CMasterSlaveAddrSet(I2C0_BASE, slave_addr, true);
    
        //send control byte and read from the register we
        //specified
        I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
    
        if(i2c_err != WaitI2CDone( I2C0_BASE)){
            data = I2CMasterDataGet(I2C0_BASE);
        	UARTprintf("Read error in data: %x\n", data);
        }
    
        //wait for MCU to finish transaction
        SysCtlDelay(my_delay);
    
        UARTprintf("Read register: %d \n",reg);
        //return data pulled from the specified register
        return I2CMasterDataGet(I2C0_BASE);
    }