Raspberry Pi Pico - Generate finite length square wave - micropython

I have a question about generating square waves with finite length by using a Raspberry Pi Pico. For example, I want to generate a 20 kHz square wave with 100 periods, or to generate a 20 kHz square wave with an exact 1 ms. I cannot have accurate control over it.
To generate an infinite length of square waves is easy, as there are lots of examples online. I can use PIO to achieve it. For example, the following code could do so:
import rp2
from machine import Pin
#rp2.asm_pio(set_init=rp2.PIO.OUT_LOW)
def blink():
set(pins, 1)
set(pins, 0)
sm = rp2.StateMachine(0, blink, freq=25000, set_base=Pin(26))
sm.active(1)
However, I don't know how to accurately control the length/periods of the square wave. By using time.sleep() is not accurate at all.
Thank you in advance!

Use the "decrement X" instruction in the PIO to count the number of cycles you want. Might have to add some delays to get back a square wave. jmp(x_dec, "top_of_loop"). You'd hang, waiting for some input, and read the X value from the input FIFO. Then you'd run the square-wave loop, decrementing X. When it hits zero, you jump to the outer loop, where you again wait for a new X value for the number of cycles. I think that's it!

Related

Accuracy of STM32L496 generated square wave

I have an STM32L496 MCU, and I want to generate a 3MHz square wave. I would like to know what would be the accuracy of this signal.
The system clock frequency of this MCU is 80MHz. If I use a prescaler of 80MHz / 3MHz = 26.667 (can I do that?), then the timer will tick at a rate of 3MHz. If I use a 16-bit timer (TIMER16), it would count to 65 535 maximum, which means it would increment once every 0.33 microseconds.
That is how far I understood, but I am not sure how to calculate the accuracy of this signal. Any help would be much appreciated!
If the core is 80MHz you can't make 3MHz exactly with a timer clocked from the same source as the core.
You can make 3.076923 MHz with even mark space ratio (prescaler 1, compare value 13 reset value 26), or you can make 2.962962 MHz (which is slightly closer) with a 13:14 mark space ratio (prescaler 1, compare value 13 or 14, reset value 27).
To get 3MHz you would have to underclock your core down to 78MHz.
I don't know the exact part you are using. You might be able to get it exactly using one of the clock outputs or a PLLs other than the one that drives the core, eg: if you have a 12MHz crystal you can output 3MHz easily on an MCO pin.

How to detect ultrasonic range sensor is out of range or not?

I am using jsn-srf04t ranging sensor (25cm to 5m range) I want to know when it is going out of range(when under 25cm)
The problem is when it goes under 25 cm, the sensor output sometimes goes to (90cm to 95cm or 100cm to 120cm) and this cause undetectability of that it is really out of range or not!
Is there any solution?
This question is not directly related, but I thought I post a suggestion/answer anyway.
SRF04's can detect the distances as small as 3 cms. Please measure the width of the output echo pulse using an oscilloscope. It can be from 100uS to 18mS and if there is no object within its range, the echo pulse is 36ms.
If the measured pulse width from the oscilloscope is agreeing with what you say, then presumably the SRF04 is faulty, or there is a problem with its mounting etc.
If the width of the pulse is measured in uS, then dividing by 58 will give you the distance in cm, or dividing by 148 will give the distance in inches.
The SRF sensors can be triggered as fast as every 50mS, or 20 times each second. You should wait 50ms before the next trigger to ensure the ultrasonic "beep" has faded away and will not cause a false echo on the next ranging.
Otherwise, check your timer configuration. Ensure that it can measure a pulse in the order of hundreds of microseconds with at least a resolution of tens of microseconds.
If you are using this, then perhaps you are at the lowest possible level.

Random number generation with Poisson distribution in Matlab

I am trying to simulate an arrival process of vehicles to an intersection in Matlab. The vehicles are randomly generated with Poisson distribution.
Let´s say that in one diraction there is the intensity of the traffic flow 600 vehicles per hour. From what I understood from theory, the lambda of the Poisson distribution should be 600/3600 (3600 sec in 1 hour).
Then I run this cycle:
for i = 1:3600
vehicle(i) = poissrnd(600/3600);
end
There is one problem: when I count the "ones" in the array vehicle there are never 600 ones, it is always some number around, like 567, 595 and so on.
The question is, am I doing it wrong, i.e. should lambda be different? Or is it normal, that the numbers will never be equal?
If you generate a random number, you can have an expectation of the output.
If you actually knew the output it would not be random anymore.
As such you are not doing anything wrong.
You could make your code a bit more elegant though.
Consider this vectorized approach:
vehicle = poissrnd(600/3600,3600,1)
If you always want the numbers to be the same (for example to reproduce results) try setting the state of your random generator.
If you have a modern version (without old code) you could do it like so:
rng(983722)

Sine LUT VHDL wont simulate below 800 hz

I made a sine LUT for VHDL, using 256 elements.
Im using MIDI input, so values range 8.17Hz (note #0) to 12543.85z (note #127).
I have another LUT that calculates how many value must be sent to my 48 kHz codec in order to play the sound (the 8.17Hz frequency will need 48000/8.17 = 5870 values).
I have another LUT that contains an index factor, which is 256/num_Values, which is used to call values from the sin table (ex: 100*256/5870 = 4 (with integer rounding)).
I send this index factor to another VHDL file, which is used to calculate which value should be sent back. (ex: index = index_factor*step_counter)
When I get this index, I divide it by 100, and call sineLUT[index] to get the value that I need to generate a sine wave at the desired frequency.
The problem is, only the last 51 notes seem to work for me, and I do not know why. It seems to get stuck on a constant note at anything below that frequency (<650 hz) , and just decrease in volume every time I try to lower the note.
If you need parts of my code, let me know.
Just guessing, I suspect your step_counter isn't going through enough cycles, so your index (into the sine lut) doesn't go through a full 360 degrees for the lower frequencies.
For anything more helpful, you'll probably have to post code.
As an aside, why aren't you using something more like a conventional DDS? Analog Devices has a nice write-up on the basics: DDS Tutorial

Measuring Frequency of Square wave in MATLAB using USB 1024HLS

I'm trying to measure the frequency of a square wave which is read through a USB 1024 HLS Daq module through MATLAB. What I've done is create a loop which reads 100 values from the digitial input and that gives me vector of 0's and 1's. There is also a timer in this loop which measures the duration for which the loop runs.
After getting the vector, I then count the number of 1's and then use frequency = num_transitions/time to give me the frequency. However, this doesn't seem to work well :( I keep getting different frequencies for different number of iterations of the loop. Any suggestions?
I would suggest trying the following code:
vec = ...(the 100-element vector of digital values)...
dur = ...(the time required to collect the above vector)...
edges = find(diff(vec)); % Finds the indices of transitions between 0 and 1
period = 2*mean(diff(edges)); % Finds the mean period, in number of samples
frequency = 100/(dur*period);
First, the code finds the indices of the transitions from 0 to 1 or 1 to 0. Next, the differences between these indices are computed and averaged, giving the average duration (in number of samples) for the lengths of zeroes and ones. Multiplying this number by two then gives the average period (in number of samples) of the square wave. This number is then multiplied by dur/100 to get the period in whatever the time units of dur are (i.e. seconds, milliseconds, etc.). Taking the reciprocal then gives the average frequency.
One additional caveat: in order to get a good estimate of the frequency, you might have to make sure the 100 samples you collect contain at least a few repeated periods.
Functions of interest used above: DIFF, FIND, MEAN
First of all, you have to make sure that your 100 samples contain at least one full period of the signal, otherwise you'll get false results. You need a good compromise of sample rate (i.e. the more samples per period you have the better the measurement is) and and number of samples.
To be really precise, you should either have a timestamp associated with every measurement (as you usually can't be sure that you get equidistant time spacing in the for loop) or perhaps it's possible to switch your USB module in some "running" mode which doesn't only get one sample at a time but a complete waveform with fixed samplerate.
Concerning the calculation of the frequency, gnovice already pointed out the right way. If you have individual timestamps (in seconds), the following changes are necessary:
tst = ...(the timestamps associated with every sample)...
period = 2*mean(diff(tst(edges)));
frequency = 1/period;
I can't figure out the problem, but if the boolean vector were v then,
frequency = sum(v)/time_to_give_me_the_frequency
Based on your description, it doesn't sound like a problem with the software, UNLESS you are using the Windows system timer, which is notoriously inaccurate (it is only accurate to about 15 milliseconds).
There are high-resolution timers available in Windows, but I don't know how to use them in Matlab. If you have access to the .NET framework, the Stopwatch class has 1 microsecond accuracy (or better), as does the QueryPerformanceCounter API in Win32.
Other than that, you might have some jitter. There could be something in your signal chain that is causing false triggers, etc.
UPDATE: The following CodeProject article should solve the timing problem, if there is one. You should check the Matlab documentation of your version of Matlab to see if it has a native high-resolution timer. Otherwise, you can use this:
C++/Mex wrapper adds microsecond resolution timer to Matlab under WinXP
http://www.codeproject.com/KB/cpp/Matlab_Microsecond_Timer.aspx
mersenne31:
Thanks everyone for your responses. I have tried the solutions that gnovice and groovingandi mentioned and I'm sure they will work as soon as the timing issue is solved.
The code I've used is shown below:
for i=1:100 tic; value = getvalue(portCH); vector(i) = value(1); tst(i) = toc; % gets an individual time sample end
% to get the total time I put total_time = toc after the for loop
totaltime = sum(tst); edges = find(diff(vec)); % Finds the indices of transitions between 0 and 1 period = 2*mean(diff(edges)); % Finds the mean period, in number of samples frequency = 100/(totaltime*period);
The problem is that measuring the time for one sample doesn't really help because it is nearly the same for all samples. What is needed is, as groovingandi mentioned, some "running" mode which reads 100 samples for 3 seconds.
So something like for(3 seconds) and then we do the data capture. But I can't find anything like this. Is there any function in MATLAB that could do this?
This won't answer your question, but it's what I thought of after reading you question. square waves have infinite frequency. The FFT of a square wave it sin(x)/x, which goes from -inf to +inf.
Also try counting only the rising edges in matlab. You can quantize the signal to just +1 and 0, and then only increment the count when you see [0 1] slice of your vector.
OR
You can quantize, decimate, then just sum. This will only work if the each square pulse is the same length and your sampling frequency is constant. I think this one would be harder to do.