Bootstrap

INA226 在连续采样的模式下的缺陷

这几天在调试INA226的时候发现了一个很麻烦的bug,我使用了INA226采集完成后通过Alter Pin通知MCU,MCU则通过中断采集数据的方式,开始的时候我使用的是连续模式,INA226在连续模式下,能在每次完成采样之后通知MCU,但是这个地方出现了一个BUG,在连续采样一段时间(大约10秒上下)之后,Shunt Voltage 和 Current 寄存器读出来的数据全是负数!

中断处理的代码如下:

void CPicoFilamental::Entry(uint32_t events) 
{
    bool awaken(false);
    if( GPIO_IRQ_EDGE_FALL & events || GPIO_IRQ_LEVEL_LOW & events )
    {
        section.Enter();

        counter ++;
        bool alter_function(false), conversion_ready(false), math_overflow(false);
        if( sampler.GetFlags(alter_function, conversion_ready, math_overflow) )
        {
            //Serial.printf( "flags...%d, %d, %d\n", alter_function, conversion_ready, math_overflow );
        }

        if( GPIO_IRQ_EDGE_FALL & events )
        {
            if( conversion_ready && math_overflow == false )
            {
                f_current = sampler.GetCurrent(); 
                awaken = true;

                double voltage = sampler.GetShuntVoltage(); 
                
                Serial.printf( "current: %f, shunt voltage: %f\n", f_current, voltage );
            }
        }
        else 
        if( GPIO_IRQ_LEVEL_LOW & events )
        {
            if( alter_function )
            {
                Serial.printf( "alter error\n" );
                awaken = true;
            }
        }

        section.Leave();

        if( awaken ) {
            signal.Awake();
        }
    }
}

代码是非常的简洁的,就是读取06H寄存器,获得Alter Pin的状态,然后根据具体情况做处理。

采样一段时间之后,读出来的数据全是负数。Shunt Voltage 和 Current 寄存器的数据明显是错误的,因为我通过电源可知,当时的电流大概在100mA左右。

对这个问题我百思不得其解,想了很久,发现调整采样时间和平均次数时,这个bug会有些变化 。我在想会不会是读取的动作本身影响了INA226内部的累加器的工作? 因为看datasheet明确说了这几个寄存器只会在完成采样后执行数据更新,这几个寄存器不存在误读的可能,那么唯一能影响的就是累加器。于是我尝试改了改代码,让INA226工作于触发模式,每一次中断之后,在所有数据读完之后,再提交一次采样请求。

代码调整如下:

bool CPicoFilamental::Start(double shunt, double max_current, double expect_current)
{
    bool result = false;
    section.Enter();
    //if( sampler.Initiate(shunt, max_current, IAT_128, ICT_140US, ICT_1100US, IOM_CONTINUOUS_SHUNT_VOLTAGE) ) 
    if( sampler.Initiate(shunt, max_current, IAT_64, ICT_140US, ICT_1100US, IOM_TRIGGERED_SHUNT_VOLTAGE) ) 
    {
        sampler.SetConversionNotify( true );
        e_current = expect_current;
        
        result = Begin( GPIO_IRQ_EDGE_FALL | GPIO_IRQ_LEVEL_LOW );

        if( result )
        {
          pwm_1.Start( 62500, 0.04 );
          pwm_2.Start( 31250, 0.04 );
        }
    }
    section.Leave();
    return result;
}


void CPicoFilamental::Entry(uint32_t events) 
{
    bool awaken(false);
    if( GPIO_IRQ_EDGE_FALL & events || GPIO_IRQ_LEVEL_LOW & events )
    {
        section.Enter();

        counter ++;
        bool alter_function(false), conversion_ready(false), math_overflow(false);
        if( sampler.GetFlags(alter_function, conversion_ready, math_overflow) )
        {
            //Serial.printf( "flags...%d, %d, %d\n", alter_function, conversion_ready, math_overflow );
        }

        if( GPIO_IRQ_EDGE_FALL & events )
        {
            if( conversion_ready && math_overflow == false )
            {
                f_current = sampler.GetCurrent(); 
                awaken = true;

                double voltage = sampler.GetShuntVoltage(); 
                
                Serial.printf( "current: %f, shunt voltage: %f\n", f_current, voltage );
            }
        }
        else 
        if( GPIO_IRQ_LEVEL_LOW & events )
        {
            if( alter_function )
            {
                Serial.printf( "alter error\n" );
                awaken = true;
            }
        }

        if( sampler.NeedTrigger() ) {
            sampler.Trigger();
        }

        section.Leave();

        if( awaken ) {
            signal.Awake();
        }
    }
}

果然如我猜想,这个Bug得到了解决。后来连续跑了30分钟,读取失败的问题没有再出现。

;