Usability of i2c of fl2k?

Steve Markgraf steve at steve-m.de
Sun Jun 17 20:02:03 UTC 2018


Hi Torben,

I'm replying with the mailing-list in Cc, as this might also be
interesting for others.

As mentioned earlier, the issue is that the FL2000 has a very inflexible
I2C implementation that was only intended (I guess?) for I2C EEPROMs.
The PCF8574 you want to use is much simpler, as it expects only one data
byte after being addressed.

If you can live with only 6 of the 8 outputs on your port expander, you
might still be able to get it working.

What the FL2000 does for an I2C write is the following:

START, I2C_ADDR(W), REG_ADDR,   DATA[0], STOP
START, I2C_ADDR(W), REG_ADDR+1, DATA[1], STOP
START, I2C_ADDR(W), REG_ADDR+2, DATA[2], STOP
START, I2C_ADDR(W), REG_ADDR+3, DATA[3], STOP

As you can see, REG_ADDR is the first byte of data that is being sent to
the device after the address. This is where you need to put the data
you want to set on the IO expander outputs. As the FL2000
auto-increments the register address, you need to set the lowest 2 bits
to 0, so that the increment is not carried to the higher bits. But that
also means that output 0 and 1 of your port-expander will toggle with
each write and are not controllable by you.

>From the datasheet of the PCF8574:
"If other data bytes are sent from the master, following the
acknowledge, they are ignored by this device."

That means that DATA[0-3] are completely ignored, which probably means
that the device will send a NAK for that byte.
So the transfer always will fail from the view of the FL2000, so you
must ignore the return value of fl2k_i2c_write(), which means you also
have no feedback if the slave is actually present or not.

The first thing I would suggest trying is writing a non-zero reg_addr to
all possible slave addresses and observe the output of the port
expander. If you have a logic analyzer, I suggest to use that and have a
look at the I2C bus.

If all that doesn't work, using a small MCU and dealing with the FL2000
I2C oddities there is probably the easiest solution.

Regards,
Steve

On 17.06.2018 21:11, Torben Keil wrote:
> Hi Steve,
> 
> I tried my luck with i2c... but I wasn't successful.
> There's a PCF8574 (Portextender) connected directly on the I2C interface
> of fl2k.
>  
> Here's my code:
> 
> torben at Mworkstation: <mailto:torben at Mworkstation:>~/Amateurfunk/C++$ cat
> fl2k_i2c.cpp
> // g++ fl2k_i2c.cpp -L/home/torben/Amateurfunk/osmo-fl2k/build/src
> -I/home/torben/Amateurfunk/osmo-fl2k/include -losmo-fl2k -o fl2k-i2c_test
> #include "osmo-fl2k.h"
> #include <iostream>
> #include <bitset>
> 
> int main (int argc, char *argv[] ) {
>     int status;
>     fl2k_dev_t *dev = NULL;
>     uint8_t i2c_addr = 0b01000001;  // Letztes Bit: Read / #Write
>     uint8_t reg_addr = 0;
>     uint8_t *data = new uint8_t[10];
>     uint32_t dev_index = 0;
>     
>     fl2k_open(&dev, (uint32_t)dev_index);
>         if (NULL == dev) {
>                 std::cerr << "Failed to open fl2k device " << dev_index
> << std::endl;
>                 return -1;
>         }
> 
>         for (i2c_addr=0; i2c_addr<128; i2c_addr++) {
>         status = fl2k_i2c_read(dev, i2c_addr, reg_addr, data);
>         if( status >= 0 ) {
>             std::cout << "Adress: " << i2c_addr;
>             std::cout << "; I2C-Status: " << status << "; Data: ";
>             for( int i=0; i<static_cast<int>(status); i++) {
>                 std::cout << " " << std::bitset<8>(data[i]);
>             }
>             std::cout << std::endl;
>                                                                                                                              
>         }
>                                                                                                                                                        
>                                                                                                                                                                  
>         data[0]=127;
>         for (i2c_addr=0; i2c_addr<128; i2c_addr++) {
>             //fl2k_i2c_write(fl2k_dev_t *dev, uint8_t i2c_addr, uint8_t
> reg_addr, uint8_t *data);
>             status = fl2k_i2c_write(dev, i2c_addr, 0, data);
>             if( status >= 0 ) {
>                 std::cout << "Write Adress: " << i2c_addr;
>                 std::cout << "; I2C-Status: " << status <<  std::endl;
>             } else {
>                 std::cout << static_cast<int>(i2c_addr) << "\t";
>             }
>         }
>     }
>     
>     fl2k_close(dev);
>     
>     free(data);
>     
>         return 0;
>     
> }
> 
> Output of that program after a fresh reboot of the system:
> torben at Mworkstation:~/Amateurfunk/C++$ ./fl2k-i2c_test
> Kernel mass storage driver is attached, detaching driver. This may take
> more than 10 seconds!
> 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
> 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
> 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
> 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
> 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
> 117 118 119 120 121 122 123 124 125 126 127
>  
> So there's nothing reachable via I2C.
>  
> What am I doing wrong here?
>  
>  
> Greetings,
> Torben
> 
> 
> 
> Am 17.06.2018 03:18, schrieb Steve Markgraf:
>> Hi Torben,
>>
>> On 16.06.2018 09:40, Torben Keil wrote:
>>> do you have a git repository for the code so that I could have a try?
>>
>> I've debugged and cleaned up the I2C code and just pushed it.
>> I2C transfers with the FL2000 seem to fail from time to time, so make
>> sure to check the return code of fl2k_i2c_read()/fl2k_i2c_write().
>>
>> Regards,
>> Steve



More information about the osmocom-sdr mailing list