You have two requirements here:
- You need to make sure you sample that data at the correct time according to the bus needs.
- You need to synchronize this data into your system clock domain.
There are a couple of ways to meet these needs.
First, if the bus clock is slow enough below your system clock, then you can synchronize the bus clock to your clock domain with a double flop. Then use a simple edge detector to determine when the rising edge is. This is used to safely sample the data line of the bus. Note that this achieves #2 automatically. Also, as noted here, this is the preferred way to do this in an FPGA.
This method has a drawback in that the data is sampled somewhere between two and three system clocks later than the actual 'on the pin' bus clock edge. If this is too long (due to your system clock not being fast enough in comparison), you have to go an alternative way.
In this method, you sample before synchronizing to the system clock domain. The reason is to make sure you are sampling at the right time according to the bus.
always @(posedge bclk) begin // positive edge of bus clock
sampled_data <= data;
end
At this point, you have sampled_data which is a signal in the bclk domain. You need to synchronize it to your system clock domain. To do this, you have to use handshaking or a FIFO.
One way that works is to do the shift register in the bus clock domain to get to parallel data. Then pass it through a dual clock FIFO to the other domain. FPGAs have primitives just for this use.
// Latch the data in the bclk domain
always @(posedge bclk) begin
fifo_d <= {fifo_d[30:0], data};
data_count <= data_count + 1;
if (data_count == 31)
fifo_wr <= 1'b1; // This will latch fifo_d to the dual clock fifo input
else
fifo_wr <= 1'b0;
end
// Read the data out of the FIFO in the system clock domain.
always @(posedge clk) begin
if (fifo_ready)
synchronized_data <= fifo_q; // Now the data is in your domain.
end
Other notes:
As with any I/O at the edge of the FPGA as well as between clock domains, you will need to correctly define the timing constraints. Do describe the details is a bit too general for this forum, but as recommended in the comments by Greg, this paper is a good source for understanding the needs for the clock domain crossing. The FPGA vendors tend to have decent write ups for input delay and output delay definitions as well.
Best Answer
This is explicitly a "X-Y problem". You have a typical audio application. To implement the real-time data processing for the signal, you have two basic options:
Implement the most trivial and common and easy USB class - CDC (aka "virtual COM port"). To accomplish the overall data processing goal, you will need to invent a method/format to pack the electret mic ADC data into UART-type stream, then use a common Windows/Linux COM-port driver to buffer and store the data, and then to develop a proprietary application do deal with your proprietary format. The plus of this approach is that you control the raw data format and don't need to dig any specifications for the data stream. Minuses of this approach is that you will need to develop a lot of your own code.
Since this is an audio device, the formal solution is to implement the audio-class USB device within the Nucleo board. As I understand, there are code examples form STM development, see USB Audio device class on NUCLEO-F446RE and USB Audio device on Nucleo F446-RE with CubeMX. Advantages of this approach would be all well-established libraries in all known operating systems. Minus side is that you need to dig into audio specifications.
In all cases the bandwidth of USB (even in FS mode) is well sufficient for audio processing tasks.