Can't get data out of FTDI FT201X using i2c - c#

I have a project using the FTDI FT201X as a USB to i2c slave and the i2c master is an AVR microcontroller. I'm using WPF Core 3.1 C# on a Windows 10 machine. Basically, everything with the FTDI chip works fine except I can't successfully get data sent from the PC to the FTDI chip no matter what I try. The D2XX Write function says it was successful and returns no error, but there is never any data in the buffer when I try to read.
I've since written a small test program in an attempt to isolate the issue but the problem remains. Basically, when a button is clicked we open the device by serial number, we write a command to the device's buffers, handshake with the AVR to let it know to read and then wait for the AVR to drive a handshake pin low meaning it has received the data.
public class USBLibrary
{
byte targetDeviceCount = 0;
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OK;
public FTDI connectedUSBDevice;
// Called from button click event
public void ConnectUSB()
{
bool isOK = true;
byte numOfBytes = 1;
uint bytesWritten = 0;
bool usbInPinIsHigh = false; // Tracks USB In Pin
byte lowMask = 0b00010000; // CBUS 0 is output (4-7), all pins low (0-3) (Default Setting)
byte highMask = 0b00010001; // CBUS 0 is output (4-7), CBUS 3 is high
byte inPinMask = 0b00001000; // AND with pin states to get input pin value (Bus3)
byte pinStates = 0; // Used to get the current pin values
double timeout = 0;
// Create new instance of the FTDI device class
connectedUSBDevice = new FTDI();
// Determine the number of FTDI devices connected to the machine
ftStatus = connectedUSBDevice.OpenBySerialNumber("P00001");
/*** Write to Device ***/
byte[] firmwareCmd = new byte[numOfBytes];
firmwareCmd[0] = 128; // 128 is Get Firmware Command
// firmwareCmd[1] = 61; // Just Testing
// Write Firmware Command to Tx buffer
ftStatus = connectedUSBDevice.Write(firmwareCmd, numOfBytes, ref bytesWritten);
Trace.WriteLine(bytesWritten);
// Handshake with Device
isOK = DeviceHandshake(lowMask, highMask, inPinMask);
// Check if handshake failed
if (isOK == false)
{
return;
}
Task.Delay(10);
// Wait until message is sent
while ((usbInPinIsHigh == false) && (timeout <= 1000))
{
Task.Delay(1);
// Check for USB In pin to go high. Signals FW transfer is complete and to retrieve.
ftStatus = connectedUSBDevice.GetPinStates(ref pinStates);
// Is input pin high or low?
if ((pinStates & inPinMask) == inPinMask) // In pin high
{
usbInPinIsHigh = true; // Means uC finished sending data
}
timeout++;
}
// TEST: displays timeout amount for testing
Trace.WriteLine("Timeout=" + timeout);
ftStatus = connectedUSBDevice.Close();
}
}
NOTE: For this code, I've taken out a lot of the error checking code for clarity. Also, the handshake code is not shown because it shouldn't be relevant: raise output pin, listen for AVR to raise output pin, lower output pin, listen for AVR to lower output pin.
On the AVR side, we simply poll for the FT201X's pin to go high and then handshake with the chip. Then we simply read. The read function always returns 0.
I doubt the problem is with i2c as there are 3 IO Expander chips controlling LEDs and buttons and we can read and write to those fine. Further, the FT chip has a function called Get USB State where you can check to see the device's status by sending the command and reading the result via i2c. When I do this, I always get back the correct 0x03 "Configured" state. So we can read from the chip via i2c.
There's also a function that will return the # of bytes in the buffer waiting to be read...when I do this, it always says 0 bytes.
And for good measure I replaced the chip with a new one in case it was bad and again we had the same results.
Is there anything I'm missing in terms of setting up the chip beyond using FT_Prog, like an initialization procedure or setting registers or something? Or do I need to somehow push the byte I write to the front of the queue or something before it can be read? Anybody seen anything like this before?
Given that I haven't affected the results, I'm either missing a key part in the process or something is wrong with their driver/version of the chip. It's been 3 weeks, I'm out of ideas, and my hair is patchy from ripping out large chunks. Please save my hair.

Check by oscilloscope that your I2C master gives clock for your slave (FT201x). Try to control only I2C (rip off GPIO controls) and check if you can isolate problem that way. I suppose you are very familiar with FT201X datasheet. Good luck!

Check the latency timer setting. It’s described in this document, https://www.ftdichip.com/Support/Documents/AppNotes/AN232B-04_DataLatencyFlow.pdf. In section 3.3, you’ll find a section describing a scenario in which no data will be made available to the app.
“While the host controller is waiting for one of the above conditions to occur, NO data is received by our driver and hence the user's application. The data, if there is any, is only finally transferred after one of the above conditions has occurred.”
You can use the latency timer to work around it, if you’re hitting this. Try setting it to 1ms, its lowest value. If your data has a delimiter character, consider setting that as an event character and you might get even better results.

Did this issue ever get resolved?
Experiencing the same issues with an FT200X except the function "bytes available" (0x0C) returns the correct byte count sent from the host PC, but can't read the actual bytes using the read procedure mentioned in the datasheet.
I have also several other I2C devices on the bus, working fine.

Related

Getting Received and Sent Bytes generated by Process for Network Activity

This is next step of my previous question.
I'm creating a C# WinForm Application which will display Network Activity (Bytes Received / Bytes Sent) for a given Process (For Example: Process name 's chrome.exe) and Speed in Megabits/s generated by the Process.
While using the Performance Counters IO Read Bytes/sec and IO Read Bytes/sec shows I/O read and write bytes instead of 'Send and Received Bytes'.
PS: I/O counts all File, Network, and Device I/Os bytes generated by a Process. But, I wants only Network Bytes generated by a particular Process.
I wanted to retrieve only Bytes Received and Bytes Sent. But, don't know what counters are used to get these bytes of a Process.
I have searched these links for this purpose but not useful:
C# Resource Monitor get network activity values
Retrieve process network usage
Missing network sent/received
Need "Processes with Network Activity" functionality in managed code - Like resmon.exe does it
Here is Process's Performance Counter code that tried:
PerformanceCounter bytesReceived = new PerformanceCounter("Process", "IO Read Bytes/sec");
PerformanceCounter bytesSent = new PerformanceCounter("Process", "IO Write Bytes/sec");
string ProcessName = "chrome";
bytesReceived.InstanceName = ProcessName;
bytesSent.InstanceName = ProcessName;
Question: How I can only get the Received and Sent Bytes generated by a Process for a network activity.
As already mentioned in the comments, I don't believe there is a way to achieve this using the PerformanceCounter class. Since it uses Windows' built-in performance counters, this can be verified by querying the entire list of installed counters using the typeperf command. On my local machine this yields about 3.200 different counters, which I went through to verify my claim. There actually are counters for network send/receive (even for specific network interfaces/adapters or processors), but none of them can filter for a specific process or process family.
Thus, the easier way might be to use this (already quite complete) answer, which makes use of the Microsoft.Diagnostics.Tracing.TraceEvent NuGet package. For testing I condensed it down to a minimal amount of code and modified it to capture the traffic of an entire process family.
static void Main(string[] args)
{
// Counter variables
var counterLock = new object();
int received = 0;
int sent = 0;
// Fetch ID of all Firefox processes
var processList = Process.GetProcessesByName("firefox").Select(p => p.Id).ToHashSet();
// Run in another thread, since this will be a blocking operation (see below)
Task.Run(() =>
{
// Start ETW session
using(var session = new TraceEventSession("MyKernelAndClrEventsSession"))
{
// Query network events
session.EnableKernelProvider(KernelTraceEventParser.Keywords.NetworkTCPIP);
// Subscribe to trace events
// These will be called by another thread, so locking is needed here
session.Source.Kernel.TcpIpRecv += data =>
{
if(processList.Contains(data.ProcessID))
lock(counterLock)
received += data.size;
};
session.Source.Kernel.TcpIpSend += data =>
{
if(processList.Contains(data.ProcessID))
lock(counterLock)
sent += data.size;
};
// Process all events (this will block)
session.Source.Process();
}
});
// Program logic to handle counter values
while(true)
{
// Wait some time and print current counter status
Task.Delay(2000).Wait();
lock(counterLock)
Console.WriteLine($"Sent: {sent.ToString("N0")} bytes Received: {received.ToString("N0")} bytes");
}
}
Note that you need elevated (administrator) privileges to execute this code.
I tested with Mozilla Firefox, which had 10 processes (7 tabs) running at that time; I downloaded a big file, and the program correctly printed the added network traffic (plus some noise from active tabs), without including the involved disk accesses (which would have at least doubled the measured traffic).
Also note that this only captures TCP/IP traffic; to also capture UDP/IP traffic, you need to subscribe to the UdpIpSend and UdpIpRecv events.

How solid is the Mono SerialPort class?

I have an application that, among other things, uses the SerialPort to communicate with a Digi XBee coordinator radio.
The code for this works rock solid on the desktop under .NET.
Under Mono running on a Quark board and WindRiver Linux, I get about a 99% failure rate when attempting to receive and decode messages from other radios in the network due to checksum validation errors.
Things I have tested:
I'm using polling for the serial port, not events, since event-driven serial is not supported in Mono. So the problem is not event related.
The default USB Coordinator uses an FTDI chipset, but I swapped out to use a proto board and a Prolific USB to serial converter and I see the same failure rate. I think this eliminates the FTDI driver as the problem.
I changed the code to never try duplex communication. It's either sending or receiving. Same errors.
I changed the code to read one byte at a time instead of in blocks sized by the size identifier in the incoming packet. Same errors.
I see this with a variety of remote devices (smart plug, wall router, LTH), so it's not remote-device specific.
The error occurs with solicited or unsolicited messages coming from other devices.
I looked at some of the raw packets that fail a checksum and manual calculation gets the same result, so the checksum calculation itself is right.
Looking at the data I see what appear to be packet headers mid-packet (i.e. inside the length indicated in the packet header). This makes me think that I'm "missing" some bytes, causing subsequent packet data to be getting read into earlier packets.
Again, this works fine on the desktop, but for completeness, this is the core of the receiver code (with error checking removed for brevity):
do
{
byte[] buffer;
// find the packet start
byte #byte = 0;
do
{
#byte = (byte)m_port.ReadByte();
} while (#byte != PACKET_DELIMITER);
int read = 0;
while(read < 2)
{
read += m_port.Read(lengthBuffer, read, 2 - read);
}
var length = lengthBuffer.NetworkToHostUShort(0);
// get the packet data
buffer = new byte[length + 4];
buffer[0] = PACKET_DELIMITER;
buffer[1] = lengthBuffer[0];
buffer[2] = lengthBuffer[1];
do
{
read += m_port.Read(buffer, 3 + read, (buffer.Length - 3) - read);
} while (read < (length + 1));
m_frameQueue.Enqueue(buffer);
m_frameReadyEvent.Set();
} while (m_port.BytesToRead > 0);
I can only think of two places where the failure might be happening - the Mono SerialPort implementation or the WindRiver serial port driver that's sitting above the USB stack. I'm inclined to think that WindRiver has a good driver.
To add to the confusion, we're running Modbus Serial on the same device (in a different application) via Mono and that works fine for days, which somewhat vindicates Mono.
Has anyone else got any experience with the Mono SerialPort? Is it solid? Flaky? Any ideas on what could be going on here?
m_port.Read(lengthBuffer, 0, 2);
That's a bug, you have no guarantee whatsoever that you'll actually read two bytes. Getting just one is very common, serial ports are slow. You must use the return value of Read() to check. Note how you did it right in your second usage. Beyond looping, the simple alternative is to just call ReadByte() twice.

SerialPort DataReceived event called or maybe sometimes with 7 data bits [duplicate]

I am working out with serial com port.
I have insert this code in my program.
I able to send data to the devices and fail to read data from the devices.
In debug mode, i only able to get serialport.BytesToRead = 0.
May i know why this will happen??
while (serialport.BytesToRead > 0)
{
int byte_count = serialport.BytesToRead;
byte[] buffer = new byte[byte_count];
int read_count = serialport.Read(buffer, 0, byte_count);
string echo = ASCIIEncoding.ASCII.GetString(buffer, 0, read_count);
echo = System.Text.Encoding.UTF8.GetString(buffer);
Console.WriteLine(echo);
}
First use another program, like Putty or HyperTerminal to verify that the device and connection is in working order and to double-check that you are using the correct port, baudrate, parity, stopbits and databits. If you can't get anything out of the device with such a program then it won't work either using your own code.
Next focus on the handshaking. A common mistake is to leave it at none and then not turn on the DtrEnable and RtsEnable signals. A device won't send anything when it thinks that you're offline. SysInternals' PortMon utility can be handy, it shows you what's going on at the device driver level.
When to you read from the SerialPort? Are you trying to read right after you send? In that case you might try to read before there is actually anything to read from the port.
You should use the DataReceived event to read data.
Note that this event might trigger before all data is received, so you might have to retrieve the data over several calls of DataReceived until you get all the data you are supposed to.

Serial port read string

I have a serial port app that read weighing machine.
public void Read()
{
while (Puerto.BytesToRead > 0)
{
try
{
string inputData = Puerto.ReadExisting();
dataReceived = inputData;
}
catch (TimeoutException) { }
}
}
the return string is like this
It has other extrange chars in it, how can i do to parse or get a clean data from it? all I need is 0.52lb
I have no idea what weighing machine is it and what the serial port specs on it but, if it is black box to you too then, check the following:
- check if you have a technical spec that explains what comes out of RS232 port
- do several (10?) samples with one sample weight and see if the number of bytes are delivered each time
- if you see the number of bytes being constant (barring discrepancy in the 0.52lb text changing to 0.5lb once in a while), it is likely that garbage following the weight is additional binary data.
- if not, and you see the weight (text) with exact offset each time, you just can scrape the output
this is complete reverse engineering, I suggest going after technical spec and doing more insightful data handling though.
This could be anything - a bug in the weighing machine, some sort of hardware issue, or a problem in how the serial port is configured. I would suspect a configuration problem. Make sure all the settings are correct (BaudRate, Handshake, Parity, StopBits). Also, try connecting to the same serial port device using another program (e.g. see http://helpdeskgeek.com/windows-7/windows-7-hyperterminal/ ) and see if you see the same garbage data.

Serial port in .Net (C#)

what should i do to wait until all the data sent to serial port
to test this condition assume the code bellow:
Console.WriteLine("Baud is:" + SerialPortObj.BaudRate);
Console.WriteLine(DateTime.Now.Millisecond);
string tmpStr="";
for (int i = 0; i < 100; i++)
{
tmpStr += "A";
}
SerialPortObj.Write(tmpStr.ToCharArray(),0,99);
Console.WriteLine(DateTime.Now.Millisecond);
example output is:
Baud is:300
97
97
And it indicate that .Net is not waiting until all chars to be send!
just to mention the code below does not work:
Console.WriteLine("Baud is:" + SerialPortObj.BaudRate);
Console.WriteLine(DateTime.Now.Millisecond);
string tmpStr="";
for (int i = 0; i < 100; i++)
{
tmpStr += "A";
}
SerialPortObj.Write(tmpStr.ToCharArray(),0,99);
while (SerialPortObj.BytesToWrite>0)
{
Thread.Sleep(1);
Console.WriteLine(SerialPortObj.BytesToWrite);
};
Console.WriteLine(DateTime.Now.Millisecond);
example output is:
Baud is:300
97
97
i am working on an special protocol that is depends on baud rate change over and use some thing like the follow:
->[Send Some Bytes (Baud300)]
<-[Receive Another Bytes (Baud9600)]
so i want to send some chars by write method and wait until it finish and right after finishing i try to change baud , so i could understand the received bytes
is there any idea?
In the first place the serial port is stateless. So you can never really by sure when the right point in time is reached for a baud rate change. Due to the fact that you are going to implement your own special protocol you must have control of both sides of the communication (sender/receiver). So in that case i strongly recommend to also set the Handshake property to RequestToSend and checking of the DtrEnable property.
Also you should use two buffers (received/outgoing) on each site of the communication which are watched by their own task/thread. If you push something into the outgoing buffer, the task check if sending is possible (CtsHolding, DsrHolding) and if yes, change the baudrate and push that data onto the wire. Wait till the holding properties are set back and then change the baudrate to the other value. The incoming thread is quite simple in this case. It simply waits for the DataReceived event cause the change of the baudrate is done by the outgoing task.
If you use hardware handshake (which i strongly recommend in your case), then be sure that your serial port supports it correctly. Most of the USB-to-Serial-Adapters don't work very well with anything else then 19200-8-N-1. So before you think you didn't code it right or the SerialPort class is buggy try to find two machines with a real serial port (or one machine with two ports for testing).
Try to store your data in a variable and when a specific condition apear (can be set by you), send the value of the variable to the serial port
Do it in hardware?
You might try to use two serial adaptors, configured as 300/9600. Tx on one and rx on the other. You would need a 'funny cable' with pins 2/3 split out to different D-types, but that should work.

Categories