analogdevicesinc / gr-iio

IIO blocks for GNU Radio
GNU General Public License v3.0
94 stars 62 forks source link

Why is TX bit shifting not done in the FPGA #29

Closed djcopley closed 6 years ago

djcopley commented 6 years ago

This is a segment from the work function from the device sink.

    for (unsigned int i = 0; i < input_items.size(); i++)
        channel_write(channel_list[i], input_items[i],
                noutput_items * sizeof(short));

It loops through all the input items, calling the function channel_write on those items. Here is the content of the channel_write function.

    uintptr_t dst_ptr, src_ptr = (uintptr_t) src, end = src_ptr + len;
    unsigned int length = iio_channel_get_data_format(chn)->length / 8;
    uintptr_t buf_end = (uintptr_t) iio_buffer_end(buf);
    ptrdiff_t buf_step = iio_buffer_step(buf) * (interpolation + 1);

    for (dst_ptr = (uintptr_t) iio_buffer_first(buf, chn);
            dst_ptr < buf_end && src_ptr + length <= end;
            dst_ptr += buf_step, src_ptr += length)
        iio_channel_convert_inverse(chn,
                (void *) dst_ptr, (const void *) src_ptr);

It then loops again calling a handful of functions, including the libiio function iio_channel_convert_inverse. Upon inspection of that libiio function, we find yet another loop that shifts every sample over 4 bits (since the bus is 12 bits wide *msb aligned).

void iio_channel_convert_inverse(const struct iio_channel *chn,
        void *dst, const void *src)
{
    uintptr_t src_ptr = (uintptr_t) src, dst_ptr = (uintptr_t) dst;
    unsigned int len = chn->format.length / 8;
    ptrdiff_t end = len * chn->format.repeat;
    uintptr_t end_ptr = dst_ptr + end;
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
    bool swap = chn->format.is_be;
#else
    bool swap = !chn->format.is_be;
#endif
    uint8_t buf[1024];

    /* Somehow I doubt we will have samples of 8192 bits each. */
    if (len > sizeof(buf))
        return;

    for (dst_ptr = (uintptr_t) dst; dst_ptr < end_ptr;
            src_ptr += len, dst_ptr += len) {
        memcpy(buf, (const void *) src_ptr, len);
        mask_upper_bits(buf, chn->format.bits, len);

        if (chn->format.shift)
            shift_bits(buf, chn->format.shift, len, true);

        if (len == 1 || !swap)
            memcpy(least(void *) dst_ptr, buf, len);
        else
            byte_swap((void *) dst_ptr, buf, len);
    }
}

Now because of this, your cpu is pegged shifting bits and it is pretty much a guarantee that you'll drop samples. The AD9361 for example can sample at 61.44 msps, however, because of the software, you most likely won't be able to sample at even a measly 3 msps (depending on your hardware).

My question: Why is the bit shift not done in the fpga? The fpga seems to handle the bit shift on the rx end, so why not tx?

This question might be better suited for the libiio repo