|
Передача данных UART => SDRAM память, Как правильно передать данные между UART и SDRAM контроллером |
|
|
|
Nov 6 2016, 16:14
|

В поисках себя...
   
Группа: Свой
Сообщений: 729
Регистрация: 11-06-13
Из: Санкт-Петербург
Пользователь №: 77 140

|
Добрый вечер уважаемые форумчане. Хочу попросить вашего совета по правильной организации передачи данных между 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 - Nov 6 2016, 16:31
|
|
|
|
|
Nov 6 2016, 22:29
|

В поисках себя...
   
Группа: Свой
Сообщений: 729
Регистрация: 11-06-13
Из: Санкт-Петербург
Пользователь №: 77 140

|
Цитата(iosifk @ Nov 6 2016, 22:10)  Все красиво, кроме одного... Откуда Вы узнаете, где в потоке данных будет 1-й байт, а где 2-й и т.д. Достаточно одного сбоя и канал перестанет работать правильно... Поскольку у меня приемник UART самописный - то я добавил сигнал валидности. Когда байт принят - формируется короткий импульс, что данные приняты и их можно использовать. Считая эти импульсы я и делаю вывод о том, какой номер байта у меня принят. Вот модуль которым я это делаю. Я правда в железе его не отлаживал, поскольку макетная плата на работе. Но симуляцию вроде прошел успешно. CODE --=============================== 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 - Nov 6 2016, 22:42
|
|
|
|
|
Nov 7 2016, 04:16
|
Знающий
   
Группа: Свой
Сообщений: 608
Регистрация: 10-07-09
Из: Дубна, Московская область
Пользователь №: 51 111

|
Цитата(Flip-fl0p @ Nov 7 2016, 01:29)  Я тоже думал про то, что если будет сбой, то счетчик байтов может сбиться. Но к сожалению у меня нет ответа на вопрос, что будет при сбое. Остаётся надежда только на то, что сбоя не будет, поскольку кроме UART у меня нет других способов связи между макетной платой и ПК... ...Как вариант найти какой-нибудь из протоколов на основе UART и передавать информацию посредством этого протокола. Но хочется обойтись "малой кровью" Сами спросили, сами ответили и засомневались. Раз есть вероятность сбоя - значит нужно поверх UART'а слепить протокол в котором будут присутствовать преамбула (начало передачи), некоторые служебные признаки, сами данные и результат для контрольной проверки. Судя по тому, что данные значительные, наверное правильно их разбить. Для Вашего случая вполне возможно будет достаточно передавать протоколы с содержанием информации по отдельной строке или некоторому набору пикселей (например квадрату 16х16).
|
|
|
|
|
Nov 7 2016, 05:06
|

В поисках себя...
   
Группа: Свой
Сообщений: 729
Регистрация: 11-06-13
Из: Санкт-Петербург
Пользователь №: 77 140

|
Цитата(Александр77 @ Nov 7 2016, 07: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 - Nov 7 2016, 05:07
|
|
|
|
|
Nov 7 2016, 05:24
|

В поисках себя...
   
Группа: Свой
Сообщений: 729
Регистрация: 11-06-13
Из: Санкт-Петербург
Пользователь №: 77 140

|
Цитата(Bad0512 @ Nov 7 2016, 08:13)  Вижу 2 проблемы в вашем дизайне : 1. Вы не придумали как передавать адрес пиксела в SDR памяти. Поэтому при изменении хотя бы одного пиксела вам придется переписывать всю картинку, и ещё надо придумать как всё-таки сбрасывать адресный счетчик. 2. Передавать данные картинки по UART со скоростью 9600 - это оооооочень медленно. Посчитайте сколько времени займёт перезапись полной картинки (это вы ещё накладные расходы на протокол не учитывали). С адресом вроде проблем нет. Первый пиксель пишется в ячейку матрицы с адресом (0,0) Второй пиксель по адресу (0,1). Я заполняю подряд ячейки памяти. Разрешение матрицы 800х480. Соответственно использую 384000 ячеек памяти. При чтении памяти каждому пикселю всегда строго соответствует своя ячейка памяти. Написав простенький автомат, который генерирует полосы я в этом убедился, поскольку изображение статично. Так-же если в память ничего не писать а просто её читать, так-же получается статичная картинка в виде "цветного матраса". Поскольку я передаю не видеопоток, а картинку, то пикселя изменяться и не должны. Данные будут писаться примерно 2 минуты.
|
|
|
|
|
Nov 7 2016, 06:59
|
Знающий
   
Группа: Свой
Сообщений: 802
Регистрация: 11-05-07
Из: Томск
Пользователь №: 27 650

|
Цитата(Flip-fl0p @ Nov 7 2016, 12:24)  С адресом вроде проблем нет. Первый пиксель пишется в ячейку матрицы с адресом (0,0) Второй пиксель по адресу (0,1). Я заполняю подряд ячейки памяти. Разрешение матрицы 800х480. Соответственно использую 384000 ячеек памяти. При чтении памяти каждому пикселю всегда строго соответствует своя ячейка памяти. Написав простенький автомат, который генерирует полосы я в этом убедился, поскольку изображение статично. Так-же если в память ничего не писать а просто её читать, так-же получается статичная картинка в виде "цветного матраса". Поскольку я передаю не видеопоток, а картинку, то пикселя изменяться и не должны. Данные будут писаться примерно 2 минуты. Ну хорошо, вот вы записали всю вашу картинку целиком. В результате указатель памяти будет указывать на место в памяти сразу за последним пикселом. Что вы будете делать дальше? Сбрасывать всю ПЛИС ради установки одного счетчика? Ну то есть по записи картинки жизнь вашей системы закончилась? По скорости записи : при скорости UARTа 9600 реальная скорость передачи данных с учетом старт и стоп битов будет 9600/10*8 = 7680 бит в секунду или 960 байт в секунду. При размере картинки 800*480*3 байта = 1152000 байт время записи составит 20 минут! И мы тут ещё не учитываем накладные. Не очень хорошая скорость для системы отображения - один кадр в 20 минут.
|
|
|
|
|
Nov 7 2016, 07:29
|

В поисках себя...
   
Группа: Свой
Сообщений: 729
Регистрация: 11-06-13
Из: Санкт-Петербург
Пользователь №: 77 140

|
Цитата(Bad0512 @ Nov 7 2016, 09:59)  Ну хорошо, вот вы записали всю вашу картинку целиком. В результате указатель памяти будет указывать на место в памяти сразу за последним пикселом. Что вы будете делать дальше? Сбрасывать всю ПЛИС ради установки одного счетчика? Ну то есть по записи картинки жизнь вашей системы закончилась? По скорости записи : при скорости 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 - Nov 7 2016, 07:30
|
|
|
|
|
Nov 7 2016, 08:24
|
Гуру
     
Группа: Модераторы
Сообщений: 4 011
Регистрация: 8-09-05
Из: спб
Пользователь №: 8 369

|
Цитата(Flip-fl0p @ Nov 7 2016, 08:06)  Без причины сбоить не должно. Данные передаю в плату простой командой, набранной в командной строке: Код mode com5 baud=9600 parity=n data=8 copy D:\bit /b com5 pause Уверяю Вас, сбоит всегда подло и без причины... И если одна посылка хотя бы сбойнет, то все следующее за ней пойдет криво. И у Вас не будет возможности понять что и где произошло. Только сбросить все и перезагрузиться... И тайм-ауты не помогут. Это же винды на хосте, а они без причины могут запустить проверку почты или что-то еще...
--------------------
www.iosifk.narod.ru
|
|
|
|
|
Nov 7 2016, 09:12
|
Знающий
   
Группа: Свой
Сообщений: 802
Регистрация: 11-05-07
Из: Томск
Пользователь №: 27 650

|
Цитата(Flip-fl0p @ Nov 7 2016, 14:29)  У меня есть автомат который управляет записью и чтением контроллера SDRAM. После того, как запись будет закончена, автомат перейдет в состояние чтения, и начнет читать данные начиная с адреса (0,0). Как только прочитал все ячейки с данными, он опять начинает читать. Таким образом после записи, автомат начинает циклически читать данные по кругу. Данные с памяти постоянно отправляются на асинхронный FIFO буфер, через который уже и выводятся на матрицу. А вот со скоростью UART беда, действительно 20 минут получается... Буду брать большую частоту. Думаю надо работать с частотой 115 200 (8-N-1). А про какой указатель памяти Вы имели ввиду ? Мне почему-то показалось что у вас порты на запись и на чтение SDRAM разные и работают независимо.Под указателем имелся ввиду счетчик адреса на запись. Ну а если у вас порт один, то следующим усовершенствованием в вашей системе будет независимая схема (один порт - только на запись, один - только на чтение). Дальше можно ещё добавлять портов, с помощью арбитра разделять по времени доступ к SDRAM и так далее. В идеале все порты могут жить в разных клоковых доменах, тем более производительности SDRAM хватает, в общем многие вещи тут можно улучшить.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|