On the picture you can see my test equipment for the FTDI. Three parts are involved:
1. Asus EEE PC as platform
2. FTDI interface board ( small one)
3. I2C I/O board ( big one )
The final test I did was based on the fact that I simulated the real domotic logic as close as possible to the final program logical blocks. I also included the fact of worse case timings. The best way to explain this is by showing you the piece of test code I wrote:
void TestWorstCaseTiming(void)
UCHAR in [5]; //I2C InBuf
UCHAR out [5]; //I2C OutBuf
UCHAR ad [1]; //Int
//*********INIT BLOCK
status = FTDI_I2C_STARTUP( _400KHZ );
//*********PREPARE IN AND INVERT
status = FTDI_I2C_PCA_READN_ALL( PCA9698_INPUT_READ , in );
BitSetExtended<40> InSet(in);// start with real values
InSet.flip();// invert push = 1
//*********PREPARE OUT ALL TO ZERO
BitSetExtended<40> OutSet(CmdOut);
//OutSet.none();
OutSet.ToByteBuf(CmdOut);
status = FTDI_I2C_PCA_WRITE_ALL( PCA9698_OUTPUT_WRITE , CmdOut );//16ms
//*********MAIN LOOP
while (1)
{
//*********POLL LOOP
status = FTDI_2XX_READN_ADBUS(ad);
while ( (ad[0] & INT_MASK_FLAG) != 0 )
{
//overwrite time to have total chain time at the end
GetSystemTime(&begin);
status = FTDI_2XX_READN_ADBUS(ad);//2ms
}
//*********DOMOTICS LOGIC READ
status = FTDI_I2C_PCA_READN_ALL( PCA9698_INPUT_READ , in );//22ms
//*********DOMOTICS LOGIC COMPARE AND MODIFY
BitSetExtended<40> InNew(in);
InNew.flip();
for ( int input = 0 ; input <>
{
if ( (InSet[input] != InNew[input]) && (InNew.test(input)) )
{
OutSet.flip(input);
}
}
//*********DOMOTICS LOGIC UPDATE LAST IN
InSet = InNew;
//*********DOMOTICS LOGIC PREPARE AND OUT
OutSet.ToByteBuf(CmdOut);
status = FTDI_I2C_PCA_WRITE_ALL( PCA9698_OUTPUT_WRITE , CmdOut );//16ms
status = FTDI_I2C_DAC_SET(0,0);//10ms
//*********CHECK TIME
//Sleep(30); simulate cpu charge
GetSystemTime(&end);
printf ("cpu time : %d ms\n",end.wMilliseconds-begin.wMilliseconds);
// should be ca 50ms + Xms logic
}
}
The program flow is very simple. I poll on interrupt flag change in the inner while loop. As soon this becomes signals I leave the loop to read in the values of the PCA-IN. I check upon which bits are changed and also if this bit equal to 1. Due to the fact I use the inputs as button device I'm not interested if this bit is zero because this indicates the released state. I'm only act upon state pushed here. I invert the PCA-OUT accordingly to have a toggle behaviour on the leds. I didn't use a complex mapping for the in and out simply in-bit[0] relates to out-bit[0] etc for all 40 of them. Finally I write the new output state to the I/O board. I also added the DAC write just for timing simulating purposes but has no further meaning in this test. As you can see in the code I use the BitSetExtended<40> InNew(in) class. This one I wrote to ease the work with atomic bits. It's an extended (derived) STD class of BitSet:
template
{
typedef __int64 _Ty;
public:
BitSetExtended ( );
BitSetExtended ( __int64 ll );
BitSetExtended ( PUCHAR pC );
void ToByteBuf ( PUCHAR pC);
private:
enum { _Nb = CHAR_BIT * sizeof (_Ty),_Nw = _N == 0 ? 0 : (_N - 1) / _Nb };
void _Treat64( __int64 _X);
void _Tidy(_Ty _X = 0);
void _Trim( void );
_Ty _A[_Nw + 1];
};
Conclusion:
I find this a very good result even with quit slow communication of the FTDI USB device. In this test I wrote the code chained one block after the other. I didn't use any optimizations on the code flow and avoided working with multiple threads. I can think of a couple changes in terms of logic and threading which can optimize the program a little bit eg seperate the poll code into one thread using events and syncronizations on the FTDI object. Perhaps writing the read-in bits to a queue system and trait the changes in an other thread. I will look into this possibilties soon and report in my blog as usually do. But I must say I'm one step closer to my decision for taking this approach as my future domotic server.
No comments:
Post a Comment