这几天在调试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分钟,读取失败的问题没有再出现。