Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
11 years ago

AVALON MM interface beginners issues

Hi, I'm trying desperately to experience the AVALON MM interface on a Cyclone V SoC FPGA board.

For my interface implementation I have written a control, an input and an output verilog file, as also some C code running on the HPS. Control, Input and Output are joined by QSYS together with a clock, and an HPS component. A top level verilog file connects the .qip to an algorithm verilog file. The actual algorithm will come later (some ready-made IP core). Currently instead of an algorithm, I'm just lighting LEDs: Initially, in state WAITING, led1. When "input" and a "start" signal come from the control verilog file inside the .qip, it should do the transition to WORKING and light another led2. My problem now, is that it does not work - it stays at lighting led1. I tried another example using AVALON MM and it works, so there should not be anything basic such as MSEL setting, etc.

Here are Control, Input and Output, as below the C code I wrote. I left out the toplevel file as also the.. what I call "algorithm" so far.

module avalonmm_control (
    input clk,
    input reset,
    output reg debug_led, // DEBUG
    input       avs_writedata,
    output reg  avs_readdata,
    input        avs_address,
    input             avs_read,
    input             avs_write,
    output algostart,
    output algoreset,
    input  algodone
);
// TODO check out, why we use "reg" here?
reg start_reg;
reg reset_reg;
assign algostart = start_reg; 
assign algoreset = reset_reg; 
always @(posedge clk) begin
    if(avs_write)begin
        case (avs_address)
            2'b00: begin
                reset_reg <= avs_writedata;
                start_reg <= 1'd0;
            end
            2'b01: begin
debug_led = 1'b1; // TODO rm, DEBUGGING
                reset_reg <= 1'd0;
                start_reg <= avs_writedata;
            end
            default: begin
                reset_reg <= 1'd0;
                start_reg <= 1'd0;
            end
        endcase
    end else if (avs_read) begin
        reset_reg <= 1'd0;
        start_reg <= 1'd0;
        case (avs_address)
            2'b00: avs_readdata <= reset_reg;
            2'b01: avs_readdata <= start_reg;
            2'b10: avs_readdata <= algodone; 
            default: avs_readdata <= 1'd0;
        endcase
    end else begin
        reset_reg <= 1'd0;
        start_reg <= 1'd0;
    end
end
endmodule

module avalonmm_input (
    input clk,
    input reset,
    input        avs_write,
    input  avs_writedata,
    input   avs_address,
    output        alg_write,
    output  alg_writedata,
    output   alg_writeaddr
);
assign alg_write = avs_write;
assign alg_writedata = avs_writedata;
assign alg_writeaddr = avs_address;
endmodule

module avalonmm_output (
    input clk,
    input reset,
    input         avs_read,
    output  avs_readdata,
    input    avs_address,
    input   alg_readdata,
    output   alg_readaddr
);
assign avs_readdata = alg_readdata;
assign alg_readaddr = avs_address;
endmodule

I'm currently trying to light an additional debugging led, on any input, and leave it light - without any success. Either it stays always on or is always off. It seems as if "avs_write" is always true, already in the beginning. As C code, I wrote the following..

#include <stdlib.h># include <stdio.h># include <string.h> // memset()# include <stdint.h> // uint8_t, etc.# include <sys/mman.h># include <sys/types.h># include <sys/stat.h># include <fcntl.h># include <unistd.h># include <errno.h>    
/*******************************************************************************/
# define INPUT_OFFSET 0x0# define OUTPUT_OFFSET 0x800# define CONTROL_OFFSET 0xa00# define INPUT_SIZE 16  # define OUTPUT_SIZE 16  # define PAGE_SIZE sysconf(_SC_PAGESIZE)# define LWHPS2FPGA_BASE 0xff200000# define SEQUENCE_SIZE 16
/*******************************************************************************/
typedef struct fpgactrl{
        void *mem;
    volatile uint32_t *input;
    volatile uint32_t *output;
    volatile uint32_t *control;
    /*
      control states / orders configured in FPGA:
          2'b00 - reset
          2'b01 - start
          2'b10 - done
     */
    int fd;
} fpgactrl_t;
typedef fpgactrl_t* fpgactrl_p;
typedef struct sequence{
    int size;
    uint8_t sequence;
} sequence_t;
typedef sequence_t* sequence_p;
/*******************************************************************************/
int fpga_init(struct fpgactrl* fpga)
{
    if (0 > (fpga->fd = open("/dev/mem", O_RDWR))) {
        fprintf(stderr, "FAILED, %s : fpga->fd < 0\n", __FILE__, __LINE__);
        return -1; // FAIL
    }
    if (MAP_FAILED == (fpga->mem = mmap(NULL, PAGE_SIZE
                        , PROT_READ | PROT_WRITE, MAP_SHARED
                        , fpga->fd, LWHPS2FPGA_BASE))) {
        perror("FAILED");
        fprintf(stderr, "%s : MAP_FAILED == (fpga->mem = mmap(...))\n", __FILE__, __LINE__);
        close(fpga->fd);
        return -1; // FAIL
    }
    fpga->input = fpga->mem + INPUT_OFFSET;
    fpga->output = fpga->mem + OUTPUT_OFFSET;
    fpga->control = fpga->mem + CONTROL_OFFSET;
    return 0; // OK
}
void fpga_reset(struct fpgactrl* fpga)
{
    fpga->control |= 0x1;
    while (fpga->control & 0x1) ;
}
void fpga_start(struct fpgactrl* fpga)
{
    fpga->control |= 0x1;
    while (fpga->control & 0x1) ;
    fprintf(stderr, "XXX: fpga started\n");    // the message comes
}
void fpga_done(struct fpgactrl* fpga)
{
    while ((fpga->control) & 0x1) ;
}
void fpga_copy_input(struct fpgactrl* fpga, uint8_t* input)
{
    int idx;
    for (idx=0; idx<INPUT_SIZE; ++idx) {
        fpga->input = (uint32_t*) input;
    }
}
void fpga_copy_output(struct fpgactrl* fpga, uint8_t* output)
{
    int idx;
    for( idx=0; idx < OUTPUT_SIZE; ++idx){
        output = (uint8_t*) fpga->output;
    }
}
void fpga_release(struct fpgactrl* fpga)
{
    munmap(fpga->mem, PAGE_SIZE);
    close(fpga->fd);
}
void sequence_init(struct sequence* seq)
{
    seq->size = 0;
    seq->size = SEQUENCE_SIZE; // static array!
    memset(seq->sequence, '\0', seq->size);
}
void sequence_init_text(struct sequence* seq)
{
    sequence_init(seq);
    memset(seq->sequence, '1', SEQUENCE_SIZE);
}
/*******************************************************************************/
int main(int argc, char* argv){
    fpgactrl_t fpga;
    fpgactrl_p ptr_fpga = &fpga;
    sequence_t seq_input, seq_output;
    sequence_p input = &seq_input;
    sequence_p output = &seq_output;
        fprintf(stderr, "init fpga\n");
    if (fpga_init(ptr_fpga)) {
        fprintf(stderr, "FAILED: initialization of fpga controller\n");
        exit(EXIT_FAILURE);
    }
        fprintf(stderr, "set up input\n");
    sequence_init(output);
    sequence_init_text(input);
        fprintf(stderr, "reset fpga\n");
    fpga_reset(ptr_fpga);
        fprintf(stderr, "copy input to fpga\n");
    fpga_copy_input(ptr_fpga, input->sequence);
        fprintf(stderr, "start fpga process\n");
    fpga_start(ptr_fpga);
        fprintf(stderr, "wait for done\n");
    fpga_done(ptr_fpga);
        fprintf(stderr, "copy output from fpga\n");
    fpga_copy_output(ptr_fpga, output->sequence);
        fprintf(stderr, "results: '%s'\n", output->sequence);
    fpga_release(ptr_fpga);
    fprintf(stderr, "READY.\n");
    exit(EXIT_SUCCESS);
}

I kept away the top level and the "algorithm" verilog. The already printed should be boring enough. Anyway, I'm not very positive that anyone really will have the patience to understand my post and read up till here. If YOU did so - I already thank you a lot!!!

Questions:

1. Where can I check by setting an LED if the FPGA is receiving any input, and then that it has input and has received the "start"?

2. Is there any obvious error?

3. What techniques I may use in quartus to debug this? I'm using quartus II web edition, I don't have any license, and no experience in working with oscilloscopes :(

ANY help is appreciated!

3 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    There is a nice tool called SignalTap in Quartus II for debugging such problems. Just add signals of interest and clock, setup the trigger and check, what's happening in your logic or on the Avalon bus. It will be more efficient than guessing and playing with LEDs for sure!

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi, thank you - I solved my issue(s)! Finally, it seems that I had something wrong in my C code. I figured it out commenting out all C instructions and executing line by line, adjusted all type lengths cleanly, and figured out some related issue.

    The hint with SignalTap was awesome, though. I read through ftp://ftp.altera.com/up/pub/altera_material/13.1/tutorials/verilog/signaltap.pdf (ftp://ftp.altera.com/up/pub/altera_material/13.1/tutorials/verilog/signaltap.pdf) for my Quartus II 13.1. Since I'm new to logic analyzers I still don't get quite, how the "triggers" actually work?! What is the difference between setting them on '1' or '0', or rising, falling, either rising and falling, or "don't care", respectively. Rarely I see really edges, but already seeing what is "set" and what not, helps me already. Currently I do single runs before, then execute the .c code, and do another single run. I don't see edges, but already helpful highs or lows.

    I really thought I'll need a special license for it, but it was just connecting the talk-back-feature in fact. For university purpose, just perfect! Great!!!
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    After occurrence of trigger condition SignalTap brings you the sample points. You can set SignalTap to see what's happening after the trigger condition, before trigger condition or simply have trigger in the middle of sampled points.