Monday, December 19, 2011

BMP085 Code Revisited Floating Point Version

Previously I posted a correction to the Bosch BMP085 calculation.
Today I found this paper, BMP085-Calcs.pdf but was unable to find C code to go with the paper.

This code results in more refined altitude increments and uses the whole accuracy.  The old integer code rounds of some bits and makes altitude increments more chunky.

(Very important in some altitude based feedback systems and others)

So I dug in and implemented it...

My variables, then the constant calcs, then the calc, then the test code.


int Baro_ac1, Baro_ac2, Baro_ac3, Baro_b1, Baro_b2, Baro_mb, Baro_mc, Baro_md;
unsigned int Baro_ac4, Baro_ac5, Baro_ac6;

float Baro_fc3;
float Baro_fc4;
float Baro_fb1;
float Baro_fc5;
float Baro_fc6;
float Baro_fmc;
float Baro_fmd;
float Baro_fx0;
float Baro_fx1;
float Baro_fx2;
float Baro_fy0;
float Baro_fy1;
float Baro_fy2;
float Baro_fp0;
float Baro_fp1;
float Baro_fp2;

...

// And calculate derrived constants used by BaroCalcFloat()
// from http://wmrx00.sourceforge.net/Arduino/BMP085-Calcs.pdf
Baro_fc3 = 160.0f * powf(2.0f, -15.0) * Baro_ac3;
Baro_fc4 = 0.001f * powf(2.0f, -15.0) * Baro_ac4;
Baro_fb1 = (160.0f * 160.0f) * powf(2.0f, -30.0) * Baro_b1;

Baro_fc5 = Baro_ac5 * powf(2.0f, -15.0) / 160.0f;
Baro_fc6 = Baro_ac6;
Baro_fmc = Baro_mc * powf(2.0f, 11.0) / (160.0f * 160.0f);
Baro_fmd = Baro_md / 160.0f;

Baro_fx0 = Baro_ac1;
Baro_fx1 = 160.0f * powf(2.0f, -13.0) * Baro_ac2;
Baro_fx2 = (160.0f * 160.0f) * powf(2.0f, -25.0) * Baro_b2;

Baro_fy0 = Baro_fc4 * powf(2.0f, 15.0);
Baro_fy1 = Baro_fc4 * Baro_fc3;
Baro_fy2 = Baro_fc4 * Baro_fb1;

Baro_fp0 = (3791.0f - 8.0f)/1600.0f;
Baro_fp1 = 1.0f - 7357.0f * powf(2.0f, -20.0);
Baro_fp2 = 3038.0f * 100.0f * powf(2.0f, -36.0);

...

float tu = BaroState.rawTemperature;
// Assumes Baro_oss highest precision BARO_OSS_MODE_ULTRA_HIGH_RES.
float pu = BaroState.rawPressure / 256.0f;

float alpha = Baro_fc5 * (tu - Baro_fc6);
float Tc = alpha + Baro_fmc / (alpha + Baro_fmd);
BaroState.temperatureC = Tc;

float s = Tc - 25.0f;
float x = Baro_fx2 * (s * s) + Baro_fx1 * s + Baro_fx0;
float y = Baro_fy2 * (s * s) + Baro_fy1 * s + Baro_fy0;
float z = (pu - x) / y;
BaroState.pressurePa = Baro_fp2 * (z * z) + Baro_fp1 * z + Baro_fp0;

...

void BaroTestMathFloat()
{
mainMessagePrint(ROUTE_DEBUG, "Baro Test Math (float)\r\n");

Baro_ac1 =7911;
Baro_ac2 = -934;
Baro_ac3 = -14306;
Baro_ac4 = 31567;
Baro_ac5 = 25671;
Baro_ac6 = 18974;
Baro_b1 = 5498;
Baro_b2 = 46;
Baro_mb = -32768;
Baro_mc = -11075;
Baro_md = 2432;

Baro_fc3 = 160.0f * powf(2.0f, -15.0) * Baro_ac3;
Baro_fc4 = 0.001f * powf(2.0f, -15.0) * Baro_ac4;
Baro_fb1 = (160.0f * 160.0f) * powf(2.0f, -30.0) * Baro_b1;
mainMessagePrint(ROUTE_DEBUG, "fc3 %f fc4 %f fb1 %f", Baro_fc3, Baro_fc4, Baro_fb1);

Baro_fc5 = Baro_ac5 * powf(2.0f, -15.0) / 160.0f;
Baro_fc6 = Baro_ac6;
Baro_fmc = Baro_mc * powf(2.0f, 11.0) / (160.0f * 160.0f);
Baro_fmd = Baro_md / 160.0f;
mainMessagePrint(ROUTE_DEBUG, "fc5 %f fc6 %f fmc %f fmd %f",
Baro_fc5, Baro_fc6, Baro_fmc, Baro_fmd);

Baro_fx0 = Baro_ac1;
Baro_fx1 = 160.0f * powf(2.0f, -13.0) * Baro_ac2;
Baro_fx2 = (160.0f * 160.0f) * powf(2.0f, -25.0) * Baro_b2;
mainMessagePrint(ROUTE_DEBUG, "x %f %f %f",
Baro_fx0, Baro_fx1, Baro_fx2);

Baro_fy0 = Baro_fc4 * powf(2.0f, 15.0);
Baro_fy1 = Baro_fc4 * Baro_fc3;
Baro_fy2 = Baro_fc4 * Baro_fb1;
mainMessagePrint(ROUTE_DEBUG, "y %f %f %f",
Baro_fy0, Baro_fy1, Baro_fy2);

Baro_fp0 = (3791.0f - 8.0f)/1600.0f;
Baro_fp1 = 1.0f - 7357.0f * powf(2.0f, -20.0);
Baro_fp2 = 3038.0f * 100.0f * powf(2.0f, -36.0);
mainMessagePrint(ROUTE_DEBUG, "p %f %f %f",
Baro_fp0, Baro_fp1, Baro_fp2);

BaroState.rawTemperature = 0x69EC;
BaroState.rawPressure = 0x982FC0;
Baro_oss = BARO_OSS_MODE_ULTRA_HIGH_RES;

float tu = BaroState.rawTemperature;
// Assumes Baro_oss highest precision BARO_OSS_MODE_ULTRA_HIGH_RES.
float pu = BaroState.rawPressure / 256.0f;

mainMessagePrint(ROUTE_DEBUG, "rt %f rp %f", tu, pu);

float alpha = Baro_fc5 * (tu - Baro_fc6);
float Tc = alpha + Baro_fmc / (alpha + Baro_fmd);
BaroState.temperatureC = Tc;
mainMessagePrint(ROUTE_DEBUG, "a %f Tc %f", alpha, Tc);

float s = Tc - 25.0f;
float x = Baro_fx2 * (s * s) + Baro_fx1 * s + Baro_fx0;
float y = Baro_fy2 * (s * s) + Baro_fy1 * s + Baro_fy0;
float z = (pu - x) / y;
BaroState.pressurePa = Baro_fp2 * (z * z) + Baro_fp1 * z + Baro_fp0;
mainMessagePrint(ROUTE_DEBUG, "s %f x %f y %f z %f p %f", s, x, y, z, BaroState.pressurePa);
}



TF

Saturday, November 26, 2011

On "Book Code"

Ok,
So you buy that nifty new book on Game Programming. One would assume the people writing the chapters would know what they are doing, or at least have used the code in an actual game.  Nope.

Always understand what the code does, and be ready for problems arising from the difference between your goal, to write a working commercial game, and the writer's goal, to write a chapter in a book.

I have run into this in two places recently.  One is the network library MTUDP in

Advanced 3D game programming with DirectX 10.0 and the other has been bullet physics. 

MTUDP is a good idea but not done and tested well. (If you want my rewrite, email me) and bullet physics is a university project to try new ideas in physics.  In my case I want to create a open ended infinite zombie game with on-the-fly AI generation of all game content.

There is an echo here of operating system issues.  Was the OS written to make money for a huge corporation, or by hobbyists to make a system they want to work in and use, or as a fashion statement for elite computer users? (Ok, you guess which three OSs to which I am referring.0

Oh, well, end of rant. And end of three weeks of wasted time trying to debug and make a fundamentally broken library work.

TF

Monday, November 21, 2011

MTUDP.cpp More Fixes

WARNING - I should remove this post, but instead will give a warning.  Do not use the MTUDP.cpp library as is.  It has many bugs and makes a fatal mistake.  The user ID is the IP address.  This breaks if there is a fire wall in the way, and there is always a firewall.  I have nearly rewritten the library with very little of the original code left over.

--------------------------------------------------------------------

Ok, turns out the previous post was not a complete fix for the Ack code.
As usual the blog mangles the C code a bit, but you should be able to copy this, else email me for a complete copy.



 unsigned short NetLibHost::ProcessIncomingACKs( char *pBuffer, unsigned short len, DWORD receiveTime )
 {
  UNREFERENCED_PARAMETER(len);
  // Get the number of ACKs in this message, not counting the base ACK.
  unsigned char numAcks, mask, *ptr;
  DWORD         basePacketID, ackID;

  ptr = (unsigned char *)pBuffer;

  // The story: We want to ack each received packet. 
  // But if we have received a series of packets we only
  // have to ack the highest numbered one and we assume all the lesser packets are ack'd too.
  // But then there can be some higher number packets we have received with some gaps.
  // So we send the highest received packet so far with no unreceived packets less than it, then
  // have bytes with the bits representing yes/no acks for higher numbered packets.'
  // So say we have received  3,4,5,6,7,9,10,11,13
  // The base would be 7 since we have all pacjets up to that,
  // Then the next byte is the bits 0x00 | 0x40 | 0x20 | 0x10 | 0x00 | 0x40
  // for packets 8,9,10,11,12,13 respectively.

  // Get the base packet ID, which indicates all the ordered packets received so far.
  memcpy( &basePacketID, ptr, sizeof( DWORD ) );
  ptr += sizeof( DWORD );
  // Get the number of additional ACKs.
  // TODO - Keene - Runs off the end if Ack record was truncated to fit!
  // Solution: don't ever make packets messages that are too large, e.g. 3k
  numAcks = *ptr;
  ptr++;
  // Zero the byte so if there is a one off error in bits, it is not a false ack.
  *ptr = 0x00;
  ackID = d_outQueue.GetLowestID();

#if defined( _DEBUG_VERBOSE )
  OUTPUTREPORT3( "<   Ack low=%04d base=%04d end=%04d\n", ackID, basePacketID, basePacketID + numAcks );
#endif

  // Can get stuck in loop here if corrupt data.
  int debugCount = 0;
  while( ackID <= basePacketID )
  {
   debugCount++;
   // The packet has been ack's so update average ping time.
   ACKPacket( ackID, receiveTime );
   ackID++;
  }

  mask = 0x80;

  // TODO - Keene - Runs off the end if ack record was truncated to fit!
  // Solution: don't ever make packets messages that are too large, e.g. 3k
  while( ackID < basePacketID + numAcks )
  {
   if( mask == 0x00 )
   {
    mask = 0x80;
    ptr++;
    // Zero the byte so if there is a one off error in bits, it is not a false ack.
    *ptr = 0x00;
   }

   if( ( *ptr & mask ) != 0 )
   {
    ACKPacket( ackID, receiveTime );
   }

   mask >>= 1;
   ackID++;
  }

  return (unsigned short)(ptr - (unsigned char *)pBuffer);
 }

 unsigned short NetLibHost::ProcessIncomingReliable( char *pBuffer, unsigned short maxLen, DWORD receiveTime )
 {
  maxLen;
  // Process any messages in the packet.
  DWORD           packetID;
  char            *readPtr;
  unsigned short  length;

  readPtr = pBuffer;
  memcpy( &packetID, readPtr, sizeof( DWORD ) );
  readPtr += sizeof( DWORD );
  memcpy( &length, readPtr, sizeof( unsigned short ) );
  readPtr += sizeof( unsigned short );
#if defined( _DEBUG_VERBOSE )
  OUTPUTREPORT2( "<   %04d (%d) R\n", packetID, length );
#endif
  // If this message is a packet, queue the data
  // to be dealt with by the application later.
  d_inQueue.AddPacket( packetID, (char *)readPtr, length, receiveTime );
  readPtr += length;

  // Should we build an ACK message?
  if( d_inQueue.GetCount() == 0 )
  {
   return (unsigned short)( readPtr - pBuffer );
  }

  // Build the new ACK message.
  DWORD         lowest, highest, ackID;
  unsigned char mask, *ptr;

  lowest = d_inQueue.GetCurrentID();
  highest = d_inQueue.GetHighestID();

  // Cap the highest so as not to overflow the ACK buffer
  // (or spend too much time building ACK messages).
  // (Was bug here because ACK_MAXPERMSG was 256 which does not fit in a byte.)
  if( highest > lowest + ACK_MAXPERMSG )
  {
   highest = lowest + ACK_MAXPERMSG;
  }

#if defined( _DEBUG_VERBOSE )
  OUTPUTREPORT2( " >  %04d ack to %04d ", lowest, highest );
#endif

  // The story: We want to ack each received packet. 
  // But if we have received a series of packets we only
  // have to ack the highest numbered one and we assume all the lesser packets are ack'd too.
  // But then there can be some higher number packets we have received with some gaps.
  // So we send the highest received packet so far with no unreceived packets less than it, then
  // have bytes with the bits representing yes/no acks for higher numbered packets.'
  // So say we have received  3,4,5,6,7,9,10,11,13
  // The base would be 7 since we have all pacjets up to that,
  // Then the next byte is the bits 0x00 | 0x40 | 0x20 | 0x10 | 0x00 | 0x40
  // for packets 8,9,10,11,12,13 respectively.

  ptr = (unsigned char *)d_ackBuffer;
  // Send the base packet ID, which is the ID of the last ordered packet received.
  memcpy( ptr, &lowest, sizeof( DWORD ) );
  ptr += sizeof( DWORD );
  // Add the number of additional ACKs.
  *ptr = (unsigned char)(highest - lowest);
  ptr++;
  // Zero the byte so if there is a one off error in bits, it is not a false ack.
  *ptr = 0x00;

  ackID = lowest + 1;
  mask = 0x80;

  while( ackID <= highest )
  {
   if( mask == 0x00 )
   {
    mask = 0x80;
    ptr++;
    // Zero the byte so if there is a one off error in bits, it is not a false ack.
    *ptr = 0x00;
   }

   // Is there a packet with id 'ackID' ?
   if( d_inQueue.UnorderedPacketIsQueued( ackID ) == true )
   {
    *ptr |= mask;  // There is
   }
   else
   {
    *ptr &= ~mask;  // There isn't
   }

   mask >>= 1;
   ackID++;
  }

#if defined( _DEBUG_VERBOSE )
  OUTPUTREPORT0( "\n" );
#endif

  // Record the ammount of the ackBuffer used.
  d_ackLength = (unsigned short)(ptr - (unsigned char *)d_ackBuffer);
  assert(d_ackLength <= ACK_BUFFERLENGTH);

  // return the number of bytes read from buffer
  return (unsigned short)( readPtr - pBuffer );
 }


Sunday, November 20, 2011

MTUDP.cpp NetLib Bug fixes.

WARNING - I should remove this post, but instead will give a warning.  Do not use the MTUDP.cpp library as is.  It has many bugs and makes a fatal mistake.  The user ID is the IP address.  This breaks if there is a fire wall in the way, and there is always a firewall.  I have nearly rewritten the library with very little of the original code left over.

--------------------------------------------------------------------

I have been using the MTUDP.cpp library from the book
Advanced 3D game programming with DirectX 10.0 By Peter Walsh


The library has many bugs that I have been fixing over time.


Several are...

The library send all packets twice, which is unnecessary. So in MTUDP.cpp I comment out the three sections where that happens. Look for secondPacket to find the blocks.

In NetLibHost.cpp there is a big problem with the Ack generation loops. They initialize the mask to 0x80 and if there are no additional Acks, then the later count returned is off by one since the mask is not zero. The mask should be initialized to 0x00. (two places in the code. Search for mask = 0x80;) WARNING - WRONG - SEE NEXT POST

The Ack record can be truncated in AddAckMessage it checks to see if the the length is exceeded and if it is it truncates, but the count of additional acks is not adjusted, boom! I don't have a fix for this except make sure no packets approach the max packet size boundary. I put an assert in to check if you run off the end.

I noticed that on creation the Host record does not initialize the ping times and last packet time. Hmmm, haven't worked on that one yet.

Hope this saved some poor soul some time.



TF

Tuesday, October 18, 2011

A change of weather

I just read (slogged through) the rather lengthy and full-of-Greek-letters paper, http://rspa.royalsocietypublishing.org/content/466/2114/303.full.pdf+html

Wow, I have been a long standing global warming skeptic.  This paper has been quite an awakening.

In this paper Mike Lockwood discusses with real numbers, real data, and the best science available all the rumors and innuendos on the internet about climate.

For example one of my favorites has been "The solar wind varies during sunspot cycles and the kinetic impact of the solar wind on the upper atmosphere could be causing warming, so at solar minimums the climate should cool."  Turns out that has been studied and estimated and is about 0.02 watts per square meter (page 323).  Global warming is in the range of 5 watts per square meter of effective heating.

In many places there are fairly wide ranges of estimates and he freely admits that.  But the range of error in "Well, I think such and such because it just seems right" is one heck of a lot wider in error.

One thing I get from reading many different scientific papers on climate (you know, the ones that are PDFs and highly technical, dense in facts and data, and unemotional, and written by actual scientists) is that the science of climate is in a huge state of flux. Planetary science is in a similar state and for the same reasons, we have satellites that are getting better and better data all the time.

The basic issue is not "do we cause global warming" nor is it "is climate mostly Sun-controlled". The real issue is "what fraction of the total climate is determined by various causes, and how?"  So in the climate debate, everyone is correct, but how correct and whom should policy makers listen to is the real issue. Also it may be that the largest climate fluctuation controller over a century or two is the sun + ocean cycles + whatever, but a very long term trend is that humans are warming the planet.  This means the highs get a little higher and the lows a little warmer, which could have profound effects on human well being.

There should also be a policy debate on what effect humans are having on climate and what can we do about it vs. what does it cost in short and long term resource investment.  This debate is not happening at all in the general public sector.

So here are the fundamental questions and where my opinion has of late changed drastically:
  1. Is global warming and/or climate change happening.  Yes.  No change here.  Everyone knows this and climate has been fluctuating for the last several billion years.
  2. Are we causing global warming? Big change here - Yes.  The evidence points to this.  It is not perfectly conclusive, but is the best most logical science we have now.  This evidence is buried under a mountain of opinion, politics, and social fear of the consequences, yet at the same time is in plain sight on the internet.  You just have to look for it and train your self to read the academic jargon.  Not that hard with practice. (I cut my teeth on Scientific American and other more technical reading so I learned this at about age 10.)
  3. Can we do any thing about it?  Yes, but it will require changes in basic societal values.  There are even some very simple solutions like injecting Sulfur Dioxide into the upper atmosphere, which would not be all that expensive or difficult.  (http://www.scientificamerican.com/article.cfm?id=poll-finds-support-for-geoengineering-blocking-sunshine) But see #4 below. (An experiment is happening very soon in England to test this idea.) There are many ideas such as lower carbon emissions, mirrors in space, etc.
  4. Will we do anything?  The current intelligence and mindset of politicians in all the world governments (not just the United States) is so pitifully low as to make it doubtful anything effective can or will be done. I suggest the video "Pale Blue Dot" on youtube. It is very unfortunate that the United States is in the perfect position to lead the world into a more sustainable future, but does not.  Such leadership will take more than a well connected oil man, or a hansome charismatic speaker.  It will take an actual leader of talent, integrity, and compromise.  Good luck with either political party of the US ever fielding such a candidate.  That future world does not need to be a world of low income peasant medieval farmers, it could be a very nice world, in many ways better that the current one.  The only way a real solution (not the joke that the Kyoto Protocol is) will happen is when the general population decides to make it happen.  Historically our track record for such response is not too good.  Neither the Democrats, nor Republicans, nor the Tree Huggers have the skills or mindset to solve this. None of the above parties have any interest in solving climate issues.  The politicians love a Big Crisis and the Al Gores of the world would be out of a job if a solution a simple as Sulfur Dioxide injection worked. (Estimated cost $200 million to solve the whole problem, untested).
As Jared Diamond said, "Cautious optimism".
    TF

    P.S. History never comes out the way one predicts or expects. Life is an adventure.

    Wednesday, September 7, 2011

    Stupid Programmer Tricks, C++

    Ok,
    I've been diving into C++ after not using it for a long time.  There are some pitfalls that have cost allot of time.
    Rather than clutter things up with angry exclamation points to show frustration, I'll make the simple statements.


    1. Destructors must be declared virtual in the base class or the child class destructor will not get called.
    2. You can declare a variable in a base class and then declare it in the child class and no compiler error or warning gets generated.  But they are different variables and when you set, NULL, or delete one, the other is untouched, with very ugly side effects.
    3. You must always initialize variables or they will contain garbage.  In particular, you must set pointers to NULL
    Now I bet there are compiler flags I could have set or some such, but they are not the default Visual Studio C++ settings. Hope I saved you some time.

    TF

    Saturday, August 20, 2011

    Permaculture and Rocks - Mico-dams

    So I was studying my yard for about an hour today.  This "study" consists of walking around while the sprinklers run and just looking.  The back of my yard is a very steep slope up to the yard behind us.  I'm in Utah so we are in an alpine desert.  The slope is eroding.

    After a while I began asking my self, "why does that plant (weed?) grow there?"  I noticed that around the rocks that are a foot around lots of plants grow. but on the barren eroding slope nothing grows.  The dirt eroding down the hill get dammed up behind the rocks and forms a small flat spot where the plants grow.


    The rocks also deflect the rain to the plants and keep the soil under the rock cooler and moist.  Our back patio has nice green grass between the flagstones for the same reason.

    I have taken lots of the rocks that were along the bottom of the slope, and moved them up into the erosion gullies as little dams to hold back the dirt.  We will see how it looks next summer.

    P.S. In the spirit of getting many synergistic things done at once, I also got some good weight lifting in without the cost of a Spa.

    TF

    Friday, July 29, 2011

    On Not Watching TV

    Sometimes some aspect of life can disappear and you don't even notice for a long while...

    A while back we stopped paying out Comcast bill.  They eventually shut us off, and a few weeks later some guy showed up and retrieved the cable boxes when I wasn't home.

    At some point after several weeks of no TV, I realized that the TV no longer worked!

    We still have internet and NetFlix, still have the HDTV in the basement for NetFlix BlueRay, and all the XBoxen, Wiii, etc. so it's not like we are unplugged.  We watch TV shows, but when we want to, on our schedule.

    So some thoughts are in order in regard to the great wasteland that is TV.
    • Wow, the house is quieter in the evenings. Before, there was always the TV in in the evenings and loud too.
    • Everyone is doing more interesting things, at a minimum on the computers instead where it is interactive activities.
    • The stress of TV is gone, let me explain: Most TV shows, if you get far away and listen to the voice tone instead of the actual words, are all people with tons of stress in their voices.  The 'reality' shows which Weird Al parodies so well, are all borderline psychotic people emoting about some tragedy.  The predominant emotions on TV are stress, fear, violence, fright, anxiety and such.
    It is probably 'writing on the wall' that my TV could disappear and I didn't even notice for a few weeks.  The networks are doomed.

    TF

    Thursday, July 14, 2011

    On Raw Salad

    So after reading a raw foods book, where they suggest you eat only live food, and another book by Art DeVany about paleofitness, I have been eating more salads.

    So I bought a organic salad mix of baby greens in a plastic box.  I didn't have any salad dressing, so I just ate from the box like the leaves were potato chips.

    Wow, each type of leaf has a unique flavor.  When you drown a salad in dressing, you miss what the actual salad tastes like!

    It sort of surprises your tongue when you put in a leaf, since you never know what a given leaf will taste like.

    TF

    Friday, July 8, 2011

    NetLib C++ bug fix in Advanced 3D Game Programming with DirectX 10.0

    Ok,
    I'm using NetLib and got a packet to transmit and receive, but there was a crash.

    In QueueIn.cpp in AddPacket the line
    pPacket = *d_packetsUnordered.begin();
    Throws on the first packet.
    Just before that line you need...

    if(d_packetsUnordered.size() > 0)
    {


    TF
     
     

    Friday, June 10, 2011

    Notes on I2C and SSI bus implementation

    A quick note:

    When you implement I2C and/or SSI you must implement timeouts and anit-lockup code.
    Both busses are driven with statements like

    while(some flag)  wait forever.

    And you can get locked up if there is a single clock glitch.


    void I2CResetLoopTimer(int i2cDeviceIdx)
    {
      xI2CConfigHandle h = I2CDevices[i2cDeviceIdx];
      h->loopTimer = xTaskGetTickCount();
    }


    int I2CHasError(int i2cDeviceIdx)
    {
      xI2CConfigHandle h = I2CDevices[i2cDeviceIdx];
      portTickType dt = xTaskGetTickCount() - h->loopTimer;
     
      return dt > 200 ||
        I2C_GetFlagStatus(h->i2cDevice, I2C_FLAG_TIMEOUT) ||
          I2C_GetFlagStatus(h->i2cDevice, I2C_FLAG_PECERR) ||
            I2C_GetFlagStatus(h->i2cDevice, I2C_FLAG_AF) ||
              I2C_GetFlagStatus(h->i2cDevice, I2C_FLAG_ARLO) ||
                I2C_GetFlagStatus(h->i2cDevice, I2C_FLAG_BERR);
    }


    int I2CHasErrorAndClear(int i2cDeviceIdx)
    {
      if(I2CHasError(i2cDeviceIdx))
      {
        I2CClearError(i2cDeviceIdx);
        return true;
      }
      return false;
    }

    And an example loop.

    int WhileBusy(int i2cDeviceIdx)
    {
      xI2CConfigHandle h = I2CDevices[i2cDeviceIdx];
      
      I2CResetLoopTimer(i2cDeviceIdx);
      while (I2C_GetFlagStatus(h->i2cDevice, I2C_FLAG_BUSY))
      {
        if(I2CHasErrorAndClear(i2cDeviceIdx))
        {
          return false;
        }
        
        portYIELD();
      }
      return true;
    }

    TF

    I2C Reset on ST Microsystems Processors

    So,
    You have a ST processor (e.g. STM32F103) and a I2C device.  If the device, bus, or processor gets a bit error in the I2C bus, it will lock up the bus.

    After trying many solutions, this one works...



    void I2C_ResetAndInit()
    {
    /* This shuts off power to the I2C circuit on the processor. */
    I2C_DeInit(I2C1);

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    /* SCL  pin enable */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* SDA pin enable  */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    I2C_StructInit(&I2C1_InitDef);
    // 400 khz.
    I2C1_InitDef.I2C_ClockSpeed = 100000;
    I2C_Init(I2C1, &I2C1_InitDef);

    I2C_Cmd(I2C1, ENABLE);
    }

    And for the I2c Device out there on the bus...
    Oh, we are using RTOS so that is the delayt and tick stuff.

    portTickType Baro_LastErrorMessageTime = 0;
    void BaroResetChip()
    {
    if(xTaskGetTickCount() - Baro_LastErrorMessageTime > 10000)
    {
    Baro_LastErrorMessageTime = xTaskGetTickCount();
    mainMessagePrint(ROUTE_HALL, "Baro failed, reset.");
    }

    I2CClearError(I2C_DEVICE_BARO);
    // Turn the baro power off and then back on.
    // You DID put this in your design, right?
    // Also, many I2C chips have a reset line that will do the same thing.
    SetPwrBaro(0);
    vTaskDelay(3000);
    SetPwrBaro(1);

    I2C_ResetAndInit();
    }

    In summary, the important pat is you must either reset or power cycle the I2C device, and you must use DeInit to power cycle the I2C internal device on the CPU.

    TF


    Monday, April 4, 2011

    XNA Steam side by side configuration

    Quick Note:

    I had a side by side configuration error when trying to run my C# XNA Steam app on a clean machine.

    Short Answer: The problem was that my dll I wrote to mediate between XNA C# and unmanaged C++
    was compiled in debug mode instead of release mode.

    This happens because the VC redist package is for release only.  You can not redistribute the debug version.
    Once I recompile for release and moved the .dll and such into my steam release area it worked fine.

    TF

    P.S. I will be making the SteamLink source available to the Steam guys so they can give it out to developers.
    That will save tons of time for other people.