SD-only version for increased sample rate and interrupts
Hi everybody!
The question of "increase the sample rate" is repeatedly raised on the forum.
The answer is both "Simple" and "Complex"... (But not that much...)
A version who allows it can be found at:
https://github.com/yj-xxxiii/OpenBCI_2kHz
You can use it "as it is" or examine the source code.
This said Joel Murphy (Biomurph) and PushTheWorld are preparing a much improved upgrade release which will rely on interrupts, see there under:
https://github.com/biomurph/OpenBCI_32_Interrupt
Awaiting for this future version you can use and look at this one. Some new added commands are commented in the readme of GitHub.
At 250Hz , it can be used with the "Processing's OBCI_ GUI" but to record at higher sample rates on a SD you should use the Arduino "Serial Monitor". (Reset the card before...)
On the following picture (that I coloured) you can see :
- in green the message sent by the card when you power it.
- in blue some commands (chars have to be sent one by one and each char is sent back)
- in red the card answers to the commands... (Dont wory, there was no SD Card in it...)
It is not clean, some "CRLF" could be added... But it works more or less...

"Taille max des fichiers" means : maximum size of the files.
Have fun and give me your impressions or ideas , if you try it,
y.j.
The question of "increase the sample rate" is repeatedly raised on the forum.
The answer is both "Simple" and "Complex"... (But not that much...)
A version who allows it can be found at:
https://github.com/yj-xxxiii/OpenBCI_2kHz
You can use it "as it is" or examine the source code.
This said Joel Murphy (Biomurph) and PushTheWorld are preparing a much improved upgrade release which will rely on interrupts, see there under:
https://github.com/biomurph/OpenBCI_32_Interrupt
At 250Hz , it can be used with the "Processing's OBCI_ GUI" but to record at higher sample rates on a SD you should use the Arduino "Serial Monitor". (Reset the card before...)
On the following picture (that I coloured) you can see :
- in green the message sent by the card when you power it.
- in blue some commands (chars have to be sent one by one and each char is sent back)
- in red the card answers to the commands... (Dont wory, there was no SD Card in it...)
It is not clean, some "CRLF" could be added... But it works more or less...

"Taille max des fichiers" means : maximum size of the files.
Have fun and give me your impressions or ideas , if you try it,
y.j.
Comments
Yes, sorry I do not have and use the daisy board.
The code does nearly nothing in case of a present Daisy.
It's already a chance that it does not completly crashes...
Your hardware is OK, that's sure...
Do you obtain flat lines by air (blue tooth) or from SD ? (or both?)
I can have a look to the code, there is probably not a lot to modify...
But currently we use all our cards (6 stations) to record mice 23h/24h
and as a consequence I could not take one of them to debug my attempt to
correct the code. (I am a very bad programmer, it never works on the
first try...).
From memory I think that I read the Daisy_1299 but
I do not push in the circular buffer these data and of coarse I dont
retreive (pop) them . I steadfastly ignores the daisy board (joke)
I dont remember..., I will have a look if you wish to record 16 channels on the SD .
2kHz sampling rate works with 8 channels but with 16 no more than 1kHz.
I tried 4kHz/8channels, it does not crashes but it is full of overruns...
Tell me if...
Y.J.
I had a glance to the code,
my memory is bad ,
the code does more than I wrote in the previous post...
I need a time for calm reflection...
y.j.
I am not sure but try (Sorry , currently I have no available card to test these suggestion modifs) :
1) To not to ignore the Daisy_Board (at least this should be done )
In the function void OpenBCI_32_Daisy::startADS(void)
replace WREG(CONFIG1,0x90 + Sample_Rate,BOARD_ADS);
by WREG(CONFIG1,0x90 + (daisyPresent? 0xB0-0x90:0) + Sample_Rate,BOARD_ADS);
It might be not enough... a bug hides another bug
2) To synchronize the ADS1299 means, in the two update functions
- OpenBCI_32_Daisy::updateBoardData()
replace twice daisyPresent by ! firstDataPacket
comment or delete the last line : if(firstDataPacket == true) firstDataPacket = false;
- Do the same modifs in OpenBCI_32_Daisy::updateDaisyData()
Add the test of ! firstDataPacket ( I supresssed it )
To toggle firstDataPacket replace the commented line by :
firstDataPacket = ! firstDataPacket ;
It might be something like that, be careful I am ofen "absent-minded"...
@biomurph,
// if daisyPresent tell on-board ADS to output its clk, set the data rate to Sample_Rate
I do not understand what determines the sample rate of the Daisy_1299.
Is it the clock it receives from the Board_1299 ?
if not , what should we do/write ?
y.j.
I imagined/(wondered if) , that this "clock" signal could be "sample rate" dependent and could have forced the Daisy_ADS to follow the rate and sync...
So we must write as I already wrote and asked to Winslow_Strong :
WREG(CONFIG1 , 0x90 + SampleRate , DAISY_ADS )
WREG(CONFIG1 , 0xB0 + SampleRate , BOARD_ADS )
isn't ? (I can't test since I do not have a daisy )
y.j.
I
used Ardunio 1.6.5 on MacOS 10.11.5. I've copied the folder libraries
from https://github.com/yj-xxxiii/OpenBCI_2kHz to the folder Ardunio. I
Upload OpenBCI_32bit_SD_Only.ino on my OpenBCI Board. I do not use the
Daisy board (I only use 8 channels). I can not send any commands to the
board OpenBCI from Serial Monitor.
Please help. I just want to see the EEG signal in the frequency 2KHz, just 2 channels is good enough.
You must send the chars one by one.
'.' send
"2" send
I see that you wrote ".2" in the input window.
If you want to send the string ".2" then write +.++2+ and send.
(I use windows XP...)
What do you mean by "see the 2kHz"?
You will not "see" the 2kHz it has to be recorded on the SD card...
the 250 Hz can be seen... with the processing GUI.
Sincerely,
y.j.
Do not fret because of my stupidity. I first used the Arduino. I want to record 1-minute to SD card with Sample Rate 500Hz, I need to write these commands? Please help me. Thanks a lot.
Yes , you have to write that
and to send an "N" command to start recording.
The file FI_7204.bin will be a binary file...
To get a *.txt file, more readable , send a single 'B' , it toggles .bin / .txt
y.j.
Is it already "officially/stable" ? Should I use the "biomurph" or "yj-xxiii" ?
So, how can I do this to record 7 channels at 500Hz? (windows 7)
Is there any way to sync the start of the recording with a trigger from the PC?
Thanks in advance.
If you need 500Hz and accept to record on the SD only using the command 'N' then upload the yj-xxxiii.
Else use Winslow_Strong version but you will have to build a hardware link.
Can you describe a bit what you want to do?
(If your program can send the 'N' on the serial line, then you will trigger the start of the recording...)
y.j.
A person is looking to a PC monitor as it will show some stimulus (images or video) and I would like to sync the presentation of the stimulus with the recording.
I mean, I want to be able to know in the OpenBCI file when the stimulus was presented, so that I can analyze what happens right after and compare the before/after state of mind.
I think 500Hz would be enough, but what is the highest sampling rate you can get without problems (overruns?) ?
1)
2kHz is the highest sampling rate one can get without problems.
2)
If the sound track of the video is not already used, if you can associate some sounds to the images then you could use the sound card output of the P.C. to "trigger , mark , tag" a signal in the auxiliary field.
It can be wired through an optical isolator, see in the learning section of the OBCI web site.
It can be through an Infra Red burst sent by 940nm diodes plug in the sound card, to an IR receptor plugged in the OBCI Card. (like your TV remote control)
I am using this second way to do.
I'll give all details and code when it will be clean...
But in brief the principle:
- make a 40kHz wav sound (at least 20 periods burst ) synchronized with the video frame / image, to excite a 940 nm diode.
- Plug in the OBCI Card, an Infra Red burst receptor such as the 3 pins component TSOP34840 (ref Farnell: 1469638).
A little modification in the yj-xxxiii code will provide you a tag in the auxiliary data of the SD recording... (keeping 8 channels)
The output level of the sound card as to be around 2 volts rms in order to exite the 1.3 volts 940nm - IR diodes...
A few mA from this sound card are enough to transmit a signal at the distance of a few tenth of centimeters.
If the frequency output of the sound card cannot reach 40kHz , make an arround 20kHz sound (or 44.1/2 it is nicer and works) and use two "head to tail mounted" diodes to double the freq.
Note that the IR burst length must be longer than the sample period... (0.5 .. 4 mS, it can be shorter if you use the PIC32 interrupt to record IR receptor signal change)
y.j.
P.S. : Ask @PushTheWorld to know if the new "Sync Command" can do the job (I did not understood what this command does, but it "sounds nice").
Its a fact that I never went back from my code to the previous initial version...
Your hypothesis is good, it could be because I used differently the EEPROM...
The basic code (there under in blue) supposes that
variables fileOnes and fileTens are inside 0..9 or A..F, or equal to 0xff.
It is probably not the case if you played with my code.
Rewrite the following line in order to check if it is inside 0..9 or A..F, or equal to 0xff, (I agree that it is much more longer...)
// if it's the first time writing to EEPROM, seed the file number to '00'
if( fileTens == 0xFF | fileOnes == 0xFF ) { fileTens = fileOnes = '0'; }
and see if the createContiguous function is OK.
I am nearly sure that you already tried it...
y.j.
void incrementFileCounter(){
fileTens = EEPROM.read(0);
fileOnes = EEPROM.read(1);
// if it's the first time writing to EEPROM, seed the file number to '00'
if(fileTens == 0xFF | fileOnes == 0xFF){
fileTens = fileOnes = '0';
}
fileOnes++; // increment the file name
if (fileOnes == ':'){fileOnes = 'A';}
if (fileOnes > 'F'){
fileOnes = '0'; // hexify
fileTens++;
if(fileTens == ':'){fileTens = 'A';}
if(fileTens > 'F'){fileTens = '0';fileOnes = '1';}
}