I2C and MMA8451

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

Hi,

   

     I am attempting to use a FreeScale MMA8451 so I read with great interest the post "reading adxl345 data on i2c" and found very similar issues. To read a register on the 8451 just like the adxl345 you have to write the register # to I2C, do a restart then read. My code to do this was just as you suggested for the adx part.

   

    status =  SCB_I2CMasterSendStart(MMA8451Address,SCB_I2C_WRITE_XFER_MODE);
    status |= SCB_I2CMasterWriteByte(reg & 0xff);
    status |= SCB_I2CMasterSendRestart(MMA8451Address,SCB_I2C_READ_XFER_MODE);
    rtnval =  SCB_I2CMasterReadByte(SCB_I2C_ACK_DATA);
    status |= SCB_I2CMasterSendStop();
    if( status != SCB_I2C_MSTR_NO_ERROR )
    {
        rtnval = -1 * status;
    }

   

This works, but monitoring the I2C bus I see an extra read value 0f 0x00 see the enclosed file (TEK00117.png).  If I remove the SCB_I2CMasterReadByte() in the above the extra byte is not there.  Where is this extra byte coming from ?

   

Also the application has BLE, FreeRTOS and will be sleeping.  In the main thread I do this:

   

   while( 1 )
    {
        // Setup Accelerometer
        rtnval = initMMA8451(MMA8451_DEFAULT_ADDRESS);  // This is where the register is read
    
        vTaskDelay(5000 *portTICK_RATE_MS  );
 
        i = i + 1;
        SCB_Sleep();
        CyBle_ProcessEvents();
        CyBle_EnterLPM(CYBLE_BLESS_DEEPSLEEP);
        SCB_Wakeup();
    }

   

The i = i+1 is to give a breakpoint line.  After two time through the loop it gets stuck in the CY_ISR(CyBLE_Bless_Interrupt) handler and won't proceed.  Removing the DEEPSLEEP line makes no difference. Any suggestions on how to handle this ?

   

Thank you for the help

   

--jim schimpf

0 Likes
1 Solution
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

When reading a byte from I2C the last (or only) byte must be NAKed. Might be the cause for the extra byte seen on the bus.

   

 

   

Bob

View solution in original post

0 Likes
8 Replies
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

When reading a byte from I2C the last (or only) byte must be NAKed. Might be the cause for the extra byte seen on the bus.

   

 

   

Bob

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

Thank you I will try this. Found this in the MMA8451 manual.

   

When performing a multi-byte read or “burst read”, the MMA8451Q automatically increments the received register address commands after a read command is received. Therefore, after following the steps of a single byte read, multiple bytes of data can be read from sequential registers after each MMA8451Q acknowledgment (AK) is received until a no acknowledge (NAK) occurs from the Master followed by a stop condition (SP) signaling an end of transmission. 

   

As you can see in TEK00118.png it worked.  Thank you very much.

   

--jim schimpf

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

You are always welcome.

   

 

   

Bob

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

Hi

   

After fixing the NAK problem in ReadRegister I then changed the WriteRegister part of the MMA8451 code to this

   

    txbuf[0] = 0xff & reg;
    txbuf[1] = 0xff & value;
    
    status = SCB_I2CMasterWriteBuf(MMA8451Address,txbuf,cnt,SCB_I2C_WRITE_XFER_MODE);
    
    // Wait for done
    
    cnt = SCB_I2CMasterStatus();
    while( cnt != SCB_I2C_MSTAT_WR_CMPLT )
    {
        vTaskDelay(1 *portTICK_RATE_MS  );
        cnt = SCB_I2CMasterStatus();
    }

   

And now the rest of the MMA8451 initialization works.  Is there a better way to determine when the WriteBuf is done ? Without the wait the next readReg in the MMA8451 codes steps on a partially completed transfer and dies in the I2C code. The spin loop prevents this but is there a better way ?

   

The image TEK00119.png shows this top of the screen shows all the register sets.  After I submit this code to Adafruit I will post the library for MMA8451 use here.

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Do not use SCB_I2C_WRITE_XFER_MODE with buffered write, there is a SCB_I2C_MODE_COMPLETE_XFER. Have a look at the transfer modes in datasheet.

   

 

   

Bob

Anonymous
Not applicable

Thank you, simplified things.  Found writing to the MMA8451 registers too fast caused it to choke.  put a vTaskDelay after write and it works fine. When code working will put a copy here.

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

As promised here is the MMA8451 library for Cypress.  This is a copy of the Adafruit library with the low level I2C routines replaced with Cypress compatible routines.  It doesn't have all the methods the original had as I didn't need them but if you do just copy from the original library.  These methods use the same low level routines so they will just compile in.

   

See Cypress.zip

   

--jim schimpf

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Thank you for sharing that project with us.

   

 

   

Bob

0 Likes