Search code examples
vhdlfpgaintel-fpganios

problems writing to an avalon slave module


I'm woring on a project for an assingment where I need to be able write data to an avalon slave module to select data from 2 different inputs on a nios system running on a DE0 board. After much toiling, I've been unable to write data from the C app running on the nios core to the avalon slave. I have verified that I'm able to read data from the slave by using some hard coded values. I have also verified that my app is running because I'm seeing the messages I expect over the jtag uart, and the push buttons, LEDs and LED display work as expected.

I have simplified my slave so that data I write to it is then read straight back. The VHDL code is:

library ieee;
use ieee.std_logic_1164.all;
USE IEEE.NUMERIC_STD.ALL;

entity FIFO_Control is
    port (clk : IN std_logic; 
            reset : IN std_logic;
            read : IN std_logic; 
            readdata : OUT std_logic_vector(7 DOWNTO 0); 
            write : IN std_logic; 
            writedata : IN std_logic_vector(7 DOWNTO 0);
            din1 : in std_logic_vector(4 DOWNTO 0);
            din2 : in std_logic_vector(4 DOWNTO 0)
            );
end FIFO_Control;


architecture FIFO_CTRL of FIFO_Control is

    signal int_data : std_logic_vector(7 DOWNTO 0) := "00000000"; -- a hard coded test value to check the read works

    begin
        with (write) SELECT
            int_data <= writedata when '1',
                            "01010101" when others;

            readdata <= int_data;


end FIFO_CTRL;

The C code is

#include "sys/alt_stdio.h"
#include <altera_avalon_timer_regs.h>
#include <altera_avalon_pio_regs.h>
#include <system.h>

#include "Sch51.h"

#include "serial.h"

#include "seven_seg.h"

#define SEVEN_SEGMENT_0_BASE 0x1001080
#define LED_BASE (0x01001070)
#define LED0_pin (0x01)
#define LED1_pin (0x01 << 1)
#define LED2_pin (0x01 << 2)
#define LED3_pin (0x01 << 3)

#define PIO_1_BASE 0x0
#define BUTTON_BASE PIO_1_BASE
#define BUTTON0 0x01
#define BUTTON1 0x02

#define FIFO_CTRL_0_BASE 0x1001090

void LED_Flash_Update(void)
{
    static count = 0;
    alt_u8 read;

    IOWR_8DIRECT(FIFO_CTRL_0_BASE, 0, 0);
    read = IORD_8DIRECT(FIFO_CTRL_0_BASE, 0);
    Serial_Printf("FIFO1: %d\r\n", read);

    IOWR_8DIRECT(FIFO_CTRL_0_BASE, 0, 1);
    read = IORD_8DIRECT(FIFO_CTRL_0_BASE, 0);
    Serial_Printf("FIFO1: %d\r\n", read);

   // Change the LED from OFF to ON (or vice versa)
   IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE,
         IORD_ALTERA_AVALON_PIO_DATA(LED_BASE) ^ LED3_pin);

   if (count < 10)
   {
       count++;
   }

   else if ((count >= 10) && (count < 100))
   {
       count += 10;
   }

   else if ((count >= 100) && (count < 1000))
   {
     count += 100;
   }

   else if ((count >= 1000) && (count < 10000))
   {
     count += 1000;
   }

   else
   {
       count = 0;
   }

   seven_seg_store_number(SEVEN_SEGMENT_0_BASE, 0, 9999, 10, count);

   if ((IORD_ALTERA_AVALON_PIO_DATA(BUTTON_BASE) & BUTTON0) == 0)
   {
       IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE,
                IORD_ALTERA_AVALON_PIO_DATA(LED_BASE) | LED0_pin);
   }

   else
   {
       IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE,
                    IORD_ALTERA_AVALON_PIO_DATA(LED_BASE) & ~LED0_pin);
   }

   if ((IORD_ALTERA_AVALON_PIO_DATA(BUTTON_BASE) & BUTTON1) == 0)
   {
       IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE,
                IORD_ALTERA_AVALON_PIO_DATA(LED_BASE) | LED1_pin);
   }

   else
   {
       IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE,
                    IORD_ALTERA_AVALON_PIO_DATA(LED_BASE) &  ~LED1_pin);
   }

}

int alt_main()
{
    alt_u8 read;
    SCH_Init_T0();
    serial_Init();

    SCH_Add_Task(serial_Update, 0, 10);
    SCH_Add_Task(LED_Flash_Update, 0, 1000);

    // Start the scheduler
    SCH_Start();

    Serial_Puts("EHMC AJE System Running\n");

    /* Event loop never exits. */
    while (1)
    {
        SCH_Dispatch_Tasks();
    }

    return 0;
}

I'm not able to see why I'm not able to write anything to the avalon slave "Fifo_control". Can someone suggest what the problem is please?


Solution

  • If you look at the port declarations on your entity/component and then at your code, you can already see that you are doing something wrong, as you are not using all the port.

    So your problem states that you want to write data to your Avalon slave. So you want the component to remember the data you've written (i.e. memory). But there is no memory component in your code. There's just a combinatorial expression.

    When designing an Avalon component, you should read the Avalon Interface Specification.

    So reading the document, you see that you should have a process/statement for the write port and a process for the read port. Each takes a clock cycle to process (if the read latency is 1). E.g.

    write_proc: process(clk) begin
        if rising_edge(clk) then
            if write = '1' then
                int_data <= writedata;
            end if;
            -- reset statement
            if reset = '1' then
                int_data <= (others => '0');
            end if;
        end if;
    end process;
    
    read_proc: process(clk) begin
        if rising_edge(clk) then
            if read = '1' then
                readdata <= int_data;
            end if;
            -- reset statement
            if reset = '1' then
                readdata <= (others => '0');
            end if;
        end if;
    end process;