Hi Rob,

I think you can specify 2 ports in the N320 image. The only reason I can
think of to leave it as 4 is to serve as an example of how to configure it
for four ports. The N320 has a 4-port DRAM interface in the fixed logic
outside of RFNoC.

One challenge possibly related to the issues you had is that the DRAM is
very bursty. The 341 MS/s figure is an average. But it actually changes
between much higher than that rate and 0 MS/s, as it jumps between reading
and writing. This delay when the FIFO is not reading or not writing for a
given channel can lead to under/overflows. So, it's important to have
enough additional buffering in the design to account for that. Also, the
latency through the DRAM (from the FIFO input to the output) is longer than
that of most blocks. Consequently, another issue people encounter is not
setting the transmit time far enough into the future. Other than that, it
should work.

Wade

On Thu, Jun 11, 2026 at 9:06 AM Rob Kossler <[email protected]> wrote:

> Thanks Wade,
> Thanks for the link to the RFNoC FAQ - I had not seen that.  One question:
> In my original email, I had pasted some code from the stock N320 BIST yaml
> which included 4 DMA FIFO ports (but then specifically indicated that the
> latter 2 were not used).  But the FAQ indicates that you could simply
> choose a lower number of ports than the max.  So, is there any reason why
> the stock N320 BIST yaml specifies 4 ports (with 2 un-connected) rather
> than just 2 ports?
>
> In the period in between our emails, I was unable to get my "repeater
> application" working using the DMA FIFO so I simply removed it.  By
> removing it, my application included the following blocks statically linked:
>     Radio0-rx => DDC0 => my-time-stamp-adjust => DUC1 => Radio1-Tx
>
> This is a single-channel repeater chain where the block
> "my-time-stamp-adjust" simply adds a user-controllable integer to the
> receive time stamp so that the samples will not be late when they arrive at
> the transmit radio.  There was apparently enough "fifo buffering" in the
> NOC shells or otherwise that would allow me to set my time-stamp adjustment
> anywhere from 8100 to 18100 samples (with no DDC decimation / DUC
> interpolation) and avoid all Lates/Overruns.
>
> I am still curious why I couldn't get it working with the DMA FIFO.  The
> FAQ indicates throughput of 341 MS/s for single channel operation. This
> should be sufficient for my case of 250 MS/s. I know that you mentioned
> latency/delay. In my application it seems that latency/delay "variation" is
> all that matters.  In other words, I can compensate for any fixed
> latency/delay as long as I set my time-stamp-adjust value large enough that
> the samples won't be late.  But, if this latency/delay is varying then
> perhaps this could be an issue.  Let me know if you have any thoughts on
> using the DMA FIFO in this application.
> Thanks.
> Rob
>
> On Wed, Jun 10, 2026 at 4:26 PM Wade Fife <[email protected]> wrote:
>
>> Hi Rob,
>>
>> Sorry for the late reply. On the N320 you have 2 GiB of space that you
>> can divide as you like. Each channel gets a memory region defined by those
>> parameters. The FIFO_ADDR_BASE is the start address of each buffer and
>> FIFO_ADDR_MASK is effectively the size minus 1. The FIFO_ADDR_MASK must be
>> a power of 2 minus 1 (i.e., all ones). Set FIFO_ADDR_BASE to 0 for every
>> bit where the mask is 1. Take care not to create overlapping regions for
>> channels you intend to use. Otherwise, the data for one channel could
>> overwrite the data in another channel.
>>
>> If you want one maximum sized FIFO buffer, you can set the mask to
>> 31'7FFFFFFF to get a 2 GiB region. If you set each channel the same, then
>> you've assigned the same memory space to all four channels. This is fine if
>> you only intend to use one channel.
>>
>>       FIFO_ADDR_BASE: "{31'h00000000, 31'h00000000, 31'h00000000,
>> 31'h00000000}"
>>       FIFO_ADDR_MASK: "{31'h7FFFFFFF, 31'h7FFFFFFF, 31'h7FFFFFFF, 31'
>> h7FFFFFFF}"
>>
>> If you want two maximum sized buffers, I think your example is correct
>> assuming you only intend to use the first and second channels.
>>
>>       FIFO_ADDR_BASE: "{31'h00000000, 31'h00000000, 31'h40000000,
>> 31'h00000000}"
>>       FIFO_ADDR_MASK: "{31'h3FFFFFFF, 31'h3FFFFFFF, 31'h3FFFFFFF,
>> 31'h3FFFFFFF}"
>>
>> If you want four maximum sized buffers, it would be:
>>
>>       FIFO_ADDR_BASE: "{31'h60000000, 31'h40000000, 31'h20000000,
>> 31'h00000000}"
>>       FIFO_ADDR_MASK: "{31'h1FFFFFFF, 31'h1FFFFFFF, 31'h1FFFFFFF, 31'
>> h1FFFFFFF}"
>>
>> The throughput is highly application-dependent. It will vary based on the
>> number of channels and how much those channels contend for memory at the
>> same time. But we have some benchmark numbers here that will give you a
>> rough idea:
>>
>>
>> https://kb.ettus.com/RFNoC_Frequently_Asked_Questions#What_DRAM_data_rates_can_I_expect_on_each_USRP.3F
>>
>> If you're looking for bytes per second, multiply the numbers in that
>> table by 4.
>>
>> One common gotcha is DRAM latency/delay. You may need to tweak the
>> IN_FIFO_SIZE and/or OUT_FIFO_SIZE when connecting DRAM directly to a radio
>> block. It's possible to see under/overruns in the radio even if the DRAM is
>> "fast enough" due to DRAM latency, particularly when it cycles between
>> multiple channels. But in your case, connecting DRAM to the DDC/DUC, you'll
>> probably be OK as long as the timestamp delay you add is longer than the
>> total latency through the DRAM.
>>
>> Wade
>>
>> On Thu, May 28, 2026 at 9:39 AM Rob Kossler via USRP-users <
>> [email protected]> wrote:
>>
>>> Hi,
>>> I am building an N320 image that is basically a repeater with static
>>> rfnoc links as follows:
>>>   radio0 => ddc0 => my-timestamp-adjust => axi_ram_fifo => duc1 => radio1
>>>
>>> I have a question about how to use the parameters of the axi_ram_fifo
>>> block in order to maximize the FIFO depth.  From the N320 BIST yml, I found
>>> the following:
>>>       # These parameters match the memory interface on the N3XX
>>>       NUM_PORTS: 4
>>>       MEM_DATA_W: 64
>>>       MEM_ADDR_W: 31
>>>       # Create four non-overlapping 32 MB buffers by default
>>>       FIFO_ADDR_BASE: "{31'h06000000, 31'h04000000, 31'h02000000,
>>> 31'h00000000}"
>>>       FIFO_ADDR_MASK: "{31'h01FFFFFF, 31'h01FFFFFF, 31'h01FFFFFF,
>>> 31'h01FFFFFF}"
>>>       MEM_CLK_RATE: "303819444" # 166.666666 MHz * 21.875 / 4 / 3 =
>>> 303.819444 MHz
>>>
>>> This indicates that there are 4 ports (later in the yml, ports 3 and 4
>>> are explicitly not connected).  My question is: how do I configure
>>> FIFO_ADDR_BASE and FIFO_ADDR_MASK in order to maximize the FIFO capacity?
>>>
>>> For the case of only needing one FIFO buffer, would this be correct?
>>>       FIFO_ADDR_BASE: "{31'h00000000, 31'h00000000, 31'h00000000,
>>> 31'h00000000}"
>>>       FIFO_ADDR_MASK: "{31'h3FFFFFFF, 31'h3FFFFFFF, 31'h3FFFFFFF,
>>> 31'h3FFFFFFF}"
>>>
>>> For the case of only needing two FIFO buffers, would this be correct?
>>>       FIFO_ADDR_BASE: "{31'h00000000, 31'h00000000, 31'h40000000,
>>> 31'h00000000}"
>>>       FIFO_ADDR_MASK: "{31'h3FFFFFFF, 31'h3FFFFFFF, 31'h3FFFFFFF,
>>> 31'h3FFFFFFF}"
>>>
>>> My other question is related to what is the maximum axi_ram_fifo
>>> throughput?  Can I run with one port (in & out) at full streaming rate of
>>> 250 MS/s?  Does the RAM bandwidth support this rate?  How about if I have 2
>>> ports (in & out) - what is the maximum rate?
>>>
>>> Rob
>>> _______________________________________________
>>> USRP-users mailing list -- [email protected]
>>> To unsubscribe send an email to [email protected]
>>>
>>
_______________________________________________
USRP-users mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to