1
\$\begingroup\$

I am writing a driver for mcp3421 ADC IC and I have a problem when I measure in 12-bit accuracy. That is 240 samples per second.

In the datasheet the min and max values are 176 SPS and 328 SPS. So I expect to be able to see a new measurement every:

-min: \$1sec/176 \$ -> \$5,69msec\$

or

-max: \$1sec/328 \$ -> \$3,05msec\$

In reality I poll the mcp3421 every 7 msec to be sure it gets a new measurement but the RDY flag( 0=new measurement ) is set every 50msec.

Is that normal? Why is this happening?

Here is the tree (every 7msec) enter image description here

and here is the forest( every 50msec ) enter image description here

 * \brief Reads all mcp3421 registers.
 * 
 * \bug Needs a timeout mechanism or it might hang in a loop if device hardware fails.
 * 
 * It reads mcp3421 and expects either 4 or 3 bytes.
 * If it is in 18-bit all bytes are used.
 * If it is not 18-bit the lower byte is not used.
 * 
 * \param[in,out]   me          The mcp3421 handle.
 * \param[out]      upper       The first byte.
 * \param[out]      middle      The second byte.
 * \param[out]      lower       The third byte(18bit) or configuration byte(12,14,16bit).
 * \param[out]      config_reg  Register is the 3rd byte(12,14,16bit) in row or the 4rth(18bit).
 * 
 * \retval          0           Success.
 * \retval          1           Failed.
 */
static int mcp3421_read_all( mcp3421_t* me, uint8_t* upper, uint8_t* middle, uint8_t* lower, uint8_t* config_reg )
{
    //TODO: Add timeout_ms
    int err = 0;
    do 
    {
        /* Read mcp3421 register */
        uint8_t data[4] = { 0x00, 0x00, 0x00, 0x90 };
        if( i2c_master_receive( &(me->bus), me->address, data, 4U, MCP3421_TIMEOUT ) )
        {
            /* Exit with error */
            errorHandler();
            return 1;
        }

        /* Get data */
        *upper = data[0];
        *middle = data[1];
        *lower = data[2];
        *config_reg = data[3];

        /* Wait until the next read */
        if( mcp3421_delayUntilNextRead( *config_reg ) )
        {
            /* Exit with error */
            errorHandler();
            return 1;
        }

        /* Check if registers are updated */
        if( ( (*config_reg) & RDY_Mask ) == 0 )
        {
            /* Exit with success */
            return 0;
        }
        err++;
    }
    while( err<200 );

    /* Exit with failure */
    errorHandler();
    return 1;
}
\$\endgroup\$
  • \$\begingroup\$ Your logic is backwards, #RDY goes low when new data is ready. Post some code if you need more specific help, too many assumption have to be made as is. \$\endgroup\$ – justing Nov 9 '17 at 18:34
  • \$\begingroup\$ You are right about RDY flag. ( 0=new measurement available ). Changed it in the description. \$\endgroup\$ – Tedi Nov 9 '17 at 19:21
  • \$\begingroup\$ Something is not consistent in your description: If your device is in 12-bit mode, you only receive 3 bytes, the last one being the config byte with the ready flag. Yet your code expects 4 bytes. The device returns 4 bytes if it is in 18-bit mode. But then you only get a sample every 250ms. Do you initialize the config register? And if so how? \$\endgroup\$ – Codo Nov 9 '17 at 20:04
  • \$\begingroup\$ Config register is 0x90(default). When in 12/14/16-bit after the third byte you get again the configuration reg. I always get the forth byte in order to have the same code for all sample rates. \$\endgroup\$ – Tedi Nov 9 '17 at 20:31
  • \$\begingroup\$ The datasheet says: "If the device is configured for 12, 14, or 16 bit-mode, the device outputs two data bytes followed by a configuration byte." (chapter 5.3.3, third paragraph). The documentation of your function mcp3421_read_all says the same. \$\endgroup\$ – Codo Nov 9 '17 at 22:22
0
\$\begingroup\$

When you repeatedly ask for the configuration byte after the data bytes( 2 in the case of 12/14/16bit and 3 in case of 18bit ) the config register is changing. So if your code counts in the last config value acquired you might miss an RDY flag or get a wrong one.

My code did that and it is a bug.

Workaround is asking the correct amount of bytes or the following code.

/**
 * \brief Reads all mcp3421 registers.
 * 
 * \bug Needs a timeout mechanism or it might hang in a loop if device hardware fails.
 * 
 * It reads mcp3421 and expects either 4 or 3 bytes.
 * If it is in 18-bit all bytes are used.
 * If it is not 18-bit the lower byte is not used.
 * 
 * In 12/14/16-bit the middle byte is set to zero.
 * 
 * \param[in,out]   me          The mcp3421 handle.
 * \param[out]      upper       The first byte.
 * \param[out]      middle      The second byte.
 * \param[out]      lower       The third byte(18bit) or configuration byte(12,14,16bit).
 * \param[out]      config_reg  Register is the 3rd byte(12,14,16bit) in row or the 4rth(18bit).
 * 
 * \retval          0           Success.
 * \retval          1           Failed.
 */
static int mcp3421_read_all( mcp3421_t* me, uint8_t* upper, uint8_t* middle, uint8_t* lower, uint8_t* config_reg )
{
    //TODO: Add timeout_ms
    uint32_t err = 0;
    do 
    {
        /* Read mcp3421 register */
        uint8_t data[4] = { 0x00, 0x00, 0x00, 0x90 };
        if( i2c_master_receive( &(me->bus), me->address, data, 4U, MCP3421_TIMEOUT ) )
        {
            /* Exit with error */
            errorHandler();
            return 1;
        }

        /* Get data */
        *config_reg = data[3];//This is config for all data rates.
        if( mcp3421_unmarshal_sample_rate( *config_reg ) == mcp3421_sample_rate_18bit )
        {
            /* 18 bit */
            *upper = data[0];
            *middle = data[1];
            *lower = data[2];
            *config_reg = data[3];
        }
        else
        {
            /* 12/14/16 bit */
            *upper = data[0];
            //*middle = 0;
            *lower = data[1];
            *config_reg = data[2];
        }

        /* Check if registers are updated */
        if( ( (*config_reg) & RDY_Mask ) == 0 )
        {
            /* Exit with success */
            return 0;
        }
        err++;
    }
    while( err<1000 );

    /* Exit with failure */
    errorHandler();
    return 1;
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.