Started by Nathan Zimmerberg on 19 JUL 2020
Authors Nathan Zimmerberg ([email protected])
Latest Revision: 07 AUG 2020
The main goal of the firmware is to:
- Setup a recording from the BNKChipV4_E100 with a specified framerate, reference electrode voltage(Vref), and number of frames.
- Run the recording. Generate the signals to drive the chip and analog to digital converters (ADC). Stream the data from the ADCs into an SD card.
- Send the final data to the attached computer via USB, along with any errors that occurred.
Micro controller - Teensy 4.1
Analog to digital converter - AD7866
100 electrode array chip - BNKChipV4_E100 vague paper
Digital to analog converter - DAC80501
During a recording, the following external signals change. Everything else on the board should be DC.
These are the two signals going into the BNKChip from the teensy 4.1.
CCLK is the clock, and CSCLK is a signal to start a new frame. CCLK clocks in CSCLK and clocks out the analog data on its falling edge.
Here is what the signals should look like (note: the teensy logic level is 3.3V and the chip logic level is 5V, so there is a logic level converter between them).
https://github.com/wramsdell/TriantaduoWS2811 is a project that I used as a working example that uses DMA and FlexIO to do high speed IO on a teensy 4. This library outputs data, while I am inputting data, but the main use of DMA and FlexIO are similar. The documentation below is also modeled on TriantaduoWS2811's readme.
The background tasks have an interface of global variables and functions.
double setupflexio(double freq)
: Setup flexIO at freq in Hz greater than 250.
returns the real frequency in Hz of reading a frame.
void closeflexio()
: Disable the flexIO.
void setupflexiodma()
: Setup DMA from FLEXIO2. Do this before calling setupflexio
Frame data struct.
struct Frame
{
/** The frame number(starting at 0). This increases at
the real framerate even if some frames are skipped.*/
uint32_t framenumber;
/** The raw data from the ADCs. framedata[0] is row 0, ADC1,
framedata[1] is row 0, ADC2 ...*/
uint32_t framedata[60];
uint32_t userdata0;
uint32_t userdata1;
uint32_t crc;
};
const uint32_t framefifo::buffersize
: Total number of frames that can be stored in the fifo.
uint32_t framefifo::framestoread()
: How many frames can be read till empty.
uint32_t framefifo::framestowrite()
: How many frames can be written till full with no overflow.
void framefifo::push(Frame frame)
: Push 1 frame to the the fifo, used by the ISR.
Frame framefifo::pop()
: Pop 1 frame from the the fifo.
volatile int32_t userdata0
: Userdata written to the frames in the ISR.
volatile int32_t userdata1
: Userdata written to the frames in the ISR.
const uint32_t framesize = 256;// frame size in bytes
volatile uint32_t framecount;
: Number of frames read, updated by dmaisr
volatile uint32_t skippedframes;
: Number of frames not written to framebuffer
because of overflow. Should be zero if all the data is correctly saved.
FlexIO is a collection of interconnected shift registers, timers, and pins in the teensy. It is described in detail in the processor reference manual
The FlexIO inputs the data from the six ADCs into six 32bit shift buffers and requests a DMA.
The FlexIO also outputs the clocks and syncs for the ADCs and chip.
The FlexIO is setup in double setupflexio(double freq)
in the flexiodmaisr
library.
This sets up the FlexIO at a requested frame rate freq
in Hz. It also returns the real frame rate used.
The DMA is setup by setupflexiodma()
in the flexiodmaisr
library.
The DMA is triggered every ADC read. It transfers the bit reversed shift buffers into a large (64 kB) circular buffer.
Every numframesinterrupt
frames the DMA transfers, dmaisr
is called.
This interrupt packs the raw frame data in the DMA circular buffer and puts it onto the frame circular buffer. It also checks if the frame circular buffer is full, and if it is, it turns on the blue LED, and skips the frames.
The most likely error to occur is a frame buffer overflow. This happens because the
frames are not being sent off chip fast enough, or there is some latency issue.
If this happens new frames will not be written to the buffer until it has more space. Also, the blue LED will light, and global skippedframes
will increase from zero.
For the flexIO, if the DMA doesn't read the shifter buffer fast enough, IMXRT_FLEXIO2_S.SHIFTERR
won't be 0x00 (this shouldn't ever be an issue).
SdFat by greiman from https://github.com/greiman/SdFat-beta is the SD card library I am using. It is included in the libraries
directory.
There is a DAC that sets the reference electrode voltage.
The RGB LED turns blue on if frames are skipped (probably because the SD card writing is too slow)
The RGB LED blinks red if there is a fatal error with the SD card or flexIO. If this happens power cycle the device.
The RGB LED green is on during a recording.
The serial protocol is command and response where the PC is the commander and the device is the responder.
All commands end with a newline.
The device will finish a response with "a\n"
when it is ready for a new command.
Sometimes the device will use with "\r\n"
instead of "\n"
in responses, but commands should just use "\n"
.
`"a\n"`
response:
`"a\n"`
d<voltage(V)>
example:
`"d0.743\n"`
response:
`"a\n"`
r<frame rate(Hz)>,<number of frame chunks(32 frames)>,<aux channel(1 or 2)>,<range(0 is 0V-2.5V and 1 is 0V-5V)>,<userdata0>,<userdata1>
example:
`"r40000.0,131072,2,1,-55,109\n"`
response:
real frame rate(Hz)
example:
`"40000.00\na\n"`
`"s\n"`
response:
<1 if recording and 0 if not recording>,<frame chunks saved>,<frames skipped>,<last saved frame(256 bytes of raw data)>
example:
`"1,115360,0,�S8......\na\n"`
This aborts the reading and closes the SD card file.
example:
`"e\n"`
response:
`"a\n"`
f<chunk id(starts at 0)>
example:
`"f100\n"`
response:
256*32 bytes of raw data and a new line and ack.
example:
`"fajknj.......\na\n"`
-
Follow the instructions on https://www.pjrc.com/teensy/td_download.html to install Arduino and Teensyduino
-
Clone or download this repo https://github.com/nhz2/BNK-E100-reader
-
Open Arduino preferences and set the Sketchbook location to the repo/firmware. For example, for me it is
/Users/nathan/GitHub/BNK-E100-reader/firmware
-
Open
blinkyRGB/blinkyRGB.ino
in the Arduino editor. -
In the Tools tab, set the board to "Teensy 4.1"
-
Connected the board with USB.
-
In the Tools tab, set the port to the one connected to the board.
-
Press the right arrow upload button in the top left of the window.
-
If everything is working the RGB led should blink red, green, and blue.
-
Open
main/main.ino
in the Arduino editor. -
Press the right arrow upload button in the top left of the window.
-
Open the serial monitor (the button in the top right of the window).
-
Test sending
a
with newline after every command and make sure you recieve ana
in response. -
Close the serial monitor.
-
Now the firmware is installed.