I need to read data from another chip. The data is generated at 1.6Mhz. And I need to send it to the PC or store it the RAM and send to PC later.
Can anyone give me some advice on how to do this? I totally have no idea.
I know nothing about microcontroler before I touch leaflab.
Thanks
How to read data at 1.6Mhz from another chip?
(18 posts) (4 voices)-
Posted 4 years ago #
-
I guess it is impossible to send data back to PC at such high speed.
So, What I need is to find one way to store it in the RAM, right?
How could I do it?
Besides, should I use digitalRead to do this? It must be too slow then.
Could anyone have other suggestions?
Thanks,Posted 4 years ago # -
I would look into using DMA if possible.
Posted 4 years ago # -
gulu2065 - I understand the data is generated at 1.6MHz, how many bits is it? Just one?
It is possible to move data at 1.6Mbits over Full-Speed USB, but I don't think the current Maple USB driver is that fast. IIRC, a single channel maxes out at 512Kbits. Well worth trying though.
One enterprising Maple user got a High-Speed (480Mbits) FTDI chip, which pumped it to the host very quickly. I don't know how fast it went, but I assume fast enough (which, I vaguely remember they needed more than Full-Speed's 12Mbits)
(full disclosure: I am not a member of LeafLabs staff.)
Posted 4 years ago # -
gbulmer
It is at least 16224 bits. Could I save data in the RAM fist and then transfer it to PC later?
kqr2 mentioned DMA. But I haven't figure not how to use it now.Posted 4 years ago # -
kqr2,
could you offer any more detail on this?
I have no idea how to use DMA. Could you give me any details?
Thanks a lot!Posted 4 years ago # -
gbulmer,
I am a little confusing on what your are saying now.
In fact, I read data from only one source, another chip, and then want to store it and at last deliever it to the PC.Posted 4 years ago # -
gulu2065 -
It is at least 16224 bits. Could I save data in the RAM fist and then transfer it to PC later?
If it is just that signal, then with a few hundred milliseconds available for a transfer, yes, you could do that.
In fact, I read data from only one source, another chip, and then want to store it and at last deliever it to the PC
Okay - I misunderstood. I thought you wanted to transfer the data to PC at the same time as the 1.6MHz signal is being sampled. Hence the comment about using a fast USB.
If your code can sample the 1.6MHz signal, and then transfer the data 'later', it is likely doable.
Posted 4 years ago # -
gulu2065 - there are a couple of ways that you might try sampling the signal.
You want to respond quite quickly to a regular signal which is quite fast, so I wouldn't recommend trying to use interrupts.
At 1.6MHz, your code only has 45 cycles to do the job, and interrupt entry and exit will likely waste more than half of that and not contribute to getting the information needed.So just poll (sit in a loop testing).
Either use the timer to do the work using "Input Capture", or do it all in code.1. Polling (no timer input capture)
As you've discovered (in other threads), you can get a pretty regular output signal using loops and setting a pin directly, and you could use a similar technique to sample an input signal. This technique is workable, but quite awkward if you change the code because the timing will have to be re-calibrated. Another problem is when the code gets the signal, it is likely going to take different amounts of time depending at some points. For example, you might want to pack the data, and every time the code gets a 'word' it'll take a different amount of time to store the word away which means the code has two different duration's (unless you can code the same number of cycles in each path (which might be very difficult).So, use the timer directly to keep track of the 1.6MHz, and poll its registers to synchronise with the input signal.
Concretely, you have most of what you need set up in http://forums.leaflabs.com/topic.php?id=1046That gives a timer which resets at 1.6MHz.
When the compare register matches the counter, it will set a bit in a timer control register (TIMxSR)
See RM0008, 15.4.5 "TIMx status register (TIMx_SR)"
I believe the bit is CC1F or CC2F or CC3F or CC4F (depending on which channel the code is using)So it will be something like:
uint8 bits[16244/8+1]; void loop() { for (int i=0; i<16244; ++i) { // wait until the timer triggers while (! (TIMER1_BASE->SR & (1<<TIMER_SR_CC1OF_BIT)) { } // get the bit from the pin, could use bit band address uint16 bit = (GPIOB_BASE->IDR & (1<<BIT_N)) != 0; if ( (i & 0x7)==0) { // bit offset within byte zero? bits[i>>3] = bit; // starting a new byte, so clear it } else { // pack the bit into the byte bits[i>>3] |= (bit<<(i & 0x7)); } } // send the bytes up to the host .... }
2. Using the timer
I had thought there was a way to get the timer to sample a pin at a regular interval, but if there is, I can't find it.
Instead, measure how many cycles the input signal is at the same value.
This uses the timers input capture mode (RM0008 15.3.5 "Input capture mode")
Instead of using a pin to generate an output signal, each timer channel can detect an input signal, and when the input signal changes, the channel will capture the counter register into its channel capture/compare register. So, if the signal changes every cycle at 1.6MHz, the capture/compare register will get the value of the counter, say 0, stored into it. If the signal doesn't change for, say, 4 cycles, the capture/compare register will get the value 3 say. So this is measuring the number of cycles of 1.6Mhz that happens in between every change. Further software will be needed to decode the value, but it should work. The reload value will be set to 65535 (0xFFFF) so that it just counts, and is used to measure stretches of the same value.Normally, I would sample the signal at a higher frequency as slight jitter on the input signal could cause the sample time to jitter by 1. So for example you might sample the signal with the counter running at 9x faster (reload at 5), and jitter should only cause the captured counter to change jitter between 7 and 8 (or multiples like 15 or 16), so the sample should be pretty reliable. This assumes the external signal changes often enough to avoid any overflow.
This time, the flag your code is monitoring is one of the CCxIF bits in the status register (SR)
For example
const int COUNTS_PER_SAMPLE = 5; // 'oversample', so jitter is easier to handle void setup() { ... Timer1.setPrescaleFactor(1); Timer1.setOverflow(COUNTS_PER_SAMPLE); } uint8 bits[16244/8+1]; int overall_duration = 0; void loop() { while (overall_duration < 16244) { // wait until input capture triggers, got a signal change while (! (TIMER1_BASE->SR & (1<<TIMER_SR_CC1IF_BIT)) { } // get the capture register, which counts signals uint16 duration = TIMER1_BASE->CCR1; // get capture value // convert the duration to a sequence bits ... somehow derive the previous state of the signal, .... could just read the pin, and invert while (duration > COUNTS_PER_SAMPLE) { if ( (overall_duration & 0x7)==0) { // starting a new byte? bits[overall_duration >>3] = prev_signal_state; // yes, so clear it } else { // pack the bit into a partial byte bits[overall_duration>>3] |= (bit<<(overall_duration & 0x7)); } duration -= duration % COUNTS_PER_SAMPLE; // adjust duration overall_duration++; } } // send the bytes up to the host .... }
There is an example in RM0008, 15.3.6 "PWM input mode" too
WARNING, I haven't compiled or tested this code, it is only outlines
Posted 4 years ago # -
gbulmer,
Thanks a lot!
Actually, I use timer1 to generate a 1.6Mhz signal and send it to another chip. And at the same time, the chip will generate a 1.6Mhz signal, synchronously with the CLK.I am quite a outsider on this program. I am a hardware engineer. I can't read and fully understand the code you post above. Could you explain a little in detail?
As I know, if we use while or such kind of command or function, it will take longer than about I microsenconds to execute it. So will it be able to read data at 1.6Mhz?
Or where could I figure this out and write and revise such code myself?
ThanksPosted 4 years ago # -
gulu2065 - Let me check that I understand.
The output of timer1 is a 'master clock' signal which is used by the other chip to synchronise sensing data?If that is the case my concerns about jitter should be irrelevant.
Set the timer counter reload to 45 to get 1.6MHz, and try the first code, simple polling, and set the compare value to 22.
When the timer channel compare register matches the timer counter, the corresponding 'compare matched bit' in the timer status register for that channel, TIMER_SR_CCxOF_BIT, will be set, and the code can go read the pin.
With a reload of 45, and a compare of 22 your code will be look at the bit in the middle of the cycle:
uint16 bit = (GPIOB_BASE->IDR & (1<<BIT_N)) != 0;
So, if the timer is timer1, and channel is 2, say, then:
while (! (TIMER1_BASE->SR & (1<<TIMER_SR_CC2OF_BIT)) { }
will be set close to half-way through the cycle, so the input signal should be stable, and ready to sample.
As I know, if we use while or such kind of command or function, it will take longer than about I microsenconds to execute it.
while
is not a function, it is a control construct of the C/C++ language. The syntax might look like a function, but it isn't. The compiler generates inline code, there is no function call overhead.
while
will often run as fast or faster than a goto because the compiler can do smarter things with while than it can with a goto.
while
should take a lot less than a microsecond.
If that test were converted to a bit-band address, I think the while would be about 6 cycles. It is probably 8.To test it, you could do something like take a start time, do something a lot, then get the stop time.
Better yet, assuming you have an oscilloscope, just use that to change a pin, and monitor it with the oscilloscope:
1 Test 'empty' loop:
void setup() { ... set up timer ... } void loop() { while(1) { (GPIOB_BASE)->BSRR = BIT(6); (GPIOB_BASE)->BRR = BIT(6); } }
You will also be able to measure this with your oscilloscope. I think it is about 12MHz.
2. Test time to check counter
Insert the extra code to test the status bit of the timer (make sure the channel it is looking at, TIMER_SR_CC1OF_BIT, is the one doing the compare.void setup() { ... set up timer ... } void loop() { while(1) { (GPIOB_BASE)->BSRR = BIT(6); while (! (TIMER1_BASE->SR & (1<<TIMER_SR_CC1OF_BIT)) { } (GPIOB_BASE)->BRR = BIT(6); } }
3. Check pin too
Add a bit more code in, for example:
void setup() { ... set up timer ... } void loop() { while(1) { (GPIOB_BASE)->BSRR = BIT(6); while (! (TIMER1_BASE->SR & (1<<TIMER_SR_CC1OF_BIT)) { } uint16 bit = (GPIOB_BASE->IDR & (1<<BIT_N)) != 0; (GPIOB_BASE)->BRR = BIT(6); } }
and again check timing with your oscilloscope.
Keep adding the stuff in, and use the pin toggling to check timing.You will want to disable USB interrupts and systick for your actual system, and to get an accurate signal, but they are so rare (by comparison with the pin wiggle) that you'll likely get a reasonable idea of timing.
Does that help?
Posted 4 years ago # -
@gulu2065 : since you have a synchronous clock signal with the data, you may be able to use SPI DMA to RAM.
STM actually provides an example of this using their standard peripheral library (not leaflab's libmaple).
It's located in:
STM32F10x_StdPeriph_Lib_V3.5.0/Project/STM32F10x_StdPeriph_Examples/DMA/SPI_RAM
You can download the library and example from:
http://www.st.com/internet/com/SOFTWARE_RESOURCES/SW_COMPONENT/FIRMWARE/stm32f10x_stdperiph_lib.zip
Posted 4 years ago # -
kqr2 - see http://forums.leaflabs.com/topic.php?id=1057#post-6489
One possible problem is SPI has a limited range of baud rates.
Posted 4 years ago # -
@gbulmer : Yes, I would definitely run the stm32 in slave mode which doesn't have the fixed baud rate limitation.
Posted 4 years ago # -
There's libmaple support for this via HardwareSPI::beginSlave():
http://leaflabs.com/docs/lang/api/hardwarespi.html#hardwarespi-class-reference
Posted 4 years ago #
Reply »
You must log in to post.