Перейти к содержанию
    

Передача данных UART => SDRAM память

Добрый вечер уважаемые форумчане. Хочу попросить вашего совета по правильной организации передачи данных между UART и SDRAM контроллером.

Хочу записать изображение в SDRAM память, и вывести его на LVDS матрицу.

Изображение представляет собой набор пикселей, где каждый пиксель состоит из 3 байтов данных. Каждый байт передает данные о базовой составляющей цвета (RGB). Передача изображения из компьютера в SDRAM память будет через UART (9600/8-N-1).

Мой UART приемник работает по классической схеме: через частоту в 16 раз больше бодовой и выборкой трех значений с середины битового интервала, с последующим мажорированием. После принятия байта приемником он поступает на модуль, который после принятия трех байт, отбрасывает ненужные мне разряды цвета, и объединяет их в одно слово, являющееся цветом пикселя, которое будет записываться в SDRAM память.

Таким образом каждые 3 байта я должен передавать данные SDRAM контроллеру (который может работать на частоте до 133 МГц) для их записи в память.

Соответственно мы в итоге должны передать данные между 2 клоковыми доменами UART => SDRAM контроллер.

У меня есть 2 варианта по организации передачи данных: использовать протокол Handshake (рукопожатие) или FIFO буфер. Первый вариант кажется предпочтительным, поскольку применение FIFO буфера неоправданно из-за того, что скорость записи данных в него будет несопоставимо ниже, чем я могу этот буфер читать, и буфер будет всегда пустой. Можно накопить данные в буфере, и периодически его считывать по мере заполнения. Но не вижу рациональных причин так делать. Вот и хотелось бы услышать Ваше мнение, как правильнее организовать передачу данных. Естественно UART приемник и SDRAM контроллер реализованы в ПЛИС.

Изменено пользователем Flip-fl0p

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Таким образом каждые 3 байта я должен передавать данные SDRAM контроллеру (который может работать на частоте до 133 МГц) для их записи в память.

Все красиво, кроме одного... Откуда Вы узнаете, где в потоке данных будет 1-й байт, а где 2-й и т.д.

Достаточно одного сбоя и канал перестанет работать правильно...

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Все красиво, кроме одного... Откуда Вы узнаете, где в потоке данных будет 1-й байт, а где 2-й и т.д.

Достаточно одного сбоя и канал перестанет работать правильно...

Поскольку у меня приемник UART самописный - то я добавил сигнал валидности.

Когда байт принят - формируется короткий импульс, что данные приняты и их можно использовать. Считая эти импульсы я и делаю вывод о том, какой номер байта у меня принят. Вот модуль которым я это делаю. Я правда в железе его не отлаживал, поскольку макетная плата на работе. Но симуляцию вроде прошел успешно.

--=============================== PIXEL_CREATING =========================================
-- Данный модуль предназначен для приема 3 байт данных по UART и пребразования их
-- В одно слово, содержащее данные о цвете пикселя. 

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;

ENTITY PIXEL_CREATING IS
   GENERIC
   (
       COLOR_DEPTH : INTEGER := 12  --COLOR_DEPTH/3   Для одного цвета
   );
   PORT
   (
       CLK         : IN  STD_LOGIC;                                      -- Частота UART ресивера
       UART_DATA   : IN  STD_LOGIC_VECTOR(7 DOWNTO 0);                   -- Данные, выдавемые UART
       DATA_VALID  : IN  STD_LOGIC;                                      -- Сигнал подтверждения валидных данных рессивером
       ASY_RESET   : IN  STD_LOGIC;                                      -- Асинхронный сброс Синхронизирован в топ модуле.
       PIXEL_COLOR : OUT STD_LOGIC_VECTOR(COLOR_DEPTH-1 DOWNTO 0);       -- Выходной сигнал который является цветом пикселя
       PIXEL_VALID : OUT STD_LOGIC
   );
END ENTITY;

ARCHITECTURE PIXEL_CREATING_arc OF PIXEL_CREATING IS
   SIGNAL BYTE_CNT         : INTEGER RANGE 0 TO 2 := 0;                                        -- Счетчик принятых байт
   SIGNAL RED_COLOR_REG    : STD_LOGIC_VECTOR(COLOR_DEPTH/3-1 DOWNTO 0) := (OTHERS => '0');    -- Регистр куда записывается красная составляющая пикселя
   SIGNAL GREEN_COLOR_REG  : STD_LOGIC_VECTOR(COLOR_DEPTH/3-1 DOWNTO 0) := (OTHERS => '0');    -- Регистр куда записывается зеленая составляющая пикселя
   SIGNAL BLUE_COLOR_REG   : STD_LOGIC_VECTOR(COLOR_DEPTH/3-1 DOWNTO 0) := (OTHERS => '0');    -- Регистр куда записывается синяя   составляющая пикселя
   SIGNAL LOAD_DATA        : STD_LOGIC := '0';                                                 -- Сигнал разрешения объедениения данных
BEGIN
   BYTE_COUNTER : PROCESS
   (
       CLK,
       ASY_RESET
   )
   BEGIN
       IF (ASY_RESET = '1') THEN
           BYTE_CNT         <=  0 ;
           LOAD_DATA        <= '0';                                          
           PIXEL_VALID      <= '0';
           RED_COLOR_REG    <= (OTHERS => '0');    
           GREEN_COLOR_REG  <= (OTHERS => '0');    
           BLUE_COLOR_REG   <= (OTHERS => '0'); 
           PIXEL_COLOR      <= (OTHERS => '0'); 
       ELSIF (CLK'EVENT AND CLK = '1') THEN
           LOAD_DATA   <= '0';                                                             -- Постоянно держим сигнал разрешения в нуле
           PIXEL_VALID <= '0';                                                             -- Постоянно держим сигнал валидности пикселя в нуле

           IF (DATA_VALID = '1') THEN                                                      -- Как только поступил сигнал валидности данных
               CASE BYTE_CNT IS                                                            -- Начинаем анализировать состояние счётчика

                   WHEN 0      =>                                                          -- Есть сигнал валидности и счтчик равен 0
                                  RED_COLOR_REG    <= UART_DATA(COLOR_DEPTH/3-1 DOWNTO 0); -- Значит это были данные о красном цвете пикселя
                                  BYTE_CNT         <= BYTE_CNT + 1;                        -- Инкрементируем счетчик на 1

                   WHEN 1      =>                                                          -- Есть сигнал валидности и счтчик равен 1
                                  GREEN_COLOR_REG  <= UART_DATA(COLOR_DEPTH/3-1 DOWNTO 0); -- Значит это были данные о зеленом цвете пикселя
                                  BYTE_CNT         <= BYTE_CNT + 1;                        -- Инкрементируем счетчик на 1

                   WHEN 2      =>                                                          -- Есть сигнал валидности и счтчик равен 2
                                  BLUE_COLOR_REG   <= UART_DATA(COLOR_DEPTH/3-1 DOWNTO 0); -- Значит это были данные о синем цвете пикселя
                                  LOAD_DATA        <= '1';                                 -- Разрешам следующим тактом "собрать пиксель"
                                  BYTE_CNT         <=  0 ;                                 -- Обнулим счетчик

                   WHEN OTHERS => BYTE_CNT         <=  0 ;                                 -- Обнуляем счётчик  если он вышел за диапазон счета 
               END CASE;
           END IF;

           IF (LOAD_DATA = '1') THEN                                         -- Как только наступило разрешение сбора пикселя
               PIXEL_VALID <= '1';                                           -- Значит следующим тактом у нас будет валидный пиксель
               PIXEL_COLOR <= BLUE_COLOR_REG&GREEN_COLOR_REG&RED_COLOR_REG;  -- Соберем его
           END IF;

       END IF;
   END PROCESS; 
END ARCHITECTURE;  

Я тоже думал про то, что если будет сбой, то счетчик байтов может сбиться. Но к сожалению у меня нет ответа на вопрос, что будет при сбое. Остаётся надежда только на то, что сбоя не будет, поскольку кроме UART у меня нет других способов связи между макетной платой и ПК. Связь осуществляется через микросхему FTDI FT2232H. В системе у меня 2 виртуальных COM порта, один из которых применяется для конфигурации ПЛИС, а через другой буду передавать данные. Надежность данного решения под вопросом. Но приходиться работать с тем, что имею. Как вариант найти какой-нибудь из протоколов на основе UART и передавать информацию посредством этого протокола. Но хочется обойтись "малой кровью"

Изменено пользователем Flip-fl0p

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сделать счетчик таймаута приема. Если он сработал, сбрасывать счетчик, он же адрес, байтов.

Передавать сплошным потоком, не допуская больших разрывов. Впрочем, можно выбрать нужный тамаут.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я тоже думал про то, что если будет сбой, то счетчик байтов может сбиться. Но к сожалению у меня нет ответа на вопрос, что будет при сбое. Остаётся надежда только на то, что сбоя не будет, поскольку кроме UART у меня нет других способов связи между макетной платой и ПК...

...Как вариант найти какой-нибудь из протоколов на основе UART и передавать информацию посредством этого протокола. Но хочется обойтись "малой кровью"

Сами спросили, сами ответили и засомневались.

Раз есть вероятность сбоя - значит нужно поверх UART'а слепить протокол в котором будут присутствовать преамбула (начало передачи), некоторые служебные признаки, сами данные и результат для контрольной проверки.

Судя по тому, что данные значительные, наверное правильно их разбить. Для Вашего случая вполне возможно будет достаточно передавать протоколы с содержанием информации по отдельной строке или некоторому набору пикселей (например квадрату 16х16).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сами спросили, сами ответили и засомневались.

Раз есть вероятность сбоя - значит нужно поверх UART'а слепить протокол в котором будут присутствовать преамбула (начало передачи), некоторые служебные признаки, сами данные и результат для контрольной проверки.

Судя по тому, что данные значительные, наверное правильно их разбить. Для Вашего случая вполне возможно будет достаточно передавать протоколы с содержанием информации по отдельной строке или некоторому набору пикселей (например квадрату 16х16).

Без причины сбоить не должно. Данные передаю в плату простой командой, набранной в командной строке:

mode com5 baud=9600 parity=n data=8
copy D:\bit /b com5
pause

Попробую через FIFO буфер передавать данные (буду его применять только потому, что примитив FIFO буфера у Altera есть готовый, и мне меньше работы). А дальше будет видно по изображению на матрице как передались данные. На стороне ПЛИС я могу делать всё что смогу, и реализовать почти любой протокол. Лишь бы хватило ресурсов в ПЛИС. А вот со стороны ПК передавать данные по UART через какой-либо протокол... У меня пока недостаточно знаний в области программирования, чтобы сделать такое. Вот и хочу обойтись "малой кровью".... Очень похожий проект на такой-же макетной плате заработал нормально. https://marsohod.org/projects/marsohod2/214-c3fb2.

Изменено пользователем Flip-fl0p

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вижу 2 проблемы в вашем дизайне :

1. Вы не придумали как передавать адрес пиксела в SDR памяти. Поэтому при изменении хотя бы одного пиксела вам придется переписывать всю картинку, и ещё надо придумать как всё-таки сбрасывать адресный счетчик.

2. Передавать данные картинки по UART со скоростью 9600 - это оооооочень медленно. Посчитайте сколько времени займёт перезапись полной картинки (это вы ещё накладные расходы на протокол не учитывали).

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вижу 2 проблемы в вашем дизайне :

1. Вы не придумали как передавать адрес пиксела в SDR памяти. Поэтому при изменении хотя бы одного пиксела вам придется переписывать всю картинку, и ещё надо придумать как всё-таки сбрасывать адресный счетчик.

2. Передавать данные картинки по UART со скоростью 9600 - это оооооочень медленно. Посчитайте сколько времени займёт перезапись полной картинки (это вы ещё накладные расходы на протокол не учитывали).

С адресом вроде проблем нет. Первый пиксель пишется в ячейку матрицы с адресом (0,0) Второй пиксель по адресу (0,1). Я заполняю подряд ячейки памяти. Разрешение матрицы 800х480. Соответственно использую 384000 ячеек памяти. При чтении памяти каждому пикселю всегда строго соответствует своя ячейка памяти. Написав простенький автомат, который генерирует полосы я в этом убедился, поскольку изображение статично. Так-же если в память ничего не писать а просто её читать, так-же получается статичная картинка в виде "цветного матраса". Поскольку я передаю не видеопоток, а картинку, то пикселя изменяться и не должны.

Данные будут писаться примерно 2 минуты.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что мешает ускорить скорость передачи до 250 кбит/с?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я могу ошибиться, но не две минуты, 9600/8 = 1200 байт в секунду, 800*480*3 = 1152000 всего байт,

1152000/1200=960 секунд или 960/60=16 минут + накладные

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

С адресом вроде проблем нет. Первый пиксель пишется в ячейку матрицы с адресом (0,0) Второй пиксель по адресу (0,1). Я заполняю подряд ячейки памяти. Разрешение матрицы 800х480. Соответственно использую 384000 ячеек памяти. При чтении памяти каждому пикселю всегда строго соответствует своя ячейка памяти. Написав простенький автомат, который генерирует полосы я в этом убедился, поскольку изображение статично. Так-же если в память ничего не писать а просто её читать, так-же получается статичная картинка в виде "цветного матраса". Поскольку я передаю не видеопоток, а картинку, то пикселя изменяться и не должны.

Данные будут писаться примерно 2 минуты.

Ну хорошо, вот вы записали всю вашу картинку целиком. В результате указатель памяти будет указывать на место в памяти сразу за последним пикселом. Что вы будете делать дальше? Сбрасывать всю ПЛИС ради установки одного счетчика? Ну то есть по записи картинки жизнь вашей системы закончилась?

По скорости записи : при скорости UARTа 9600 реальная скорость передачи данных с учетом старт и стоп битов будет 9600/10*8 = 7680 бит в секунду или 960 байт в секунду. При размере картинки 800*480*3 байта = 1152000 байт время записи составит 20 минут! И мы тут ещё не учитываем накладные. Не очень хорошая скорость для системы отображения - один кадр в 20 минут. :(

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну хорошо, вот вы записали всю вашу картинку целиком. В результате указатель памяти будет указывать на место в памяти сразу за последним пикселом. Что вы будете делать дальше? Сбрасывать всю ПЛИС ради установки одного счетчика? Ну то есть по записи картинки жизнь вашей системы закончилась?

По скорости записи : при скорости UARTа 9600 реальная скорость передачи данных с учетом старт и стоп битов будет 9600/10*8 = 7680 бит в секунду или 960 байт в секунду. При размере картинки 800*480*3 байта = 1152000 байт время записи составит 20 минут! И мы тут ещё не учитываем накладные. Не очень хорошая скорость для системы отображения - один кадр в 20 минут. :(

У меня есть автомат который управляет записью и чтением контроллера SDRAM. После того, как запись будет закончена, автомат перейдет в состояние чтения, и начнет читать данные начиная с адреса (0,0). Как только прочитал все ячейки с данными, он опять начинает читать. Таким образом после записи, автомат начинает циклически читать данные по кругу. Данные с памяти постоянно отправляются на асинхронный FIFO буфер, через который уже и выводятся на матрицу. А вот со скоростью UART беда, действительно 20 минут получается... Буду брать большую частоту. Думаю надо работать с частотой 115 200 (8-N-1).

А про какой указатель памяти Вы имели ввиду ?

Изменено пользователем Flip-fl0p

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Без причины сбоить не должно. Данные передаю в плату простой командой, набранной в командной строке:

mode com5 baud=9600 parity=n data=8
copy D:\bit /b com5
pause

Уверяю Вас, сбоит всегда подло и без причины...

И если одна посылка хотя бы сбойнет, то все следующее за ней пойдет криво. И у Вас не будет возможности понять что и где произошло. Только сбросить все и перезагрузиться...

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня есть автомат который управляет записью и чтением контроллера SDRAM. После того, как запись будет закончена, автомат перейдет в состояние чтения, и начнет читать данные начиная с адреса (0,0). Как только прочитал все ячейки с данными, он опять начинает читать. Таким образом после записи, автомат начинает циклически читать данные по кругу. Данные с памяти постоянно отправляются на асинхронный FIFO буфер, через который уже и выводятся на матрицу. А вот со скоростью UART беда, действительно 20 минут получается... Буду брать большую частоту. Думаю надо работать с частотой 115 200 (8-N-1).

А про какой указатель памяти Вы имели ввиду ?

Мне почему-то показалось что у вас порты на запись и на чтение SDRAM разные и работают независимо.Под указателем имелся ввиду счетчик адреса на запись. Ну а если у вас порт один, то следующим усовершенствованием в вашей системе будет независимая схема (один порт - только на запись, один - только на чтение). Дальше можно ещё добавлять портов, с помощью арбитра разделять по времени доступ к SDRAM и так далее. В идеале все порты могут жить в разных клоковых доменах, тем более производительности SDRAM хватает, в общем многие вещи тут можно улучшить.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Реализуйте что-то типа Манчестера и будет вам счастье. Накладные ресурсы - не большие. CRC - можно и не считать, хотя желательно. Поднять и на ПК и на ПЛИС - не сложно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...