@wjcroft I'm still waiting on my isolator and FT232H breakout, but want to make sure I understand before I get started. Sorry if this is really basic, but I have no experience doing anything like this.
If I understand right, the connections should be: PC---(via USB)---> USB Isolator ---(via USB)---> FT232H breakout ---(via??)---> OBCI.
How should the FT232H connect to OBCI? Do we do it the SPI way outlined above, or a different way?
You linked to the UART section of tutorial for FT232H. Is UART the intended protocol? If so, which pins on OBCI are needed? Will using UART instead of SPI give sufficient data rate?
Basically you're going to be going through similar steps to how Momen wired up his Bluetooth breakout board. But in your case you will be using usb vs wireless. Momen's instructions show the use of a "breadboard". However that adds to the bulk and fragility of the setup. Instead I suggest you mount the breakout as mentioned below on the mainboard with double stick foam tape.
If Jeffery still has the Sofia guys nearby doing various hardware projects in your "hackerspace" area, then those guys are great resources on how to do various microcontroller hookup steps such as soldering and using jumper wires. And feel free to continue posting here of course.
Connections:
A short usb cable from your laptop to the isolator; this could be as small as a foot or two. This cable uses the standard large usb connectors.
A longer usb cable goes from the isolator to the OpenBCI main board, where the FT232H is double stick foam tape mounted to the top of the mainboard; near the "chipKIT" or "OpenBCI" logo text would be fine. Stick the tape a few times to your hand skin to cut down the aggressiveness of the adhesive. This will make it easier to pull off the mainboard if needed. This cable is the mini-usb connector type.
The FT232H breakout comes with some header strips. I assume you have some short header pin jumper wires, with female sockets on each end. The wires here only need to be a couple inches long each. Easiest way to go is to solder in the header strip, you only need to use one of them, this is placed / soldered on the side with the holes labeled GND, D0, D1, etc.
There are two ways the long side of the pins can face: towards the top of the breakout board, or towards the bottom. Since you are double stick mounting this to the mainboard, it's best for the pins to come out on top. Be sure to follow the instructions as shown and trim the short side so that it is flush with the bottom of the board. Your foam tape will keep any conductors from contacting the mainboard.
Easiest way to solder, is to place BOTH pin header rows into a breadboard, then place the breakout on top of the short side pins, with the bottom of the board facing up. Now solder, remember you only need one row soldered. Other row is just holding everything level for your soldering step.
Now with your jumper wires you need to connect as shown here:
The TX (D0) on the breakout goes to RX on the mainboard. Use the same RX pin that Momen used. The RX (D1) on the breakout goes to TX on the mainboard. Use the same TX pin that Momen used. The GND on the breakout goes to GND on the mainboard.
All your mainboard pins are in the lower right corner in headers marked J3 or J4. Do NOT connect anything to the 5V pin!
As the Adafruit tutorial points out, the breakout board powers up in Serial UART mode. None of the other fancy features of the FTDI chip need to be used.
The current OpenBCI serial bit rate (set in the FTDI serial device COM port driver) is 115200 bps. These are 10 bit bytes, 8 data bits, 1 start and 1 stop bit. The FTDI serial chips also support 230400, 460800, and 921600. I would use the lowest one that can support your data stream.
Remember you need to configure the COM port on windows with the baud rate you want, and also adjust manually the FTDI device driver "Latency Timer" as you did with the OpenBCI COM port (1 millisecond).
This serial UART is much easier to connect than SPI and should give you enough speed.
Here is your pin mapping for the RX TX pins on the 32 bit board. I think Momen might have used the 8 bit board, so the pins he used probably don't apply in your case.
D11 is your TX (transmit) output pin from the chipKIT, and D12 is RX (receive). You need to edit that one settings file in the chipKIT core as Joel mentions. Then you just put the
Serial1.begin(460800);
(Or whatever baud rate you want). In your init section. All your usb IO will be on that Serial1 serial port. The Serial0 port is used to communicate with the RFduino, so is unavailable (and the pins are not available externally on headers.)
One point I continue to be confused about is the often-referred to serial bottleneck between the uC and RFduino. I had surmised from earlier posts in this thread that if using the Rx/Tx pins, then that serial bottleneck applied. I also saw many posts by biomurph in other threads stating his inability to change the 115200 baud rate. E.g. :
Does this issue only apply when we are transmitting over Rfduino? E.g. Momen was using the Rfduino and bluetooth. I had been operating under the idea that it applied whenever we used the Tx/Rx pins, hence the need to use the SPI pins. Will it be a problem if I need to send commands to the board, such as to do impedance checks? Can we send those over UART? I haven't gone into Momen's code yet, but I remember you mentioning that he kept the RFduino up in addition to bluetooth in order to send commands over it.
A few small points for anyone else reading this:
I'm pretty sure the FT232H breakout has a micro USB port, not a mini USB port.
It looks like the Isolator board takes a mini USB from the computer.
Yes, the "bottleneck" is the serial receive pin on the RFduino. If the baud rate is set faster than 115200, there is interference from the radio interrupt code that scrambles the data. I suggested a possible workaround, but that was not tried (receiving data with a very short and fast serial receive interrupt routine.)
The PIC32 hardware serial port should be capable of those higher baud rates we mentioned. And the FTDI must support them because they are listed in the COM driver.
Your USB COM port link will operate just like the current dongle radio link. For both commands and data.
re: mini to micro. I think there are small adapter plugs (mini one side, micro the other).
So the headers shown are female, 4 pins each. That means your jumper wires should have male on one end, female on the other to match the male header on the breakout. But in actuality, you could use any header gender you want, if you happen to have the matching jumper wires and header blocks.
@wjcroft So I'm still a bit unclear if we anticipate changing the baud from 115200 in this particular setup will cause problems with our USB COM connection running over the Tx/Rx pins. Has this been successfully done by someone on the forum? I'm wondering which of the following 2 possibilities you predict will happen:
Changing the baud from 115200 is not a problem for our serial COM port, but makes the RFduino unusable. Hence we need to send any and all instructions to the chip via the serial COM port.
Changing the baud causes RFduino interrupt interference which makes the UART serial COM port not work, and we need to find a workaround.
Winslow, hi. Each new FTDI device plugged into your laptop is a NEW COM port. The dongle is on one COM port, the FT232H breakout is a second COM port. The way you can tell them apart is to go into your control panel Device Manager and look at the description for the numbered COM port.
You will be modifying the mainboard firmware as described earlier. With the power switch in PC position, operation will be with the dongle and radio link COM port. With switch in BLE position, the other COM port is used and the firmware code is sending/receiving from Serial1 not Serial0.
YOU are the one who will do these firmware mods, using Momen's code as a suggestion. There will be TWO code paths in the firmware, one doing IO on Serial0, the original code. And your new code doing IO on Serial1. Does that make sense? Momen's code outputed to BOTH Serial0 and Serial1. Your code will only output/input from one Serial port at a time, depending on position of the power switch.
OK, on second thought, here is one more simplification of your firmware mods. You could just do a "grep" (string search operation) on the OpenBCI_32bit code tree and Daisy libraries for the string "Serial0". Then with your text editor, if you replace all those Serial0 strings with Serial1, that would have the effect of routing all IO over the wired link. The idea I suggested about using the power switch to control wireless vs wired mode could be helpful, but not strictly needed if you are going to be using wired mode primarily.
Note that the RFduinos (mainboard and dongle) do some juggling with the data packets sent by the chipKIT to the laptop. Adding bytes to the front / back of the packets, packet counter, etc. So I think Momen's code will show how to add those extra bytes where needed.
Also note that the uploading of new firmware to the chipKIT will still always be over the dongle radio link, as outlined in the OpenBCI tutorials. The bootloader is setup to use the radio exclusively. Your new firmware upload does not change the bootloader, which lives in a different address space.
We don't expect a problem in changing the baud rate on FT232H's COM port. That issue is confined to using the RFduino.
We can use the FT232H's COM port to do all IO, including sending instructions to the board such as starting, stopping, turning on and off channels, etc. This is because the board only cares that it is communicating with some COM port. It doesn't care about the details.
We need to take care to package the bytes properly to make the right packet format. See Momen's code for details.
I wont be able to get to attempting this until this upcoming week. I'll of course post details of how it goes.
In terms of Momen's mods, one way I always like to use, is to do a recursive diff of the original code tree and modified tree. This will usually show only a page or so of modified lines. Versus the total file sizes which could be large. There are various GUI diff programs that can do side by side listings comparisons. I've used WinMerge in the past.
Since Momen used the 8 bit board, it will be easiest to just take the ideas of what he has done, and transfer that over to your copy of the current OpenBCI_32bit code tree. Should be fairly straightforward; you'll be dropping his Bluetooth setup code. The previously mentioned string change, "Serial0" -> "Serial1" would go a long way towards the goal. That, and adding whatever header/footer bytes as needed.
As an intermediate simple test of your hardware and COM port setup, you could utilize a tiny uploaded chipKIT arduino program that just 'echos' the RX data onto TX. Using the serial terminal emulation program running on your laptop, built into the Arduino IDE app. Then what you type on the keyboard should be echoed onto your screen. This verifies the entire hardware / driver path from the COM port to the chipKIT and back. Also confirms your baud rate settings on chipKIT and laptop, which must match.
Here's a benchmark test of the FT232H COM port max baud rates. It easily reaches megabit/sec speeds! In your case you still want to pick the lowest speed needed to support your data stream needs.
As the speeds go higher and higher, especially over 1Mb/s, there can be noise that creeps into the TX / RX lines because they are not minimal length. Also the chipKIT UART and your firmware will likely be the limiting factor as the UART speed is increased. From what you've said about the 500 sps, I think 460800 will be plenty.
The Adafruit USB isolator is going to be fine for your application. The Analog Devices iCoupler (monolithic air core transformer) parts inside it are rated for Medical grade (IEC 60601, 5000V) isolation on the data lines, and 2500V on the +5V DC/DC power output. (In your case you are not even using the USB power to power the OpenBCI).
If someone was looking for a complete Medical grade isolator on both the data and power sides, I just saw this inexpensive model on Amazon, from CableMax, $40.
Yes @wjcroft, we were out of town at the BCI Meeting all week last week and catching up!
@yj, I'm using the firstDataPacket flag because the whole idea was to send the deltas between successive samples on a 1-8 and then 9-16 alternating basis. This is certainly not ideal, but it was what we could pull off with reasonable results given the desire to ship products.
In this case, if it is the first data packet, I don't have anything in the boardChannelDataInt array to copy to the lastBoardChannelDataInt array. So the very first data packet that is read from the ADS is used to sort of seed the system, if you will.
So I've finally been able to try this out. Got the FT232H USB connection working as Serial1 after making Joel's mods to the chipkit files suggested here:
OBCI.useAccel = true; // option to add/remove accelerometer data to stream
OBCI.useAux = false; // option to add/remove auxiliary data to stream
}
Tested with Joel's recommendation of adding the following echo onto Serial1 of Serial0 input within the eventSerial() function after "char inChar = (char)Serial0.read();"
Serial1.write(inChar);
So that works, so we know the hardware is good and Serial1 is basically working at the software level. I also tested the capability of Serial1 to read input, which works.
Next I tested the COM# that Serial1 is associated with up to 460800, (including changing "Serial1.begin(115200)" to "Serial1.begin(460800)" and it passed that test.
Next I wanted to stream all data over Serial1, and as suggested by @wjcroft above, the easiest thing to try seemed to be just replacing "Serial0" with "Serial1" in all code. I set the baud back to 115200, in case that might create an issue. I searched for all instances of "Serial0" in the OpenBCI_32_Daisy library and in the .ino, replacing them with "Serial1". Im not having success with the system running, though. I get the load-up message:
no daisy attached!
OpenBCI V3 16 channel
On Board ADS1299 Device ID: 0x3E
On Daisy ADS1299 Device ID: 0x3E
LIS3DH Device ID: 0x33
$$$
And then it seems frozen. No commands produce an output.
To troubleshoot, I checked for what I could find regarding serial ports in the chipkit core and OpenBCI board def files. There are some mentions there, but it seems nearly symmetric wrt Serial1, and no changes suggested themselves.
From what I understand, the Rfduino creates/modifies packets in certain ways before transmitting, and that could be the issue. But doesn't the dongle radio undo these modifications? I have very little understanding of how data travels over Serial1 by default, vs how it arrives over Serial0 post Rfduino. If anyone could sketch out what is going on, or point out where the relevant code is that does that packaging, I'd be grateful.
Earlier we talked about modifying Momen's 8-bit-board code, which transmits data over an auxiliary bluetooth hardware, while continuing to use the Rfduino for control commands. This is a different style solution, which simply uses the bluetooth to stream the EEG data. Momen's code has no special packet creation that I can see. For data transmission, they use the SoftwareSerial library and send their data in the main loop() after the default OBCI.sendChannelData(sampleCounter) via:
for(int i=0;i<24;i++){
mySerial.write(OBCI.ads.bit24ChannelData[i]);
}
mySerial.write("-|-");
The ads.bit24ChannelData member of OpenBCI doesn't exist anymore in the 32-bit boards. Im guessing it's been replaced by boardChannelDataRaw. In any case, I don't understand how to have OBCI's software, for me just the Python code, interact with that stream productively.
So basically, Im just looking for the middleware or packet code that I need to write/change to get my Serial1 picked up by OpenBCI's existing Python code. Any help is greatly appreciated!
Hmm, on further contemplation of the interaction between Joel's variants/openbci #define changes and the mapPps() calls -- what broke the SPI was when the mapPps interacted with the previous pin default pin definitions in variants/openbci. Now that those are patched, the mapPps() calls you were using SHOULD be simply redundant, not needed. Since the pins now default correctly. But... we don't know for sure. In any case mapPps() calls are now no longer needed. I do assume you commented out the pinMode() calls Joel suggested.
My understanding was that the RFduino added a checksum byte, which the dongle then removes after the packet checks ok. So you don't need this. But I then believe the over-the-air packets don't have a header / trailer byte. These were added by the dongle receive code before passing to the COM port.
My guess is that the header/trailer ARE passed on the Serial0 link from the chipKIT to the RFduino. Because it needs those to delimit the packet boundaries. The mainboard RFduino then likely removes them for packet transmission (since the radio link does it's own framing).
The additional manipulation of removing / adding header / trailer / checksum bytes is something done between the two RFduinos. So may be transparent as far as what you need to send over Serial1. These are just my assumptions not delving into the chipKIT or RFduino codes.
I think you are currently using yj's code base because it had the changes for different sample rates and high speed SDcard output. But as you found, the daisy is broken in that version. Another tack is just to use the current OpenBCI Github 32-bit source files. Then do your Serial1 changes there. You can tweek the default sample rate in the appropriate section once you get it running at the original 125 sps. Yj's mods had to do some amount of juggling to get the high speed SDcard output running with no hiccups. This is because there was some interaction / interference between SDcard and the ADS chips. But with the Serial1 output link, you don't really have any similar timing constraints.
OK, here's one more "fine point" of the interaction between the two RFduinos. This time on the command characters sent from the laptop. Each command character sent must be "sandwiched" between plus signs. This is a trick to avoid noise on the incoming radio link. See,
So it could be that your code is already working. You just need to add the pluses. On the other hand you could mod the mainboard protocol so it just no longer uses the sandwich protocol for your Serial1 link, since that should have no noise on it.
@wjcroft, thanks for all the tips! So I'm not sure what I changed, but it's not frozen anymore.
Re: The mapPps calls - Yes they appear to be redundant, and can be dropped. They weren't causing a problem either though.
Re: the .ino file that I'm working off of - I did play around with yj's, but I realized I had better figure out how to get full transmission working over the wired USB prior to worrying about changing the sample rate. So I took Joel's SD_only .ino and used that as the template to change all "Serial0"--> "Serial1". I also switched to an 8 channel board to avoid any issues having to do with the daisy.
Re: burger protocol ('+' sandwiching) - Yes this is definitely an issue. Leaving it in place, I can send commands over the USB COM via the Arduino IDE Serial Monitor, as long as I burgerify them. E.g. "D" produces no response, while "+D+" produces "060110$$$". So I figured I could just remove it, and at least the commands would work unburgerified. This works! To remove the burger protocol, I changed eventSerial() to:
void eventSerial(){
while(Serial1.available()){
char inChar = (char)Serial1.read();
//below is in lieu of the burger protocol
testChar = inChar;
if(getChannelSettings){ // if we just got an 'x' expect channel setting parameters
loadChannelSettings(testChar); // go get em!
}else if(getLeadOffSettings){ // if we just got a 'z' expect lead-off setting parameters
loadLeadOffSettings(testChar); // go get em!
}else{
getCommand(testChar); // decode the command
}
}
}
Next I moved to testing it with the OpenBCI Python code, which is what I am ultimately after. The board loads just fine, and accepts and executes (unburgerified) commands. However, something goes wrong when /start is issued. Quite possibly the packeting (which I haven't done any modifications to) is the issue. The error message is:
--> Warning: Skipped 1677 bytes before start found
Warning: ID:<56> <Unexpected END_BYTE found <57> instead of <192>
Warning: Skipped 1889 bytes before start found
Warning: ID:<206> <Unexpected END_BYTE found <245> instead of <192>
Warning: Skipped 2537 bytes before start found
Warning: ID:<22> <Unexpected END_BYTE found <14> instead of <192>
Warning: Skipped 2886 bytes before start found
Warning: ID:<0> <Unexpected END_BYTE found <0> instead of <192>
Exception in thread Thread-1:
Traceback (most recent call last):
File "C:\Python27\lib\threading.py", line 801, in __bootstrap_inner
self.run()
File "C:\Python27\lib\threading.py", line 754, in run
self.__target(*self.__args, **self.__kwargs)
File "C:\Users\Winslow\PAN GDrive\PAN Shared\software\Python\OpenBCI_Python-master\open_bci_v3.py", line 163, in start_streaming
call(sample)
File "C:\Users\Winslow\PAN GDrive\PAN Shared\software\Python\OpenBCI_Python-master\plugins\streamer_lsl.py", line 40, in __call__
self.outlet_eeg.push_sample(sample.channel_data)
The issue occurs in the class file: open_bci_v3.py when streaming when
sample = self._read_serial_binary()
is acted on by
call(sample)
Near that in the code there's the packet format explanation:
""" PARSER: Parses incoming data packet into OpenBCISample. Incoming Packet Structure: Start Byte(1)|Sample ID(1)|Channel Data(24)|Aux Data(6)|End Byte(1) 0xA0|0-255|8, 3-byte signed ints|3 2-byte signed ints|0xC0
"""
So Im guessing that's the issue. I don't know where in the OpenBCI code the packets are formatted though. I thought to trace through OBCI.sendChannelData() within loop() of the .ino. The OBCI object is from class OpenBCI_32_Daisy, which is in the corresponding library file. The relevant code from the sendChannelData method is:
Serial1.write(sampleCounter); // 1 byte
ADS_writeChannelData(); // 24 bytes
sampleCounter++;
The relevant code from the ADS_writeChannelData() method in the 8-channel case is:
So there's no obvious packet formatting occurring there.
As another test, I tried running over Serial1 in the OBCI Processing GUI. It runs and accumulates Byte Count, but bit rate is always 0, and no data appears (signal is 0.0 at all times). In the data file produced, data does accumulate, but extremely slowly. E.g. running for a few minutes I got 2 lines of data, and the sample counters aren't continuous:
%OpenBCI Raw EEG Data
%
%Sample Rate = 250.0 Hz
%First Column = SampleIndex
%Other Columns = EEG data in microvolts followed by Accel Data (in G) interleaved with Aux Data
Wondering if @biomurph knows if circumventing the rfduino by using a USB wired connection over Serial1 should require any code modifications beyond replacing all "Serial0" with "Serial1" in OpenBCI_32bit.ino and the corresponding library files, of which only OpenBCI_32_Daisy.cpp contains Serial0.
Here's what I suggest: use a hex dump program to look at the two raw data files. That is, the normal working OpenBCI stream, versus the one coming in over the wired link. You will likely see some difference in the packet formats in the header or trailer byte, or the packet counter, etc. This will give you a clue where to look in the chipKIT code to correct that.
On Unix / Linux, the command used is "od" to hex dump files. There are equivalent programs on Windows.
The relevant code from the sendChannelData method is: Serial1.write(sampleCounter); // 1 byte ADS_writeChannelData(); // 24 bytes sampleCounter++;
It seems likely that the RFduino packet-izing code is timer driven. In other words the samples are pumped out by the chipKIT code on Serial0. Then after buffering for a period of time, the RFduino sends those out as previously described. (Adding a checksum byte.) The dongle RFduino then removes the checksum byte and prepends appends the header trailer.
So it looks like all you need to do is bracket the above code snippet with header / trailer bytes, and you should be all set.
Great suggestion! I rewrote the relevant sendChannelData method as:
Serial1.write(0xA0); // attempt to manually prepend the packet header
Serial1.write(sampleCounter); // 1 byte
ADS_writeChannelData(); // 24 bytes
...
<aux and accel code here>
...
Serial1.write(0xC0); //attempt to manually append the packet footer
sampleCounter++;
Now both the OpenBCI processing GUI and Python code run and stream what looks like data. There's definitely still something slightly amiss, as at seeming random intervals of about average time of ~5s, I get the Warning messages from Python:
--> /start
Warning: Skipped 124 bytes before start found //Normal
--> Warning: ID:<50> <Unexpected END_BYTE found <38> instead of <192>
Warning: Skipped 15 bytes before start found
Warning: ID:<153> <Unexpected END_BYTE found <255> instead of <192>
Warning: Skipped 27 bytes before start found
Warning: ID:<147> <Unexpected END_BYTE found <255> instead of <192>
Warning: Skipped 30 bytes before start found
Warning: ID:<117> <Unexpected END_BYTE found <255> instead of <192>
Warning: Skipped 30 bytes before start found
Warning: ID:<232> <Unexpected END_BYTE found <160> instead of <192>
Warning: Skipped 31 bytes before start found
Warning: ID:<64> <Unexpected END_BYTE found <65> instead of <192>
Warning: Skipped 35 bytes before start found
Warning: ID:<34> <Unexpected END_BYTE found <127> instead of <192>
Warning: Skipped 34 bytes before start found
Warning: ID:<174> <Unexpected END_BYTE found <141> instead of <192>
Warning: Skipped 15 bytes before start found
Warning: ID:<52> <Unexpected END_BYTE found <0> instead of <192>
Warning: Skipped 5 bytes before start found
Warning: ID:<163> <Unexpected END_BYTE found <127> instead of <192>
Warning: Skipped 31 bytes before start found
Warning: ID:<145> <Unexpected END_BYTE found <255> instead of <192>
Warning: Skipped 33 bytes before start found
It seems too irregular to be explained by a buffer flushing time interval. It's looking for 192, which is the postfix packet footer, 0xC0 in hex. Maybe those checksum bytes are important, even for the wired USB? Could packets be being dropped over the USB wired connection? Or could the line pickup noise, corrupting data occasionally? I tried putting the isolator on, and adjusting the distance of the board from my computer, but that didnt seem to make much of a difference. Not sure what else it might be. I can try the hex file analysis of the same data sent as originally coded over Serial0 and then also over Serial1 to see the differences.
Try upping the speed to the 460800 bps. The 115200 may be too close to the edge as far as the amount of data being pushed. Remember, internally the chipKIT code was previously NOT sending header / footer bytes, and now you are. You could calculate this out, knowing the bytes on the wire are 10 bits, not 8.
> Maybe those checksum bytes are important, even for the wired USB?
No.
> Could packets be being dropped over the USB wired connection?
No, USB is already has link level error correction. As long as your cable is less than 15 feet or so, you should be fine.
> Or could the line pickup noise, corrupting data occasionally?
No.
> I tried putting the isolator on,
DO be sure to use the isolator before you connect to any heads! :-)
Hmm, well 33 bytes * 10 bit * 250 = 82500 bps. Should fit, shouldnt it? I thought the FTDI chip had a fairly deep FIFO, but let me check that. The USB cable length is non critical, but the small wires of your RX TX lines on the mainboard should be as short as possible, e.g. a few inches.
On the Windows COM port driver settings, be sure your Latency Timer is set to 1 millisecond, not 0 and not the default. The FTDI spec sheet (below) says the internal buffers are 1K in size, should be plenty, if they manage them correctly. Data bits settings, 8 bits, 1 stop, no parity.
Hmm, it's possible that the FT232H manages it's 1K internal receive buffer in a kind of "all or nothing" fashion. In other words, instead of a ring buffer or similar scheme that can keep receiving when the USB is busy sending to the laptop -- it might just have this ONE receive buffer that remains busy and unavailable if the USB transaction is underway. I would be surprised if they did it that way, but it's possible. If you look at their block diagram, the UART (connected to the RX pin) has it's own internal FIFO, not sure how big this is.
Another thing you could try is to change the Latency Timer to 2 or 3 ms. Each packet coming from the chipKIT is arriving at 4 ms intervals at 250 sps.
The FT232H also has "hardware flow control" pins. These are called RTS / CTS, request to send, clear to send. The RTS pin is low (0) when the FT232H is ready to receive more data. It will become 1 if the FT232H is busy with a USB transaction.
The V1 OpenBCI that was a shield on a regular Arduino board, interfaced over a serial COM port at 115200. Using an FTDI chip of some sort (FT232R?) I didnt think that required any hardware flow control.
---
Just found this post, which states that the 1K buffers ARE FIFO ring buffers, so should be able to handle your data rates without using flow control RTS pin.
I havent found any FTDI doc that states these are ring buffers, but they'd almost certainly have to be.
One other area of possible misalignment is in the baud rates chosen. the PIC processor (chipKIT) uses a clever scheme to get these "standard" baud rates such as the ones you see in the driver list. But the 115200 we know does work fine between the PIC and the RFduino. So that can't be the issue.
Another back of the envelope calculation. If the FT232H has a 1K ring buffer, how many 8 channel packets can be in there before it fills?
1024 / 33 = only 31 packets. And since they are coming out every 4 milliseconds (250 sps),
31 * 4 = 124 milliseconds worth of data before overflow.
One tenth of a second. That's not much of a window if the USB traffic happens to be a little sluggish. The Latency Timer setting here might well be a factor, if you increase it some (say to 2 or 4 or 8 ms), that means fewer and larger transactions on the usb bus.
One other thing I saw: FTDI has a newer device, the FT2232H. This has a 4K ring buffer. There are breakout boards available for this as well. It's a 2 channel device, so you would only need one. About the same pricing as the board you have.
It can also run at USB 2.0 High speed mode (480 Mbps), as contrasted with the FT232H which is limited at Full speed (12 Mbps). But since your isolator is only Full speed rated, the FT2232H will drop back to that speed.
Comments
Basically you're going to be going through similar steps to how Momen wired up his Bluetooth breakout board. But in your case you will be using usb vs wireless. Momen's instructions show the use of a "breadboard". However that adds to the bulk and fragility of the setup. Instead I suggest you mount the breakout as mentioned below on the mainboard with double stick foam tape.
If Jeffery still has the Sofia guys nearby doing various hardware projects in your "hackerspace" area, then those guys are great resources on how to do various microcontroller hookup steps such as soldering and using jumper wires. And feel free to continue posting here of course.
Connections:
A short usb cable from your laptop to the isolator; this could be as small as a foot or two. This cable uses the standard large usb connectors.
A longer usb cable goes from the isolator to the OpenBCI main board, where the FT232H is double stick foam tape mounted to the top of the mainboard; near the "chipKIT" or "OpenBCI" logo text would be fine. Stick the tape a few times to your hand skin to cut down the aggressiveness of the adhesive. This will make it easier to pull off the mainboard if needed. This cable is the mini-usb connector type.
The FT232H breakout comes with some header strips. I assume you have some short header pin jumper wires, with female sockets on each end. The wires here only need to be a couple inches long each. Easiest way to go is to solder in the header strip, you only need to use one of them, this is placed / soldered on the side with the holes labeled GND, D0, D1, etc.
https://learn.adafruit.com/adafruit-ft232h-breakout/wiring
There are two ways the long side of the pins can face: towards the top of the breakout board, or towards the bottom. Since you are double stick mounting this to the mainboard, it's best for the pins to come out on top. Be sure to follow the instructions as shown and trim the short side so that it is flush with the bottom of the board. Your foam tape will keep any conductors from contacting the mainboard.
Easiest way to solder, is to place BOTH pin header rows into a breadboard, then place the breakout on top of the short side pins, with the bottom of the board facing up. Now solder, remember you only need one row soldered. Other row is just holding everything level for your soldering step.
Now with your jumper wires you need to connect as shown here:
https://learn.adafruit.com/adafruit-ft232h-breakout/serial-uart
The TX (D0) on the breakout goes to RX on the mainboard. Use the same RX pin that Momen used.
The RX (D1) on the breakout goes to TX on the mainboard. Use the same TX pin that Momen used.
The GND on the breakout goes to GND on the mainboard.
All your mainboard pins are in the lower right corner in headers marked J3 or J4.
Do NOT connect anything to the 5V pin!
As the Adafruit tutorial points out, the breakout board powers up in Serial UART mode. None of the other fancy features of the FTDI chip need to be used.
port driver) is 115200 bps. These are 10 bit bytes, 8 data bits, 1 start
and 1 stop bit. The FTDI serial chips also support 230400, 460800, and
921600. I would use the lowest one that can support your data stream.
Remember you need to configure the COM port on windows with the baud rate you want, and also adjust manually the FTDI device driver "Latency Timer" as you did with the OpenBCI COM port (1 millisecond).
This serial UART is much easier to connect than SPI and should give you enough speed.
You will be modifying the mainboard firmware as described earlier. With the power switch in PC position, operation will be with the dongle and radio link COM port. With switch in BLE position, the other COM port is used and the firmware code is sending/receiving from Serial1 not Serial0.
YOU are the one who will do these firmware mods, using Momen's code as a suggestion. There will be TWO code paths in the firmware, one doing IO on Serial0, the original code. And your new code doing IO on Serial1. Does that make sense? Momen's code outputed to BOTH Serial0 and Serial1. Your code will only output/input from one Serial port at a time, depending on position of the power switch.
In terms of Momen's mods, one way I always like to use, is to do a recursive diff of the original code tree and modified tree. This will usually show only a page or so of modified lines. Versus the total file sizes which could be large. There are various GUI diff programs that can do side by side listings comparisons. I've used WinMerge in the past.
Since Momen used the 8 bit board, it will be easiest to just take the ideas of what he has done, and transfer that over to your copy of the current OpenBCI_32bit code tree. Should be fairly straightforward; you'll be dropping his Bluetooth setup code. The previously mentioned string change, "Serial0" -> "Serial1" would go a long way towards the goal. That, and adding whatever header/footer bytes as needed.
As an intermediate simple test of your hardware and COM port setup, you could utilize a tiny uploaded chipKIT arduino program that just 'echos' the RX data onto TX. Using the serial terminal emulation program running on your laptop, built into the Arduino IDE app. Then what you type on the keyboard should be echoed onto your screen. This verifies the entire hardware / driver path from the COM port to the chipKIT and back. Also confirms your baud rate settings on chipKIT and laptop, which must match.
http://arduinobasics.blogspot.com/2012/07/arduino-basics-simple-arduino-serial.html
[Change "Serial" to "Serial1".]
http://www.avrfreaks.net/forum/ftdi-ft232h-4-megabaud-uart
As the speeds go higher and higher, especially over 1Mb/s, there can be noise that creeps into the TX / RX lines because they are not minimal length. Also the chipKIT UART and your firmware will likely be the limiting factor as the UART speed is increased. From what you've said about the 500 sps, I think 460800 will be plenty.
Here's a post on the chipKIT / PIC32MX max rates.
http://chipkit.net/forum/viewtopic.php?t=2707
From what I understand, the Rfduino creates/modifies packets in certain ways before transmitting, and that could be the issue. But doesn't the dongle radio undo these modifications? I have very little understanding of how data travels over Serial1 by default, vs how it arrives over Serial0 post Rfduino. If anyone could sketch out what is going on, or point out where the relevant code is that does that packaging, I'd be grateful.
If you re-read Joel's comment link,
http://openbci.com/forum/index.php?p=/discussion/comment/3934/#Comment_3934
He's saying to DROP, don't use the two mapPps() calls. This messes up the SPI interface with the ADS1299. All you needed to do was the mods in the
Documents/Arduino/hardware/chipkit-core/pic32/variants/openbci
file, that change the #defines. This by default should remap the pins with no mapPps needed.
Give that a try.
Cheers,
William
My understanding was that the RFduino added a checksum byte, which the dongle then removes after the packet checks ok. So you don't need this. But I then believe the over-the-air packets don't have a header / trailer byte. These were added by the dongle receive code before passing to the COM port.
My guess is that the header/trailer ARE passed on the Serial0 link from the chipKIT to the RFduino. Because it needs those to delimit the packet boundaries. The mainboard RFduino then likely removes them for packet transmission (since the radio link does it's own framing).
The additional manipulation of removing / adding header / trailer / checksum bytes is something done between the two RFduinos. So may be transparent as far as what you need to send over Serial1. These are just my assumptions not delving into the chipKIT or RFduino codes.
http://openbci.com/forum/index.php?p=/discussion/540/character-in-command-protocol
So it could be that your code is already working. You just need to add the pluses. On the other hand you could mod the mainboard protocol so it just no longer uses the sandwich protocol for your Serial1 link, since that should have no noise on it.
So Im guessing that's the issue. I don't know where in the OpenBCI code the packets are formatted though. I thought to trace through OBCI.sendChannelData() within loop() of the .ino. The OBCI object is from class OpenBCI_32_Daisy, which is in the corresponding library file. The relevant code from the sendChannelData method is:
Serial1.write(sampleCounter); // 1 byte
So there's no obvious packet formatting occurring there.
As another test, I tried running over Serial1 in the OBCI Processing GUI. It runs and accumulates Byte Count, but bit rate is always 0, and no data appears (signal is 0.0 at all times). In the data file produced, data does accumulate, but extremely slowly. E.g. running for a few minutes I got 2 lines of data, and the sample counters aren't continuous:
Serial1.write(sampleCounter); // 1 byte
ADS_writeChannelData(); // 24 bytes
sampleCounter++;
It seems likely that the RFduino packet-izing code is timer driven. In other words the samples are pumped out by the chipKIT code on Serial0. Then after buffering for a period of time, the RFduino sends those out as previously described. (Adding a checksum byte.) The dongle RFduino then removes the checksum byte and prepends appends the header trailer.
So it looks like all you need to do is bracket the above code snippet with header / trailer bytes, and you should be all set.
http://www.ftdichip.com/Support/FAQs.htm#HwGen3
---
Just found this post, which states that the 1K buffers ARE FIFO ring buffers, so should be able to handle your data rates without using flow control RTS pin.
http://electronics.stackexchange.com/questions/56127/is-the-ft232h-a-single-channel-version-of-the-ft2232h
I havent found any FTDI doc that states these are ring buffers, but they'd almost certainly have to be.
One other area of possible misalignment is in the baud rates chosen. the PIC processor (chipKIT) uses a clever scheme to get these "standard" baud rates such as the ones you see in the driver list. But the 115200 we know does work fine between the PIC and the RFduino. So that can't be the issue.
1024 / 33 = only 31 packets. And since they are coming out every 4 milliseconds (250 sps),
31 * 4 = 124 milliseconds worth of data before overflow.
One tenth of a second. That's not much of a window if the USB traffic happens to be a little sluggish. The Latency Timer setting here might well be a factor, if you increase it some (say to 2 or 4 or 8 ms), that means fewer and larger transactions on the usb bus.
One other thing I saw: FTDI has a newer device, the FT2232H. This has a 4K ring buffer. There are breakout boards available for this as well. It's a 2 channel device, so you would only need one. About the same pricing as the board you have.
https://www.google.com/search?q=FT2232H+breakout
It can also run at USB 2.0 High speed mode (480 Mbps), as contrasted with the FT232H which is limited at Full speed (12 Mbps). But since your isolator is only Full speed rated, the FT2232H will drop back to that speed.