Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Создание компонета для SOPC Builder с несколькими регистрами ввода/вывода
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Системы на ПЛИС - System on a Programmable Chip (SoPC)
altlogic
Здравствуйте!

Простая по идее задача - хочу созадать свой компонент I2C для SOPC с возможностью конфигурирования его через внутренние регистры компонента (да хотя бы флаг RUN реализоватьsm.gif ). Как это сделать? Нашел на сайте Altera пример Memory Mapped Slave. В этом шаблоне у устройства задается использование 16 внутренних регистров. Но там мощный шаблон, на 700 сток кода. Я аж испугалсяsm.gif
А мне кажется можно это все сделать проще. Ведь всего лишь нужно вытянуть из SOPC информацию о том, по какому адресу он разместил внутренние регистры устройства, ну и сделать их программно доступными конечо с шины Avalon. Примеров других пока не разбирал. Но мне кажется моя задача должна встречаться у всех разработчиков периферии под процессор для FPGA. Товарищ показал код для Xilinx MicroBlaze в аналогичной ситуации. Там, как и в примере Altera в описании компонента применяется специальная нотация.

Смотрел IP-core I2C от Terasic. Там, как я понял используется несколько отдельных регистров ввода-вывода, то есть устройство состоит из нескольких устройств на шине Авалон. Видимо это вообще самое простое решение. Но ведь как-то некрасиво?..
Konst_777
Цитата(altlogic @ Jul 25 2012, 09:23) *
...Смотрел IP-core I2C от Terasic...

Возможно, для Вас будет интересным IP-core I2C с alterawiki.com.Там как раз обновили этот компонент для Quartus 12.
altlogic
Спасибо, буду иметь ввиду. Надо поковырять этот модуль, чтобы посмотреть прицнип управления.
barabek
Цитата(altlogic @ Jul 26 2012, 12:05) *
Спасибо, буду иметь ввиду. Надо поковырять этот модуль, чтобы посмотреть прицнип управления.

Могу свой дать посмотреть. Конечно документации нет, но в подключаемом файле I2C_component_regs.h назначение регистров описано.

И прошу прощения за мой английский sm.gif
Orochi
Я учился работать с регистрами анализируя код этого компонента (файл прилагается). Всё с коментариями, даже с таблицами (карты регистров). Посмотрите, там всё понятно изложено.
Acvarif
Цитата(Orochi @ Jul 30 2012, 23:00) *
Я учился работать с регистрами анализируя код этого компонента (файл прилагается). Всё с коментариями, даже с таблицами (карты регистров). Посмотрите, там всё понятно изложено.


Пытаюсь на базе данного компонента разобраться как из регистров пользовательской логики переносить данные на шину Авалон.
Для начала из верхнеуровневого модуля sd_controller.v в SOPC создаю компонент. В компоненте кроме сигналов Авалон шины имеются сигналы интерфейса SPI ( spi_data_out,
spi_data_in,
spi_cs_n,
spi_clk
).
Нажмите для просмотра прикрепленного файла
Не пойму почему при создании компонента эти сигналы попадают опять на шину Авалон (avalon_slave_1)? Как при создании компонента на базе данного модуля оставить SPI сигналы просто пользовательской логикой?
Копейкин
Сигналы, идущие наружу должны иметь тип интерфейса Conduit, а не Avalon Memory Mapped Slave, как у Вас.
Orochi
Вот как подключен этот этот компонент у меня. avalon_slave_export type: conduit (как раз внешняя логика).

P.S.: Если не ответил на вопрос предыдущего поста переформулируйте и поподробней)
Acvarif
Цитата(Orochi @ Aug 13 2012, 20:15) *
Вот как подключен этот этот компонент у меня. avalon_slave_export type: conduit (как раз внешняя логика).

P.S.: Если не ответил на вопрос предыдущего поста переформулируйте и поподробней)

Спасибо. Все получилось. У меня Q9. Поэтому только Conduit.
Нажмите для просмотра прикрепленного файла
Теперь на базе Вашего примера представляется возможным написать (vhdl) логику переноса данных из двухпортовой памяти на шину Avalon.
Пока не до конца понимаю процессы чтения и записи из(в) процессора в(из) ram. Попробую выполнить диаграмму
Нажмите для просмотра прикрепленного файла
Непонятна вкладка Deprecated
Копейкин
Deprecated-параметрами не следует пользоваться.
Это параметры, которые уже не имеют значения (для совместимости с предыдущими версиями)
или будут отменены в будущих версиях Квартуса.
Например адресация DYNAMIC/NATIVE, по умолчанию =DYNAMIC.
Ваша программа должна использовать макросы доступа к регистрам для соответствующего типа адресации.
Альтера настоятельно рекомендует пользоваться динамической адресацией.
Acvarif
Создал компонент Avalon MM Slave с пользовательской логикой.
В качестве пользовательской логики двухпортовая RAM куда с помощью
внешней кнопки загружаются 4 слова данных с последующим тестом чтения (для просмотра на wavwform) в
соответствии с диаграммой работы двухпортовой памяти.
Вот верхний уровень
CODE
--------------------------------------------------------------------
-- Project : ramtest
--------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.numeric_std.all;

entity ramtest is
port (
-- Avalon Slave
clk : in std_logic := '0'; -- clock.clk
reset_n : in std_logic := '0'; -- .reset_n
avs_s0_address : in std_logic_vector(1 downto 0) := (others => '0'); -- s0.address
avs_s0_read_n : in std_logic := '0'; -- .read_n
avs_s0_readdata : out std_logic_vector(15 downto 0); -- .readdata
avs_s0_write_n : in std_logic := '0'; -- .write_n
avs_s0_writedata : in std_logic_vector(15 downto 0) := (others => '0'); -- .writedata
avs_s0_chipselect : in std_logic := '1'; -- .chipselect
-- ins_irq0_irq : out std_logic;

-- RAM Exports
-- Вспомогательные сигналы (тест загрузки и чтения RAM)
ldrd : in std_logic := '1'; -- внешний старт записи-чтения RAM (от кнопки)
ram_load : out std_logic; -- старт загрузки RAM (для теста)
ram_wr : out std_logic; -- строб записи RAM
ram_rd : out std_logic; -- строб чтения RAM
ram_ld : out std_logic; --
ram_wt : out std_logic; --
cnt_out : out std_logic; --
ram_read : out std_logic; -- старт чтение RAM (для теста)
ram_data_in : out std_logic_vector(15 downto 0); -- входные данные RAM (для теста)
ram_data_out : out std_logic_vector(15 downto 0) -- выходные данные RAM (для теста)
);

end entity ramtest;

architecture rtl of ramtest is

--------------------------------------------------------------------
-- компонент двухпортовая RAM

component ramresult
generic
(
DATA_WIDTH : integer := 16;
ADDR_WIDTH : integer := 2
);

port
(
rclk : in std_logic;
wclk : in std_logic;
raddr : in std_logic_vector (0 to ADDR_WIDTH - 1);
waddr : in std_logic_vector (0 to ADDR_WIDTH - 1);
data : in std_logic_vector((DATA_WIDTH-1) downto 0);
we : in std_logic := '1';
q : out std_logic_vector((DATA_WIDTH -1) downto 0)
);
end component;

-- сигналы загрузки и теста чтения RAM
signal cnt : std_logic_vector(3 downto 0) := X"0"; -- делитель
signal s_data_in : std_logic_vector(15 downto 0) := X"0000"; -- данные RAM (вход)
signal s_data_out : std_logic_vector(15 downto 0); -- данные RAM (выход)
signal s_rd : std_logic; -- клок чтения из RAM
signal s_wr : std_logic; -- клок записи в RAM
signal s_we : std_logic := '1'; -- выбор кристалла
signal s_addr_rd_ram : std_logic_vector(1 downto 0); -- адрес чтения
signal s_addr_wr_ram : std_logic_vector(1 downto 0); -- адрес записи
signal en_loadcnt : std_logic := '0'; -- разрешение загрузки в RAM
signal en_readcnt : std_logic := '0'; -- разрешение чтения из RAM
signal s_lrcnt : std_logic_vector(5 downto 0) := "000000"; -- счетчик
signal s_ramload : std_logic := '1'; --
signal s_ramread : std_logic := '1'; --
signal en_wrrd : std_logic := '0'; --

-- сигналы для шины Avalon
signal avs_s0_readdata_reg : std_logic_vector(15 downto 0);

begin

uramresult : ramresult
generic map (16, 2)
port map (rclk => s_rd, wclk => s_wr, raddr => s_addr_rd_ram,
waddr => s_addr_wr_ram, data => s_data_in, we => s_we, q => s_data_out);

--------------------------------------------------------------------
-- Вспомогательные сигналы
--------------------------------------------------------------------
--
process(clk)
begin
if (rising_edge(clk)) then
cnt <= cnt + 1;
end if;
end process;

cnt_out <= cnt(0);

process(cnt(0))
begin
if (rising_edge(cnt(0))) then
if(ldrd = '0') then
en_wrrd <= '1';
end if;
if(en_wrrd = '1') then
s_lrcnt <= s_lrcnt + 1;
end if;
if (s_lrcnt = "000011") then
s_ramload <= '0';
elsif (s_lrcnt = "000101") then
s_ramload <= '1';
elsif (s_lrcnt = "001011") then
s_ramread <= '0';
elsif (s_lrcnt = "001101") then
s_ramread <= '1';
elsif (s_lrcnt = "101101") then
en_wrrd <= '0';
end if;
end if;
end process;

ram_ld <= s_ramload;
ram_wt <= s_ramread;

--------------------------------------------------------------------
-- Заполнение RAM
--------------------------------------------------------------------

-- старт стоп перебора адресов RAM
process(cnt(0))
begin
if (falling_edge(cnt(0))) then
if(s_ramload = '0') then
en_loadcnt <= '1';
end if;
if(en_loadcnt = '1') then
s_addr_wr_ram <= s_addr_wr_ram + 1;
else
s_addr_wr_ram <= (others => '0');
end if;
if(s_addr_wr_ram = "11") then
en_loadcnt <= '0';
end if;
end if;
end process;

ram_load <= en_loadcnt;
s_wr <= not((cnt(0) and en_loadcnt) and (not clk));
ram_wr <= s_wr;

-- загрузка RAM
process(cnt(0))
begin
if (rising_edge(cnt(0))) then
if(en_loadcnt = '1') then
if(s_addr_wr_ram = "00") then
s_data_in <= X"0102";
elsif(s_addr_wr_ram = "01") then
s_data_in <= X"0304";
elsif(s_addr_wr_ram = "10") then
s_data_in <= X"0506";
elsif(s_addr_wr_ram = "11") then
s_data_in <= X"0708";
end if;
end if;
end if;
end process;

ram_data_in <= s_data_in;

--------------------------------------------------------------------
-- Чтение RAM (для тестирования)
--------------------------------------------------------------------

-- старт стоп перебора адресов RAM
process(cnt(0))
begin
if (falling_edge(cnt(0))) then
if(s_ramread = '0') then
en_readcnt <= '1';
s_we <= '0';
end if;
if(en_readcnt = '1') then
s_addr_rd_ram <= s_addr_rd_ram + 1;
end if;
if(s_addr_rd_ram = "11") then
en_readcnt <= '0';
s_we <= '1';
end if;
end if;
end process;

ram_read <= en_readcnt;
s_rd <= cnt(0) and en_readcnt;
ram_rd <= s_rd;
ram_data_out <= s_data_out;

--------------------------------------------------------------------
-- Avalon slave register read logic
--------------------------------------------------------------------
process(clk)
begin
if (falling_edge(clk)) then
if(reset_n = '0') then
avs_s0_readdata_reg <= (others => '0');
else if(avs_s0_read_n = '0' and ) then
avs_s0_readdata_reg <= s_data_out;
end if;
end if;
end if;
end process;

avs_s0_readdata <= avs_s0_readdata_reg;

end architecture rtl; -- of ramtest

Вот двухпортовая RAM
CODE
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity ramresult is

generic
(
DATA_WIDTH : natural := 16;
ADDR_WIDTH : natural := 2
);

port
(
rclk : in std_logic;
wclk : in std_logic;
raddr : in std_logic_vector (0 to ADDR_WIDTH - 1);
waddr : in std_logic_vector (0 to ADDR_WIDTH - 1);
data : in std_logic_vector((DATA_WIDTH-1) downto 0);
we : in std_logic;
q : out std_logic_vector((DATA_WIDTH -1) downto 0)
);

end ramresult;

architecture behavioural of ramresult is

-- Build a 2-D array type for the RAM
subtype word_t is std_logic_vector((DATA_WIDTH-1) downto 0);
type memory_t is array(2**ADDR_WIDTH-1 downto 0) of word_t;

-- Declare the RAM signal.
signal ram : memory_t;

begin

process(wclk)
begin
if(falling_edge(wclk)) then
ram(conv_integer(waddr)) <= data;
end if;
end process;

process(rclk)
begin
if(rising_edge(rclk)) then
if(we = '0') then
q <= ram(conv_integer(raddr));
else
q <= (others => 'Z');
end if;
end if;
end process;

end behavioural;

Вот Waveform
Нажмите для просмотра прикрепленного файла
Далее ступор.
Не понимаю как теперь построить логику переноса данных из этой же RAM на шину Avalon
имея набор только этих сигналов
Нажмите для просмотра прикрепленного файла
Очевидно нужен промежуточный регистр между выходом RAM и Avalon.
Кому приходилось с этим сталкиваться подскажите please как примерно это должно выглядеть в коде (Avalon slave register read logic).
Если не в коде, то словах тоже думаю пойму.
Копейкин
Я не силён в VHDL, пишу на Verilog, но
1) Выходной шине данных для шины Авалон не нужно 3 (Z) состояние.
Авалон - шина мультиплексор.
Промежуточный регистр ставить не нужно.
2) Порт памяти подключеный к Nios должен тактироваться частотой Nios, в противном случае пользовать Clock Crossing Bridge.
В чём затруднение пользования сигналов Авалон?
Советую найти документ mnl_avalon_spec.pdf.
Это подробная спецификация шины Авалон, с диаграммами.
Можно/нужно взять полный набор документации здесь: http://www.altera.com/literature/lit-nio2.jsp для своей версии.
Там же будет и спецификация.

Вот мой пример чтения регистров компонента, сигнал чтения не использую:
CODE
//-------------------------------------------------------------------
// Read all internal registers management
// Avalon MM slave read signal used only for FIFO access
//
//
always @ (posedge clk)
begin
case( avs_s0_address[7:0] )
DATA_REGISTER: avs_s0_readdata[31:0] <= { 24'b0, fifo_rx_data }; // DATA FIFO RAM
CONTROL_REGISTER: avs_s0_readdata[31:0] <= { 16'b0, control[15:0] }; // All bits of control register
STATUS_REGISTER: avs_s0_readdata[31:0] <= { 16'b0, status }; // All bits of status register
INDEX_REGISTER: avs_s0_readdata[31:0] <= { 24'b0, 2'b0, respond[45:40] }; // Respond index
RESPOND_REGISTER: avs_s0_readdata[31:0] <= respond[39:8]; // card status (R1), OCR(R3), RCA(R6)
(RESPOND_REGISTER+1): avs_s0_readdata[31:0] <= respond[71:40]; // CID CSD access
(RESPOND_REGISTER+2): avs_s0_readdata[31:0] <= respond[103:72]; // CID CSD access
(RESPOND_REGISTER+3): avs_s0_readdata[31:0] <= respond[135:104]; // CID CSD access
default: avs_s0_readdata[31:0] <= { 24'b0, status[7:0] }; // default bus state
endcase
end
//-------------------------------------------------------------------------


Описание доступа:
CODE

/************************************************************************
* DYNAMIC address mode
* BYTE address of register must be used
************************************************************************/

//-------------------------------------------------------------------------------------------------
// Data buffer read / write have separate FIFO buffers 512 bytes depth
#define IOADDR_ALTERA_AVALON_SD_HOST_DATA(base) __IO_CALC_ADDRESS_DYNAMIC(base, 0)
#define IORD_ALTERA_AVALON_SD_HOST_DATA(base) IORD_32DIRECT(base, 0)
#define IOWR_ALTERA_AVALON_SD_HOST_DATA(base, data) IOWR_32DIRECT(base, 0, data)


//-------------------------------------------------------------------------------------------------
// Control register may be read/write
#define IOADDR_ALTERA_AVALON_SD_HOST_CONTROL(base) __IO_CALC_ADDRESS_DYNAMIC(base, 4)
#define IORD_ALTERA_AVALON_SD_HOST_CONTROL(base) IORD_32DIRECT(base, 4)
#define IOWR_ALTERA_AVALON_SD_HOST_CONTROL(base, data) IOWR_32DIRECT(base, 4, data)

Acvarif
Спасибо. Попробую разобраться.
Если примитивно то получается что-то вроде этого
CODE
process(clk)
begin
if (falling_edge(clk)) then
if(reset_n = '0') then
avs_s0_readdata_reg <= (others => '0');
else if(avs_s0_read_n = '0' and avs_s0_chipselect = '0') then
case (avs_s0_address) is
when "00" => avs_s0_readdata_reg(0) <= s_data_out(0);
when "01" => avs_s0_readdata_reg(1) <= s_data_out(1);
when "10" => avs_s0_readdata_reg(2) <= s_data_out(2);
when "11" => avs_s0_readdata_reg(3) <= s_data_out(3);
end case;
end if;
end if;
end if;
end process;

avs_s0_readdata <= avs_s0_readdata_reg;

Тоесть при появлении со стороны Nios сигналов avs_s0_address, avs_s0_read_n, avs_s0_chipselect
по спаду clk данные с выхода RAM должны появиться на шине Avalon.
Но что теперь делать с сигналами управления RAM?
Тупо подать avs_s0_address - на адрес RAM, avs_s0_chipselect - на выбор кристалла RAM?
Да...в общих чертах понятно.
Используя сигналы Avalon нужно сформировать импульсы которые будут управлять чтением RAM так,
чтобы данные из нее появлялись на шине в нужные моменты (в соответствии с диаграммой чтения созданного компонента).
Думаю, что справлюсь.

По ходу еще вопрос.
Как в общих чертах организовать чтение данных RAM (каждого отдельного байта) по прерываниям идущим от пользовательской логики?
Копейкин
Для чтения/записи отдельного байта следует использовать сигналы (для 32-разрядной шины) byteenable[3:0].
В реализации RAM также следует предусмотреть доступ к единичному байту.
Если это невозможно, то читать 32бита из которых брать требуемый байт - это несложно.
Вот для записи будет последовательность чтение слова - модификация байта - запись слова.
Acvarif
Цитата(Копейкин @ Aug 20 2012, 12:18) *
Для чтения/записи отдельного байта следует использовать сигналы (для 32-разрядной шины) byteenable[3:0].
В реализации RAM также следует предусмотреть доступ к единичному байту.
Если это невозможно, то читать 32бита из которых брать требуемый байт - это несложно.
Вот для записи будет последовательность чтение слова - модификация байта - запись слова.


Для визуализации работы команды IORD(base, 1) (чтение по базовому адресу + 1 компонента ramtest )
вывел команду avs_s0_read_n через буфер наружу надеясь увидеть импульс чтения. Но ничего нет.
Непонятно какой из сигналов Avalon
Код
    port (
--        Avalon Slave
        clk                  : in  std_logic                     := '0';             -- clock.clk
        reset_n              : in  std_logic                     := '0';             --      .reset_n
        avs_s0_address       : in  std_logic_vector(1 downto 0)  := (others => '0'); --    s0.address
        avs_s0_read_n        : in  std_logic                     := '0';             --      .read_n
        avs_s0_readdata      : out std_logic_vector(15 downto 0);                    --      .readdata
        avs_s0_write_n       : in  std_logic                     := '0';             --      .write_n
        avs_s0_writedata     : in  std_logic_vector(15 downto 0) := (others => '0'); --      .writedata

можно вживую наблюдать при выполнении операции чтения IORD(base, 1) из Nios если в моем компоненте с Avalon MM Slave нет byteenable?
Копейкин
Макро IORD(base, n) применяется при адресации типа NATIVE
Если адресация DYNAMIC (рекомендованая), то макро IORD32_DIRECT(BASE, OFFSET)
см. файл project_bsp\HAL\io.h там описываются эти макросы.
Адрес пользуешь из system.h?
Сигнал чтения должен активироваться.
Смотришь через SignalTap? Советую его пользовать.
Acvarif
Цитата(Копейкин @ Aug 20 2012, 14:48) *
Макро IORD(base, n) применяется при адресации типа NATIVE
Смотришь через SignalTap? Советую его пользовать.


SignalTap загружает проект. Хотелось бы увидеть сигналы вживую.

Поставил
Код
#define IORD_ALTERA_AVALON_RAM_1(base)  IORD_16DIRECT(base, 1);

В основном цикле просто читаю RAM
Код
ramres=IORD_ALTERA_AVALON_RAM_1(RAMTEST_0_BASE);

Цитата
Адрес пользуешь из system.h?
Сигнал чтения должен активироваться.

Да, адрес компонента (system.h)
CODE
#define RAMTEST_0_NAME "/dev/ramtest_0"
#define RAMTEST_0_TYPE "ramtest"
#define RAMTEST_0_BASE 0x00000010
#define RAMTEST_0_SPAN 8
#define RAMTEST_0_TERMINATED_PORTS ""
#define ALT_MODULE_CLASS_ramtest_0 ramtest

Если у меня на Avalon MM Slave
CODE
port (
-- Avalon Slave
clk : in std_logic := '0'; -- clock.clk
reset_n : in std_logic := '0'; -- .reset_n
avs_s0_address : in std_logic_vector(1 downto 0) := (others => '0'); -- s0.address
avs_s0_read_n : in std_logic := '0'; -- .read_n
avs_s0_readdata : out std_logic_vector(15 downto 0); -- .readdata
avs_s0_write_n : in std_logic := '0'; -- .write_n
avs_s0_writedata : in std_logic_vector(15 downto 0) := (others => '0'); -- .writedata
avs_s0_chipselect : in std_logic := '0'; -- .chipselect

то какой из портов можно наблюдать на осциляторе (если вывести его наружу) при выполнении команды IORD_ALTERA_AVALON_RAM_1(RAMTEST_0_BASE)?
Никак не пойму почему простая команда, например IORD_16DIRECT(base, 1) со стороны Nios не активирует ни один из сигналов Avalon MM Slave?
Копейкин
Вы должны увидеть активацию сигналов
avs_s0_read_n (активный 0 ?) и
avs_s0_chipselect (активный 1 ?)

Уже при 50MHz тактовой частоты нужен хороший осциллограф, чтобы увидеть импульсы,
поэтому я и рекомендовал SignalTap.
--------
#define RAMTEST_0_BASE 0x00000010
Подозрительно маленький адрес. Автораспределение адресов в SOPC builder?
Можно скриншот системы, c соединениями шин?
Acvarif
Цитата(Копейкин @ Aug 20 2012, 16:36) *
Вы должны увидеть активацию сигналов
avs_s0_read_n (активный 0 ?) и
avs_s0_chipselect (активный 1 ?)

Уже при 50MHz тактовой частоты нужен хороший осциллограф, чтобы увидеть импульсы,
поэтому я и рекомендовал SignalTap.
--------
#define RAMTEST_0_BASE 0x00000010
Подозрительно маленький адрес. Автораспределение адресов в SOPC builder?
Можно скриншот системы, c соединениями шин?

Понял. Спасибо.
Активация имеется.
Хорошо, как тогда активировать-деактивировать сигналы программно в цикле? (чтобы увидеть что процесс работает)
Нажмите для просмотра прикрепленного файла
С памятью что-то пока не выходит. Попробую создать простой компонент Avalon MM Slave с одним регистром для чтения.
При компиляции проекта в Nios создается файл alt_sys_init.c в котором имеется
Код
ETH_OCM_INSTANCE( ETH_OCM_0, eth_ocm_0 );
ALTERA_AVALON_UART_INSTANCE( UART_0, uart_0 );
ALTERA_AVALON_TIMER_INSTANCE( TIMER_0, timer_0 );
//RAMTEST_INSTANCE( RAMTEST_0, ramtest_0 );
//SD_CONTROLLER_INSTANCE( SD_CONTROLLER_0, sd_controller_0 );

/*
* Initialise the devices
*
*/

void alt_sys_init( void )
{
    ALTERA_AVALON_TIMER_INIT( TIMER_0, timer_0 );
    ETH_OCM_INIT( ETH_OCM_0, eth_ocm_0 );
    ALTERA_AVALON_UART_INIT( UART_0, uart_0 );
//    RAMTEST_INIT( RAMTEST_0, ramtest_0 );
//    SD_CONTROLLER_INIT( SD_CONTROLLER_0, sd_controller_0 );
}


Строки
Код
//    RAMTEST_INIT( RAMTEST_0, ramtest_0 );
//    SD_CONTROLLER_INIT( SD_CONTROLLER_0, sd_controller_0 );

выдают ошибку. Приходся их комментить.
Откуда это берется и зачем?
Копейкин
Вы имеете в виду, что сигналы avs_s0_read_n & avs_s0_chipselect всегда в активном состоянии?
Если так, то это неправильно.
Может создать простой проект без SD и Ethernet контроллеров и отладить память?

Функции RAMTEST_INIT и SD_CONTROLLER_INIT создаются разработчиком компонентов и
относятся к драйверам компонента (каталоги ..\ip\DevName\HAL\inc , ..\ip\DevName\HAL\src)
Их наличие или отсутствие задаётся в devname_sw.tcl.
Про это есть есть отдельные главы (создание компонентов и драйверов) в документации
NiosII Software Developer's Handbook \ Section2 \ SubChapter7 "Developing Device Driver for HAL".

Еще, у Вас довольно много компонентов на шине, может их следует разделить через pipeline_bridge.
Иначе падает максимальная допустимая частота шины... и возможны всякие чудеса.
У Вас TimeQuest при компиляции не говорит: "Timing requirements not met."?
Acvarif
Цитата(Копейкин @ Aug 20 2012, 19:51) *
Вы имеете в виду, что сигналы avs_s0_read_n & avs_s0_chipselect всегда в активном состоянии?
Если так, то это неправильно.
Может создать простой проект без SD и Ethernet контроллеров и отладить память?

Я поторопился. По поводу активации надо будет еще проверить.
CD уберу. Ethernet не мешает.
Цитата
У Вас TimeQuest при компиляции не говорит: "Timing requirements not met."?
С этим все впорядке.

Код
Функции RAMTEST_INIT и SD_CONTROLLER_INIT создаются разработчиком компонентов и
относятся к драйверам компонента (каталоги ..\ip\DevName\HAL\inc , ..\ip\DevName\HAL\src)
Их наличие или отсутствие задаётся в devname_sw.tcl.
Про это есть есть отдельные главы (создание компонентов и драйверов) в документации
NiosII Software Developer's Handbook \ Section2 \ SubChapter7 "Developing Device Driver for HAL".
Спасибо. Все понятно. Значит перед компиляцией можно закомментить даже в sd_controller_sw.tcl и др.
Типа:
Код
# Initialize the driver in alt_sys_init()
# set_sw_property auto_initialize true

Попробую упростить компонент и проект...
Acvarif
Вроде получилось.
Для того, чтобы пронаблюдать на осцилляторе сигналы чтения avs_s0_read_n, avs_s0_chipselect
пришлось их просто затянуть, примерно так
CODE
process(clk)
begin
if (falling_edge(clk)) then
if(avs_s0_read_n = '0') then
avs_s0_read_n_ext_reg <= '0';
avs_s0_read_n_ext_fl <= '1';
end if;
if(avs_s0_read_n_ext_fl = '1') then
avs_s0_read_n_ext_cnt <= avs_s0_read_n_ext_cnt + 1;
end if;
if(avs_s0_read_n_ext_cnt = "11111111") then
avs_s0_read_n_ext_fl <= '0';
avs_s0_read_n_ext_reg <= '1';
end if;
if(avs_s0_chipselect = '1') then
avs_s0_chipselect_ext_reg <= '1';
avs_s0_chipselect_ext_fl <= '1';
end if;
if(avs_s0_chipselect_ext_fl = '1') then
avs_s0_chipselect_ext_cnt <= avs_s0_chipselect_ext_cnt + 1;
end if;
if(avs_s0_read_n_ext_cnt = "11111111") then
avs_s0_chipselect_ext_fl <= '0';
avs_s0_chipselect_ext_reg <= '0';
end if;
end if;
end process;

-- внешний контроль сигналов
avs_s0_read_n_ext <= avs_s0_read_n_ext_reg;
avs_s0_chipselect_ext <= avs_s0_chipselect_ext_reg;

При этом IORD и IORD_32DIRECT внешне (по сигналам avs_s0_read_n, avs_s0_chipselect) работают одинаково
Теперь остается прописать нормальный механизм чтения данных на Avalon MM Slave из пользовательской двухпортовой памяти .
Можно в нескольких словах, как организовать механизм чтения по прерыванию от пользовательской логики?
Копейкин
Добавляете интерфейс Interrupt sender.
У Вас добавится прерывание, которое в SOPC билдере нужно будет подключить к процессору.
В пользовательской логике предусмотреть посылку прерывания уровнем или импульсом.
Чтение/запись как обычно Avalon MM...
Acvarif
Цитата(Копейкин @ Aug 21 2012, 13:35) *
Добавляете интерфейс Interrupt sender.
У Вас добавится прерывание, которое в SOPC билдере нужно будет подключить к процессору.
В пользовательской логике предусмотреть посылку прерывания уровнем или импульсом.
Чтение/запись как обычно Avalon MM...

Спасибо. Получилось
Нажмите для просмотра прикрепленного файла
Чем может грозить предупреждение?
Warning: cpu_0.data_master/ramtest_0.s0: ramtest_0.s0 does not have byteenables. Narrow (less than 32-bit) writes from cpu_0.data_master will result in spurious writes to ramtest_0.s0

Acvarif
Почитал немного букварь "Avalon Interface Specification".
Прописал нормально механизм чтения из RAM на Avalon.
Чтение из RAM пошло.
Но пока какая-то путаница с адресами.
Если я определяю
Код
#define IORD_ALTERA_AVALON_RAM_0(base)  IORD_16DIRECT(base, 0);
#define IORD_ALTERA_AVALON_RAM_1(base)  IORD_16DIRECT(base, 1);
#define IORD_ALTERA_AVALON_RAM_2(base)  IORD_16DIRECT(base, 2);
#define IORD_ALTERA_AVALON_RAM_3(base)  IORD_16DIRECT(base, 3);

то надеюсь, что IORD_ALTERA_AVALON_RAM_0(base) прочитает данные по базовому адресу без смещения (по нулевому адресу RAM) - таки так оно и есть.
далее надеюсь, что IORD_ALTERA_AVALON_RAM_1(base) прочитает данные по адресу базовый плюс 1- а реально читаются данные опять по нулевому адресу RAM.
И только IORD_ALTERA_AVALON_RAM_2(base) читает данные по первому адресу RAM. IORD_ALTERA_AVALON_RAM_3(base) тоже читает данные по первому адресу RAM.
В чем тут хитрость?
Копейкин
Предупреждение предупреждает (о как), что устройство не имеет сигнала выбора байта и поэтому,
при записи данных шириной меньше полного слова будут изменены соседние байты.
Почитайте про режимы адресации.
Авалон будет читать целое слово, в вашем случае шириной 32 бита.
Поэтому чтение со смещением в 2 байта, приведёт к чтению всё того же 32-битного слова.
Acvarif
Цитата(Копейкин @ Aug 22 2012, 16:31) *
Предупреждение предупреждает (о как), что устройство не имеет сигнала выбора байта и поэтому,
при записи данных шириной меньше полного слова будут изменены соседние байты.
Почитайте про режимы адресации.
Авалон будет читать целое слово, в вашем случае шириной 32 бита.
Поэтому чтение со смещением в 2 байта, приведёт к чтению всё того же 32-битного слова.

Спасибо. Понял.
Чтение заработало нормально.
Перешел к прерываниям (от внешней кнопки).
Прерывание срабатывает, но на нем и виснет (не выходит из подпрограммы прерываний)
По аналогии с микроконтроллерами полагал, что какой-то флаг прерывания должен автоматом сброситься при входе в обработчик.
Получается не не так.
Если в двух словах, то как?

Копейкин
Нет, автоматом не сбрасывается.
Ты должен иметь свой триггер, который устанавливается железом
и сбрасывается программой (например, чтением регистра).
Acvarif
Цитата(Копейкин @ Aug 22 2012, 18:24) *
Нет, автоматом не сбрасывается.
Ты должен иметь свой триггер, который устанавливается железом
и сбрасывается программой (например, чтением регистра).

Спасибо. Понял.
Читаю мануалы. Пытаюсь найти простейший пример (программный и аппаратный) реализации обработки прерывания от
пользовательской логики. Пока ничего путного не нашел.
Также не ясен момент (нигде пока не нашел) как устанавливается как должно срабатывать прерывание (уровень, фронт, спад)
В пользовательской логике формирую просто короткий положительный импульс. Вроде и сбрасывать в этом случае ничего не надо.
В программе вход в обработчик имеется, но выхода из него нет - виснет на обработчике.
В программе при инициализации системы регистрирую обработчик так
Код
alt_irq_register(RAMTEST_0_IRQ, (void*)RAMTEST_0_BASE, ramtest_isr);

Сам обработчик
CODE
// Обработчик прерываний RAMTEST_0_IRQ
static void ramtest_isr()
{
Start == 0;
int ramresult;
char uramresult[10] = {0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x00};

ramresult=IORD_ALTERA_AVALON_RAM_0(RAMTEST_0_BASE);
uramresult[1] = ramresult;
uramresult[0] = ramresult >> 8;
.... и т. д.
}
Если можно в коротком примере как должно быть правильно так, чтобы обработчик по фронту от пользовательской логики выполнил свою задачу однократно и не зависал.?
Копейкин
У меня примера под рукой нет, но когда разбирался, то отложилось в памяти так:
1) Интерфейс Interrupt sender даёт нам линии irq или irq_n, которые работают по уровню, не фронту.
Выбрали, допустим irq - срабатывает на уровень "1".
2) Ставим на линию irq триггер.
3) Триггер взводится в "1" Вашим событием (кнопка, счётчик...)
4) Программа в обработчике прерывания ОБЯЗАТЕЛЬНО должна этот триггер сбросить в "0",
иначе из прерывания не выйти. Сбросить можно чтением или записью по адресу, как Вам удобно.
Вот таким образом.

Есть ещё компонент - векторизируемый контроллер прерываний - он даёт возможностей побогаче,
более предсказуемое время входа в прерывание, но требует существенных ресурсов, для реализации.
С ним не разбирался - так, обзорно...
Acvarif
Цитата(Копейкин @ Aug 23 2012, 12:05) *
У меня примера под рукой нет, но когда разбирался, то отложилось в памяти так:
1) Интерфейс Interrupt sender даёт нам линии irq или irq_n, которые работают по уровню, не фронту.
Выбрали, допустим irq - срабатывает на уровень "1".
2) Ставим на линию irq триггер.
3) Триггер взводится в "1" Вашим событием (кнопка, счётчик...)
4) Программа в обработчике прерывания ОБЯЗАТЕЛЬНО должна этот триггер сбросить в "0",
иначе из прерывания не выйти. Сбросить можно чтением или записью по адресу, как Вам удобно.
Вот таким образом.

Есть ещё компонент - векторизируемый контроллер прерываний - он даёт возможностей побогаче,
более предсказуемое время входа в прерывание, но требует существенных ресурсов, для реализации.
С ним не разбирался - так, обзорно...

Спасибо. Понятно. Жаль, что только по уровню.
Вобщем так вроде и реализовал. Только сброс со стороны обработчика не делал.
Попробую со сбросом.
Всеравно не до конца понимаю зачем сбрасывать тригер со стороны программы (тоесть в обработчике).
Почему не проходит номер просто формировать импульс небольшой длительности и все?

Читал мануал и выяснил, что если использовать PIO то можно все реализовать и по фронту. В этом случае используется
регистр PIO который внешним событием можно установить, а в обработчике сбросить типа
CODE
/* Initialize the button_pio. */
static void init_button_pio()
{
/* Recast the edge_capture pointer to match the
alt_irq_register() function prototype. */
void* edge_capture_ptr = (void*) &edge_capture;
/* Enable all 4 button interrupts. */
IOWR_ALTERA_AVALON_PIO_IRQ_MASK(BUTTON_PIO_BASE, 0xf);
/* Reset the edge capture register. */
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE, 0x0);
/* Register the ISR. */
#ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT
alt_ic_isr_register(BUTTON_PIO_IRQ_INTERRUPT_CONTROLLER_ID,
BUTTON_PIO_IRQ,
handle_button_interrupts,
edge_capture_ptr, 0x0);
#else
alt_irq_register( BUTTON_PIO_IRQ,
edge_capture_ptr,
handle_button_interrupts );
#endif
}

Вроде и так можно, но тогда придется из компонента прерывание убрать, добавить 1 бит PIO, вывести наружу импульсы запроса прерывания которые подать извне на PIO (тоесть просто перемычка). Насколько так будет хуже или лучше?
Копейкин
Импульс небольшой длительности не гарантирует срабатывание вообще или именно однократное срабатывание.
Сбрасывать программой, да ещё в обработчике, нужно потому, что больше никто не знает, что уже отреагировал на IRQ.
Собственно можно и через PIO.
Ничего плохого я в этом не вижу.
Просто если вводить для этого отдельный компонент, то увеличивается нагрузка на шину -> падает быстродействие.
Ещё, компонент получается не самодостаточным, если для только себя, то и пусть, а если отдавать кому, то совестно.
Собственно, сделать детектор перепада уровня - это 2 триггера и логический элемент.
А бит события PIO, также нужно чистить в прерывании, иначе в нем и останешься.
barabek
Цитата(Acvarif @ Aug 23 2012, 20:18) *
Спасибо. Понятно. Жаль, что только по уровню.

По другому никак. Ну только у 51-ых для некоторых прерываний флаги автоматом сбрасываются при переходе на вектор прерываний. Но это редкость и это не Ваш случай.Для ниоса попытайтесь понять механизм обработки прерываний. Читайте мануал exaption handling. Кратко так. При появлении какого-либо флага ниос переходит на строго определенный адрес (exception address). И этот адрес ОДИН для всех прерываний в системе. По этому адресу хранится библиотечный обработчик (ЕМНИП irq_handler()), который проверяет регистр ipending. В этот регистр смультеплексированы все флаги прерываний. Проверяет софтверно! И на каждый установленный бит вызывает соответствующий обработчик прерывания из таблицы. А теперь представьте, Вы выставили флаг, обработчик вызвался, но не успел обнаружить Ваш флаг, а Вы его сбросили. Нехорошая ситуация.
Вам же выложили примеры. Там есть прерывания. Посмотрите. У меня в примере есть сбос прерывания по чтению региста данных. Это на несколько команд сокращает обработчик sm.gif. Т.е. не обязательно заставлять пользователя сбрасывать флаг, можно сделать так, чтобы флаг сбрасывался, когда Вы вычитываете (или записываете новые) данные из переферии.
Acvarif
Цитата(barabek @ Aug 24 2012, 01:19) *
По другому никак. Ну только у 51-ых для некоторых прерываний флаги автоматом сбрасываются при переходе на вектор прерываний. Но это редкость и это не Ваш случай.Для ниоса попытайтесь понять механизм обработки прерываний. Читайте мануал exaption handling. Кратко так. При появлении какого-либо флага ниос переходит на строго определенный адрес (exception address). И этот адрес ОДИН для всех прерываний в системе. По этому адресу хранится библиотечный обработчик (ЕМНИП irq_handler()), который проверяет регистр ipending. В этот регистр смультеплексированы все флаги прерываний. Проверяет софтверно! И на каждый установленный бит вызывает соответствующий обработчик прерывания из таблицы. А теперь представьте, Вы выставили флаг, обработчик вызвался, но не успел обнаружить Ваш флаг, а Вы его сбросили. Нехорошая ситуация.
Вам же выложили примеры. Там есть прерывания. Посмотрите. У меня в примере есть сбос прерывания по чтению региста данных. Это на несколько команд сокращает обработчик sm.gif. Т.е. не обязательно заставлять пользователя сбрасывать флаг, можно сделать так, чтобы флаг сбрасывался, когда Вы вычитываете (или записываете новые) данные из переферии.

Да, так все и сделал. В смысле сбрасываю пользовательский тригер, который генерирует уровень прерывания, чтением по определенному адресу.
Вроде работает нормально.
Всем спасибо. В основном вопрос решен.
Но почитал тут лабораторку про прерывания и понял, что в моем случае придется переходить на DMA.
Вот лабораторка http://www.khstu.ru/vestnik/articles/396.pdf
Время забора данных из пользовательской памяти в память SDRAM NIOS у меня сильно ограничено. За 2 мкс в определенный момент нужно перегрузить из пользовательской двухпортовой памяти данные (16 слов) в SDRAM NIOS.
Похоже это уже тема для другой ветки (про DMA) форума...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.