Alchitry

Navigation: Main menu

This tutorial will introduce you to the register interface component and how it can be used to create easy and reliable interfaces to your designs.

Overview

The register interface component takes over a serial port (typically from the AVR interface component) and create an address based interface. You can then issue read and write requests over the Mojo's USB port to specific addresses. By default, these addresses have no meaning. They are simply a way for you to differentiate the requests. Both the data and address values are 32 bits wide.

Example

Let's create a quick example that will map the LEDs on the Mojo to address 0. That way we can read and write to address 0 to change the value of the LEDs.

Create a new project based on the AVR Interface example.

Now open up the components library and add the Register Interface component, which can be found under Interfaces.

We now need to hook it up to the serial port of the AVR Interface in mojo_top.luc.

Here you can see the interface we will be dealing with. When the master (your PC) issues a command, regOut.new_cmd goes high. At this time, regOut.write will tell you if it is write or read request and regOut.address will tell you what address is being referenced. During a write, regOut.data is valid and is the data that should be written to the specified address. During a read, this value is invalid and should be ignored.

When a read request is sent, the value corresponding to regOut.address should be generated and presented on regIn.data. When it is ready, regIn.drdy should be set high.

We now need to add a dff to save the value of the LEDs.

.rst(rst){
// the avr_interface module is used to talk to the AVR for access to the USB port and analog pins
avr_interface avr;
reg_interface register;
dff leds [8];
}

When we detect a write request, we update the value of leds, but when detect a read request, we return the value of leds. Note that we are filtering only for address 0. All other address requests will be ignored.

In the Mojo IDE, go to Tools->Register Interface.... This tool allows you to send read and write requests to specific addresses when using the register interface component. Fill in 0 for Address and 1 for Value then click Write.

If everything went well, the first LED on your Mojo should have lit up! Try writing different values. Also note that you can use the radio buttons to select if you want the address and value fields to be represented in decimal or hexadecimal.

If you try to read from an address other than 0, you'll get an error message saying the read failed. This is because if the address isn't 0, we never return any data (regIn.drdy stays 0 forever) so the read times out. You can write to other addresses, but the writes are simply ignored.

Try to modify the code so that address 0 still controls the LEDs, but address 1 now will read a bit-wise inverted version of what was last written to it. If you need help, hit up our forums.

The API

This built in register interface tool is helpful, but manually entering everything isn't always practical. Here we will go over how the protocol works for issuing read and write requests so that you can use this in your own applications.

Every request starts with 5 bytes being sent. The first byte is the command byte and the next four are the address (32 bits = 4 bytes) sent with the least significant byte first.

In many cases you will want to read or write to many consecutive addresses, or perhaps the same address many times. It would be inefficient to have to issue the entire command each time so the command byte contains info for consecutive or multiple read/write requests in one.

The MSB (bit 7) of the command byte specifies if the command is a read (0) or write (1). The next bit (bit 6), specifies if consecutive addresses should be read/written (1) or if the same address should be read/written multiple times (0). The 6 LSBs (bits 5-0) represent how many read/write requests should be generated. Note that the number of requests will alway be 1 more than the value of these bits. That means if you want to read or write a single address, they should be set to 0. Setting them to 1 will generate two read or write requests.

If you send a write request, after sending the command byte and address, you continue sending the data to be written. Data is always sent as four bytes per write request and the least significant byte should be sent first.

For reads, after sending the command byte and address, you simply wait for the data to be returned. Data is returned in least significant byte order. Note that you may not always receive all the data you ask for if there is an issue with the FPGA design (i.e. the requested data is never presented, like in our LED example).

Let's take a look at an example.

If you want to write to addresses 5, 6, and 7, you could issue the following request. 0xC2 (1100 0010), 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00. This would write 1 to address 5, 2 to address 6, and 3 to address 7. If you changed the command byte to 0x82 (1000 0010) you would write 1 to address 5, 2 to address 5, and then 3 to address 5 (in that order).

Issuing a read follows the exact same format except the data bytes are received instead of sent.

A single command can generate up to 64 read/write requests. If you need to read/write more, you need to issue separate commands.

Java Example

You can download a working Java example (Eclipse project) by clicking here. This example simply writes 0x12 to address 0, but there is a class to make it easy to perform reads and writes in bulk.