link my added nios2 register with actual Nios software

Discussions related to embedded firmware, driver, and user mode application software development

Moderator: robert.ghilduta

Post Reply
zibi
Posts: 3
Joined: Mon May 30, 2016 5:29 am

link my added nios2 register with actual Nios software

Post by zibi » Fri Jun 10, 2016 7:21 am

Hi everyone,

I wanna access my parallel I/O 32Bit Register "fft" added with QSYS to my nios2 Softcore.
I'm relatively new in software development and a bit confused about the "NIOS II Code Redesign".
https://www.nuand.com/blog/page/2/

Could you suggest some steps a should follow?
The README file specifies only packets with different sizes .. pkt_32x32 for example, but no ways how to move on..
Because it's too trivial.. I hope:)

Thanks in advance,


Zibi

jynik
Posts: 455
Joined: Thu Jun 06, 2013 8:15 pm

Re: link my added nios2 register with actual Nios software

Post by jynik » Fri Jun 10, 2016 9:23 pm

I'll try to take a stab at explaining this, and if it helps, I'll add it to some READMEs.

Accessing Registers
Once you've added a register in QSYS and built the FPGA, you'll find that some files will be generated in the bladeRF_nios_bsp directory. In here you'll see headers that contain the base address of your address space. Try doing a build and then looking for the LMS6 register access space region, described by a LMS_SPI_BASE definition.

The devices.c file is generally where we add functions (generally small wrappers with nice names) to register accesses. Here is an example of where we access the LMS6002 register space (8-bit address and data).

Packet formats
As you found from this README, there's a number of different packet formats. The formats in the form pkt_AxD are intended for register access with A-bit addresses (or masks) and D bit data. You'll also see a pkt_retune for "quick retune" and "scheduled retune" functionality, as well as a pkt_legacy for reverse compatibility with earlier FPGAs.

A "magic byte" is the first byte of a packet and denotes the format of the data the follows. Values of 0x80-0xff will not be used in upstream bladeRF code and are reserved for users to make customizations without worrying about conflicting with any packet formats we may add in the future. (If you're going to submit a PR to integrate your code upstream, you may choose one of the "official" values.)

In the pkt_AxD formats, you'll see an ID field that denotes the device/module to communicate with. Again, values of 0x80-0xff are available for user customizations -- official code will not use these values.

Adding a (sub)packet

To either add a new packet format entirely, or add a new ID to an existing packet, you'll want to modify the header files found here.
These files are located in fpga_common/include because both libbladeRF and the NIOS II code both use these definitions.

The implementation of a packet should contain descriptions of the request and response formats, similar to what's shown here for the pkt_32x32.


You can then add a definition of your custom pkt_32x32 ID here.

Handle the packet in the NIOS II
Next, you'll want to add the code to handle there request and response associated with this new ID in the NIOS code. For each packet format, there's an associated C file here.

For example, this is where you could place a function call to write your 32-bit data, and this is where you could place a function call to read it.

The functions to perform those reads/writes are up to you, and depend on the FPGA module you're talking to.

At this point, the FPGA side of thing should be ready to handle reads/writes of your packet changes. Onto the host side!

NIOS II access in libbladeRF

libbladeRF's nios_access.h and nios_access.c
provide functions to perform the operations made available by these packets. These are conveniently named wrappers around using these packets, and abstract away the underlying packet handling; the caller does not and should not need to care about the underlying packet format.

Thus, you'd add a read/write pair of functions to these files.

Some simple example are the nios_lms6_read() and nios_lms6_write() functions, which utilize the pkt_8x8 format.

Next, you need to expose this functionality to the libbladeRF code through the "backend" interface. If you take a look here at usb.c, you'll see that there's a function table
of all the operations that may be performed over a "backend". You can add a function pointer to this structure and assign in in usb.c. (This whole "backend" abstraction was made to allow us to add IPC and network backends at some point...still a TODO unfortunately...)

At this point, your functionality has been exposed to the libbladeRF core code.

API access

If you want to extend the libbladeRF API to allow you to use your functionality, you can do so by adding a function prototype to libbladeRF.h and an implementation to bladerf.c. Generally, I prefer that new functionaly be added into separate .c/.h files and that bladerf.c remains just a place to acquire the "control lock", if needed, and call into the module's interface.

Going back to our earlier example of the lms6_read/write implementations in nios_access.c -- we see the calls into that "backend" interface here for the LMS6 read and here for the write.


Comments

This certainly seems like a lot, but it's not too bad once you've been through it a time or two. Bear in mind this whole interface is more intended for "slow" control data, as opposed to the tens of MSPS worth of data the sample streaming interface is designed for.

Let me know if anything's unclear!

Cheers,
Jon

zibi
Posts: 3
Joined: Mon May 30, 2016 5:29 am

Re: link my added nios2 register with actual Nios software

Post by zibi » Mon Jun 13, 2016 4:28 am

Hi Jon,

thank You for your comprehensive response.
I did as you said and
-defined my own package in nios_pkt_32x32.h :

Code: Select all

#define NIOS_PKT_32x32_TARGET_FFT    0x80
-added my handle case in pkt_32x32.c
in perform_write function:

Code: Select all

        //my customizations
        case NIOS_PKT_32x32_TARGET_FFT:
        	data = 0x9520; //Base address 0x9520 of my fft register
			break;
        //my customizations END
in perform_read:

Code: Select all

        //my customizations
        case NIOS_PKT_32x32_TARGET_FFT:
        	*data = 0x9520; //Base address 0x9520 of my fft register
			break;
        //my customizations END
I can not understand why eclipse cannot resolve my stuff:
"Symbol 'NIOS_PKT_32x32_TARGET_FFT' could not be resolved pkt_32x32.c"
The definition "NIOS_PKT_32x32_TARGET_EXP_DIR", for example can be found and stands just above my "NIOS_PKT_32x32_TARGET_FFT" in
nio_pkt_32x32.h .

Greetings,
Zibi

zibi
Posts: 3
Joined: Mon May 30, 2016 5:29 am

Re: link my added nios2 register with actual Nios software

Post by zibi » Mon Jun 13, 2016 8:44 am

@Jon

What do you mean with "add a function pointer to this structure and assign in in usb.c" ?

Following the lms6 example I added and changed the sizes to 32 only.

in nios_access.h :

Code: Select all

int nios_fft_register_read(struct bladerf *dev, uint32_t addr, uint32_t *data);
int nios_fft_register_write(struct bladerf *dev, uint32_t addr, uint32_t data);
in nios_access.c :

Code: Select all

int nios_fft_register_read(struct bladerf *dev, uint32_t addr, uint32_t *data)
{
    int status = nios_32x32_masked_read(dev, NIOS_PKT_32x32_TARGET_FFT, addr, data);
    if (status == 0) {
        log_verbose("%s: Read 0x%02x from addr 0x%02x\n",
                    __FUNCTION__, *data, addr);
    }
    return status;
}

int nios_fft_register_write(struct bladerf *dev, uint32_t addr, uint32_t data)
{
    int status = nios_32x32_masked_write(dev, NIOS_PKT_32x32_TARGET_FFT, addr, data);
    if (status == 0) {
        log_verbose("%s: Wrote 0x%02x to addr 0x%02x\n",
                    __FUNCTION__, data, addr);
    }
    return status;
}
in usb.c :

Code: Select all

    FIELD_INIT(.fft_register_read, nios_fft_register_read),
    FIELD_INIT(.register_write, nios_fft_register_write),

in backend.h :

Code: Select all

    int (*fft_register_read)(struct bladerf *dev, uint32_t addr, uint32_t data);
    int (*fft_register_write)(struct bladerf *dev, uint32_t addr, uint32_t *data);

results in the error "initialization from incompatible pointer type" referring to my "nios_fft_register_read"

Thanks for your patiece,
Zibi

Post Reply