I was thinking it would be cool to construct a short-to-moderate audio delay, sort of similar to a PT2399, but with an Arduino to get some extra features not available with the PT2399.
So a feature set would be something like:
-1-bit delta sigma ADC (perhaps a dedicated, separate IC codec for this part)
-approximately 44kbits (not bytes!) shift register for the audio delay, with the clock-through rate externally variable (via pot or tap-tempo depending on how much memory is available)
-for chorus/flanger/doubling effects you could split this register into smaller chunks and clock data through at an LFO-modulated rate
-PWM output, external filtering back to analog.
...But, I don't have a feel for how much of this could be done inside an Arduino (let's say for example using an ATmega328, with ~30kB available space)... for instance, would this require external RAM to hold everything?
Quote from: earthtonesaudio on December 05, 2011, 09:16:04 AM
I was thinking it would be cool to construct a short-to-moderate audio delay, sort of similar to a PT2399, but with an Arduino to get some extra features not available with the PT2399.
So a feature set would be something like:
-1-bit delta sigma ADC (perhaps a dedicated, separate IC codec for this part)
-approximately 44kbits (not bytes!) shift register for the audio delay, with the clock-through rate externally variable (via pot or tap-tempo depending on how much memory is available)
-for chorus/flanger/doubling effects you could split this register into smaller chunks and clock data through at an LFO-modulated rate
-PWM output, external filtering back to analog.
...But, I don't have a feel for how much of this could be done inside an Arduino (let's say for example using an ATmega328, with ~30kB available space)... for instance, would this require external RAM to hold everything?
On the 328, that 30kb is program memory, not RAM; even if you could read/write it quickly enough, the write cycles would run out in minutes.
Good point, I was not sure about that. In that case it would need to be an external RAM.
SPI serial RAM seems like the way to go for this application... cheap, fast enough, and big enough. I can buy one of these (http://ww1.microchip.com/downloads/en/DeviceDoc/22126E.pdf) for $0.86 from Digikey.
What I don't understand is what the latency would be for simply using the RAM as a large FIFO. If possible I would like to get audio delays as short as 50ns for through-zero flanging effects, so I suspect the microcontroller latency will be the limiting factor.
64kb ram ... Get more , i don't think it's enough ...
The PT2399 contains 44kbits, which is 5.5kB, which means you could fit eleven PT2399's worth of delay into 64kB. The PT2399 can do 300ms fairly clean, so with 64kB of RAM that would be equivalent to 3.3 seconds of clean delay.
Quote from: earthtonesaudio on December 05, 2011, 01:12:36 PM
The PT2399 contains 44kbits, which is 5.5kB, which means you could fit eleven PT2399's worth of delay into 64kB. The PT2399 can do 300ms fairly clean, so with 64kB of RAM that would be equivalent to 3.3 seconds of clean delay.
Close enough .
ive had a project like that on my back burner for way too long now
the fastest you can get data in and out of an arduino
is using the SPI interface at 8Mbits/second
and thats assuming no interrupt handling latency
so thats 125ns min audio latency
although since things have to be handled bytewise
maybe its really 1us latency
i decided to use standard parallel dram
since its pretty innexpensive and fast and has a lot of space
and the arduino wouldnt handle any of the data
it only controlled the indexing of the dram
ill have another look at the serial sram chips
but i seem to recall having to clock in a byte that represented the desire to write
followed by the address you wanted to write to
and then the data at that segment
and if you wanted to read data back out
you had to go through the same process
so it was going to take forever
Thanks guest, having some actual numbers to look at is very helpful.
The SRAM I linked to (23x640) was chosen arbitararily; I just searched Digikey for SPI RAM and sorted for cheap and in-stock. But looking closer at the datasheet, it has a "sequential mode" which automatically increments its internal address register, so you only have to tell it to write once, then you can fill the array (and overwrite) in order by simply clocking in data. Reading can be done sequentially as well.
Being a hardware guy, this immediately makes me think to use two identical SRAMs; one writing while the other is reading and vice versa. So the Arduino would say to one chip "read sequentially" and to the other it would say "write sequentially" then after a little less than 64000 clock cycles it would give the opposite command. That would require 3 pins from the Arduino (two data outputs and one clock output) and you could simply OR the SRAM outputs together.
With two SRAM chips, I *think* the operations could be overlapped such that there was no break in the data output stream, but I'm not completely sure.
I'm not completely against the parallel DRAM idea but the chips are much larger and seem to require more AVR pins to operate them.
i like the idea of dual serial sram chips
those chips tend to be pretty cheap and small
im still a bit concerned about using the arduino
to sample the data coming from the sigmadelta
there is a 1.5 clock cycle setup time on the inputs to avr chips
so you need to wait around 2 clock cycles before sampling inputs
just to be sure the state is what it says it is
so this will incure a bit more delay
im also not sure how the variable clock rate will be implemented
will the arduino be clocked externally as well?
Here is what I was picturing:
-Arduino gets its clock signal normally, from a 16MHz crystal or what have you.
-Internally it generates an "effect clock" which is variable according to how it is programmed. The speed of this clock would necessarily be slower than the Arduino's crystal. I'm not sure what a reasonable speed is for an Arduino-generated signal. Maybe 1MHz? Please correct me if this assumption is off.
-The Delta-Sigma ADC runs off the "fast" 16MHz crystal clock source, but the Arduino has setup and hold requirements. No problem! If you think about it this means that the Arduino acts as the decimation filter for the ADC, thereby improving its signal-noise ratio. In fact it might even be preferable to sample the inputs less frequently than the Arduino's maximum rate.
This is about as much as I have thought it through so far. I don't yet have an Arduino but I'm expecting to get a Nano from Santa this year. :)
Consider that the PT2399 chip, as to the datasheet, is runnign at 2Mhz for 300ms, but can go up to 20M for shorter times...
Also, i dont know exactly how many Clock cycles takes up to execute one instruction in the AVR (for PICs it takes 4). Seems like its a 1:1, so optimistically it'll be 16Mips. A 1-bit sampling at 2Mhz means you've got only 8 instruction cycles to get everything done before the next sampling takes place... Thats a very tight margin
That's an interesting point about the number of instruction cycles, Carlos.
From the PT2399 datasheet's tables of clock frequency and delay times (together with 44kbits of memory):
The equation [fck(clock cycles/second) * td(delay time in seconds) / 44kbits] will give us the number of clock cycles that go by while a bit of data is stored in a particular location. From the table I get a number around 15.5 so it seems reasonable to conclude that the PT2399 takes about 16 clock cycles to move an *average* bit from its current address to its next address.
With the two-SRAM setup I am imagining, the time-critical instructions would be relatively few and far between. For instance each time you alternate SRAM chips, you need to send that chip an 8-bit instruction and a 16-bit address to tell it where to start reading/writing from.
Maybe it can be simplified enough to make the margin more relaxed somehow...
the arduino is essentially 1 clock per instruction
a few things take 2
like multiplies and data fetches from internal memory
if the adc is getting clocked at 16mhz
but is only being sampled at 1mhz
is the data getting buffered between them?
or do you just lose those other 15 bits?
is it the variation of the internal clock runing at 1mhz
that will cause the flanger effects and whatnot?
or will variable delay data fetches get used?
if its variations in the internal clock
that will be a bit choppy
as you can only divide by integer factors
also be aware that there is a lot of overhead in the arduino language
so things dont move as fast you think they should
Hi again, had to do some serious reading and come back to this topic.
I originally thought that simply sampling the ADC output at a lower rate is equivalent to decimation. Now I think they are not quite the same thing. Still, sampling at 1MHz is 50x oversampling for 20kHz audio. Guitar generally has very little info above 10kHz so I think 1MHz sampling is sufficient. Whether the ADC is clocked at 1MHz or just sampled at 1MHz seems to not matter very much in my mind.
It seems to me there are two main ways to get a variable delay time using two RAMs. One way would be to vary the clock frequency. Another would be to use a fixed clock frequency but use a variable amount of the available RAM. For example write 1000 bits and then switch to the other RAM. It seems like the second method would be less resource-intensive.
Quote from: earthtonesaudio on December 12, 2011, 03:28:22 PM
It seems to me there are two main ways to get a variable delay time using two RAMs. One way would be to vary the clock frequency. Another would be to use a fixed clock frequency but use a variable amount of the available RAM. For example write 1000 bits and then switch to the other RAM. It seems like the second method would be less resource-intensive.
or some kind of ring buffer... one index writes, and other reads, how far they are apart is the delay time (at a constant clock)... very similar to magnetic tape heads.
Exactly. Then to implement a variable delay time you would need a variable-length timer.
varying the clock speed has 2 advantages
first its easier to do
you just vary the clock
and second it smoothly transitions between delay times
but it also has two downsides
it can be tricky to vary a microcontroller clock
without glitching the microcontroller
and it also reduces the effective oversampling rate
as you go to longer delay times
i was having a lot of trouble
getting smooth delay time variations
with the variable buffer size implementation
i got all this digital noise when i skipped samples
to move to the new buffer point
i have a chart i put together a while back
comparing oversmampling rate with bit depth
for doing this sort of 1bit sampling
if i can dig it up ill post it
Quote from: earthtonesaudio on December 12, 2011, 03:28:22 PM
Whether the ADC is clocked at 1MHz or just sampled at 1MHz seems to not matter very much in my mind.
There are two important facts if you a planning to use atmega328 for experiments:
1. The ADC converters are not 1bit Sigma-Delta, but 10bit successive approximation.
2. The max clock you can use for ADC at 10bit resolution is about 200kHz. It can go higher if you reduce the bit resolution.
Let's say the ADC is clocked at 200kHz, it doesn't mean that the sampling frequency will be the same value. The adc conversion process is split in two parts: sample&hold and conversion. Both use a multiple ADC clock cycles to complete. Take a look at the datasheet:
http://www.atmel.com/dyn/resources/prod_documents/doc8161.pdf
page 253
to see how the ADC module on Atmega operates.
Usually you'd need to set up a timer to trigger an interrupt at the required conversion frequency (f.e. 32kHz) and do all the process (sampling, storing in RAM, reading from RAM, sending to DAC) in the interrupt subroutine.
QuoteIt seems to me there are two main ways to get a variable delay time using two RAMs. One way would be to vary the clock frequency. Another would be to use a fixed clock frequency but use a variable amount of the available RAM. For example write 1000 bits and then switch to the other RAM. It seems like the second method would be less resource-intensive.
The usual approach is the second method + the use of interpolation techniques to calculate the values that are between the samples to get a smooth delay time change.
Here's another nice board to play with DSP:
http://www.st.com/internet/evalboard/product/252419.jsp
I've bought it recently for about 16EUR. Not bad for an 32bit MCU with 1MB flash, 192kB RAM (!), intergrated DAC ond lots of other interesting stuff.
At the very beginning of this thread I was considering using the Arduino's ADC but quickly realized it was too limited and simply not the right tool for the job.
At this point, I think the Arduino would be just incrementing a (user-controllable) counter and sending the switch instructions to the two RAM chips at the appropriate intervals. The audio signal would be presented to the Arduino in already-digitized format. Technically the Arduino would not even have to touch the audio data except that seems like an easier way to multiplex the RAM inputs.
That ST chip looks awesome, but for me it would realistically cost $200+ due to my lack of Windows. For my budget, anything over $50 is a non-starter.
if you were considering doing the traditional ADC to DAC route
the leaflabs maple or maple native with 1MB of RAM is not too expensive
and can be programmed with the arduino environment
http://leaflabs.com/store/
or theres the codecshield i designed
http://www.openmusiclabs.com/projects/codec-shield/
but that doesnt get you much delay time
ultimately i think the sigmadelta delay has a far more interesting sound anyways
it starts going crazy when it gets clocked too slow
since you will have to process things pretty quickly inside the arduino
i would reccomend the following for your main loop
void loop() {
while(1) {
// your code here
}
}
there are a bunch of jumps inside the main loop that arduino does
and these take up a fair bit of time
putting the while(1) bypasses all that stuff
Cool tip, thanks!
i just remembered that that arduino has a built in comparator
so you can make the whole thing with just a resistor and capacitor
of course some input and output buffers would be nice too
i wrote up a quick test of this
its running at 2MHz sample rate
which is the fastest it can get through the loop
and its not storing anything to memory at the moment
but it wouldnt be too tough to use the internal memory
that would probably knock it down to 1MHz
heres the code if you want to try it
// 1 bit sigmadelta converter using arduino internal comparator
// there is a 2 clock cycle setup time on the comparator
//
// D5 = PD5 = digital output
// D6 = PD6 = AIN0 = comparator positive
// D7 = PD7 = AIN1 = comparator negative
void setup() {
DIDR1 = 0x03; // turn off digital inputs for analog comparator
ACSR = 0x00; // setup analog comparator
DDRD |= (1<<DDD5); // set PORTD5 as output
TIMSK0 = 0x00; // turn off delay timer to reduce jitter
}
void loop() {
while(1) { // speeds up loop time
byte input = ACSR & (1<<ACO); // get comparator data
if (input == (1<<ACO)) {
asm("nop"); // even up loop times
PORTD |= (1<<PORTD5);
}
else {
PORTD &= ~(1<<PORTD5);
}
}
}
im getting -60dB third harmonic distortion at 1khz
and this goes to -24dB at 5khz
but i think thats my capacitor being too big
im using a 10k resistor and 15nF capacitor for the filter
That is very cool, thank you for sharing. I'll try that as soon as I get a chance.
This thread is looking quite interesting. I can visualise a pretty decent sounding digital delay with tap tempo & based around a handful of chips. Could fit in a 1590b...
Now, didn't somebody come up with a micro controlled LFO too? Modulated delay anybody? Add some serious low pass filtering, maybe some companding & we've got a Carbon Copy clone that goes to 1s and beyond.
I'd contribute more if I had the time to do more than just think & read about stuff like this - keep it coming guys, its good brain fodder!
QuoteNow, didn't somebody come up with a micro controlled LFO too?
Yep. Electric Druid's Tap Tempo LFO, open source too (both functions, one chip?). http://www.electricdruid.net/index.php?page=projects.taplfo (http://www.electricdruid.net/index.php?page=projects.taplfo)
This project sounds interesting to me too, LFO madness only makes it sound more interesting.
Quote from: free electron on December 13, 2011, 04:06:31 AM
Quote from: earthtonesaudio on December 12, 2011, 03:28:22 PM
Whether the ADC is clocked at 1MHz or just sampled at 1MHz seems to not matter very much in my mind.
There are two important facts if you a planning to use atmega328 for experiments:
1. The ADC converters are not 1bit Sigma-Delta, but 10bit successive approximation.
2. The max clock you can use for ADC at 10bit resolution is about 200kHz. It can go higher if you reduce the bit resolution.
Let's say the ADC is clocked at 200kHz, it doesn't mean that the sampling frequency will be the same value. The adc conversion process is split in two parts: sample&hold and conversion. Both use a multiple ADC clock cycles to complete. Take a look at the datasheet:
http://www.atmel.com/dyn/resources/prod_documents/doc8161.pdf
page 253
to see how the ADC module on Atmega operates.
Usually you'd need to set up a timer to trigger an interrupt at the required conversion frequency (f.e. 32kHz) and do all the process (sampling, storing in RAM, reading from RAM, sending to DAC) in the interrupt subroutine.
QuoteIt seems to me there are two main ways to get a variable delay time using two RAMs. One way would be to vary the clock frequency. Another would be to use a fixed clock frequency but use a variable amount of the available RAM. For example write 1000 bits and then switch to the other RAM. It seems like the second method would be less resource-intensive.
The usual approach is the second method + the use of interpolation techniques to calculate the values that are between the samples to get a smooth delay time change.
Here's another nice board to play with DSP:
http://www.st.com/internet/evalboard/product/252419.jsp
I've bought it recently for about 16EUR. Not bad for an 32bit MCU with 1MB flash, 192kB RAM (!), intergrated DAC ond lots of other interesting stuff.
Man ... i bought the STM32F4-Discovery , thanks for the discovery , literally ! ( 20$ SGD )
It's cheaper then a arduino !
Just bumping this thread to say I got an Arduino Nano for Christmas, and I just ordered some memory chips. Since my current plan involves only partially filling the SRAM, 64k versus 256k makes no difference, so I went for the 256k. Perhaps I'll want more memory for something else in the future.
At the moment I'm a total Arduino Noob, so simply getting an LED to blink according to a program is a cause for celebration for me. :)
Man , guys ,
Which one should i get , 16Mbit SPI Flash ( faster and cheap but it's Flash . ) http://sg.element14.com/amic/a25l016-f/memory-flash-spi-16m-8dip/dp/1907083?in_merch=New%20Products (http://sg.element14.com/amic/a25l016-f/memory-flash-spi-16m-8dip/dp/1907083?in_merch=New%20Products)
or 256kb Serial SRAM http://sg.element14.com/microchip/23k256-i-p/ic-sram-serial-256k-2-7v-pdip8/dp/1695546 (http://sg.element14.com/microchip/23k256-i-p/ic-sram-serial-256k-2-7v-pdip8/dp/1695546)
The flash one is HUGE and has a lot of cool features, but it looks like it would need significantly more programming to get data in and out.
The 23k256 is exactly what I ordered, the main reason being the sequential r/w modes which would hopefully allow for simple programming.
Quote from: earthtonesaudio on December 28, 2011, 02:51:18 PM
The flash one is HUGE and has a lot of cool features, but it looks like it would need significantly more programming to get data in and out.
The 23k256 is exactly what I ordered, the main reason being the sequential r/w modes which would hopefully allow for simple programming.
I bet it would do me useful in the future if i order both eh . :icon_mrgreen:
Not a bad idea. 8)
nice christmas present
i was looking at the 23k256 datasheet
and it says it runs off 3.3V
so be careful when connecting it to the 5v arduino
you might need to put a level shifter or resistors
on the data out lines
also note that the 3.3v rail on the arduino nano
is only available when usb is plugged in
Yeah, thanks. That part (hardware) is the easy part for me. The part I'm struggling with now is figuring out how the physical pins connect to their names in the code you posted, and what the various commands do. I'm doing my homework though.
my code is not in the traditional arduino language
which makes it a bit confusing
but the arduino commands take too long to execute
its written in C for AVR
if you have any specific questions
feel free to ask
if youre good with hardware
then the best place to start is with the arduino nano schematic
and the atmega328p datasheet
they list all the register names in the datasheet
and you can just write to them by name
otherwise you can get something up and running with the arduino language
and then make it go faster by working on a bit at a time
Quote from: earthtonesaudio on December 28, 2011, 07:44:54 PM
Not a bad idea. 8)
Oh by the way , i found some EEPROM's that are cheaper then SRAM's ... What's the main difference between them ?
EEPROM is ROM, so it's good for holding programs but not suitable as RAM.
Quote from: earthtonesaudio on January 01, 2012, 10:05:39 AM
EEPROM is ROM, so it's good for holding programs but not suitable as RAM.
Forget it ... I found out DRAM is only SMD
Quote from: g_u_e_s_t on December 31, 2011, 03:10:32 AM
my code is not in the traditional arduino language
which makes it a bit confusing
but the arduino commands take too long to execute
its written in C for AVR
if you have any specific questions
feel free to ask
if youre good with hardware
then the best place to start is with the arduino nano schematic
and the atmega328p datasheet
they list all the register names in the datasheet
and you can just write to them by name
otherwise you can get something up and running with the arduino language
and then make it go faster by working on a bit at a time
Okay, sure! My first question: is there a resource for learning all those speed-up tricks for arduino?
I have been perusing the atmega328 data sheet, particularly going between your code and the register and instruction set summary pages, but I could not find some of the names you used, such as DDRD.
Also, could you explain why you used a compound bit wise or/and rather than a simple bit wise or/and?
Thanks again!
Quote from: DavenPaget on January 01, 2012, 10:08:32 AM
Quote from: earthtonesaudio on January 01, 2012, 10:05:39 AM
EEPROM is ROM, so it's good for holding programs but not suitable as RAM.
Forget it ... I found out DRAM is only SMD
there are dip dram
the 41256 for example
its 256k x 1bit
which is perfect for 1bit converters
jameco has good stock
Quote from: earthtonesaudio on January 01, 2012, 10:17:55 AM
Quote from: g_u_e_s_t on December 31, 2011, 03:10:32 AM
my code is not in the traditional arduino language
which makes it a bit confusing
but the arduino commands take too long to execute
its written in C for AVR
if you have any specific questions
feel free to ask
if youre good with hardware
then the best place to start is with the arduino nano schematic
and the atmega328p datasheet
they list all the register names in the datasheet
and you can just write to them by name
otherwise you can get something up and running with the arduino language
and then make it go faster by working on a bit at a time
Okay, sure! My first question: is there a resource for learning all those speed-up tricks for arduino?
I have been perusing the atmega328 data sheet, particularly going between your code and the register and instruction set summary pages, but I could not find some of the names you used, such as DDRD.
Also, could you explain why you used a compound bit wise or/and rather than a simple bit wise or/and?
Thanks again!
i dont think there is a single resource for arduino tricks
but writing in C is usually a good first step
and can save hundreds of clock cycles
i dont have a great reference for learning C
i picked it up by reading "Kernighan and Ritchie"
but i wouldnt really reccomend that
perhaps ask around at avrfreaks.net
so the register DDRD is the Data Direction Register for port D
you will probably find it in the datasheet listed as DDRx
as there is one for every port (DDRB, DDRC, etc)
there is also PORTC, PORTD for the port register and PIND, PINC for the pin registers
each pin can be acessed via PORTB1, or PINB1, etc
DDRx sets wether its an in or an out
PORTx sets an output to high or low
PINx reads an input to see if its high or low
so if you want to set PORTB1 as an output you could do it one of 3 ways
DDRD = 0x02; (or 0b00000010, or (1<<PORTB1))
DDRD |= 0x02;
DDRD = DDRD | 0x02; (does the same as the one above)
the |= 0x02 will ensure that you only set the bit you want to change
and the rest will be left alone
the = 0x02 will change the whole port
people generally use the format DDRD |= (1<<PORTB1), and DDRD &= ~(1<<PORTB1)
to make sure they only set the bits they want
and so it easy to understand which pins are being changed
Quote from: g_u_e_s_t on January 01, 2012, 07:53:03 PM
there are dip dram
the 41256 for example
its 256k x 1bit
which is perfect for 1bit converters
jameco has good stock
DRAM is slow anyway ... Not everyone here lives in the states you know :icon_mrgreen:
It's a very good code, thank you. But I have few questions.
1. Digital output PD5 must be connect to AIN1, the negative input of comparator for feedback loop?
2. In sigma delta we have a unit delay AFTER analogic comparator. So from ACO to quantizer we should have a comparator. I've noticed that you wrote NOP as a delay just for 1 logic output. But for 0 logic????
3. Have you put a capacitor on feedback loop between AIN1 and PD5?
thank you! waiting your answear.
Quote from: undergraduate1990 on March 29, 2014, 10:05:34 AM
It's a very good code, thank you. But I have few questions.
1. Digital output PD5 must be connect to AIN1, the negative input of comparator for feedback loop?
2. In sigma delta we have a unit delay AFTER analogic comparator. So from ACO to quantizer we should have a comparator. I've noticed that you wrote NOP as a delay just for 1 logic output. But for 0 logic????
3. Have you put a capacitor on feedback loop between AIN1 and PD5?
thank you! waiting your answear.
I assume the schematic is:
analog input to AIN0 (positive comparator input)
resistor from digital output to AIN1 (negative comparator input)
capacitor from AIN1 to ground.
And the need for the `nop`:
if (input == (1<<ACO)) {
asm("nop"); // even up loop times
PORTD |= (1<<PORTD5); // bitshift, bitwise OR, assignment
}
else {
PORTD &= ~(1<<PORTD5); // bitshift, negation, bitwise AND, assignment
}
...is because the `else` branch contains one additional instruction (~).
ok, I understood.It is any possibility to see bitstream signal?? I mean you have the output passed through a lowpass filter. I have tried to make a simulation on Proteus and It didn t work.
I m student, I m begginer and I need a bitstream signal from sigma delta modulator. After that I will have a digital lowpass filter and finally I want to reconstruct my original signal.
I saw that ACO can take only 2 value, depending of inputs, may I consider ACO as bitstream signal? At which frequency do you think that it will works?
Thank you and excuse my english! I hope that I will finish my project at faculty with succes!
I had the need to collect a bit more data than I could stuff in a 328....and I looked at adding some memory chips too.
But then I found the Teensy 3.1.
https://www.pjrc.com/teensy/teensy31.html (https://www.pjrc.com/teensy/teensy31.html)
64KB of Ram, 256KB of Flash, 2 ADC, Built-in 12 bit DAC, 32 bit 72Mhz ARM that runs Arduino Code. $20 each....cheap for this kind of power...!!
I am using it to capture a Pulse from a Fiber Loom and process an analog signal....capturing 4000 records.....pulse width is accurate to 1usec. Thing is super fast and super tiny...!! Also has a built in Real USB port, and 3 hardware serial ports.
it s working, sorry for previous post. i have obtained a 50khz bitstream sugnal. maybe higher frequency it will be better.