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

fookat

Новичок
  • Постов

    6
  • Зарегистрирован

  • Посещение

Репутация

1 Обычный

Посетители профиля

387 просмотров профиля
  1. Хочу оставить отзыв о AlexSt. Это мой первый проект, где я решился идти дальше макетной платы и мне повезло, что связался с AlexSt. С учётом отсутствия ТЗ с моей стороны, AlexSt выудил из меня достаточно информации, чтобы развести плату с учётом моих пожеланий. Так же дал рекомендации, как можно сделать лучше, что я планирую применить в следующих ревизиях. Рассказал как отправить на распайку плату в Китай и провёл через этот путь. Как итог - уже на днях первые пять плат едут в Россию. Очень благодарен за проделанную работу и всем рекомендую.
  2. Привет Нужно развести плату на которой будет ESP32 WROOM с подключённым ADC HX711, а так же питание от батарейки/аккумулятора. Помимо этого требуется кнопка вкл/выкл и выводы UART. Размер платы не должен превышать размер 55мм на 35мм(меньше - лучше). Так же нужен один тестовый рабочий прототип. Прошивку сделал и отладил на макете. г. Москва, но в целом не важно - лишь бы работало. По цене сложно, т.к. ни разу не обращался по такому вопросу, поэтому нужно будет договориться в ЛК)
  3. Здравствуйте. Разбирался с SDRAM контроллером представленным здесь http://fpga4fun.com/SDRAM2.html (http://fpga4fun.com/files/SDRAM_ctrl.zip) и возникли некоторые вопросы по коду. Код на Verilog с моими комментариями. module sdram_controller( input clk, /* Тактирование */ /* Чтение */ input RdReq, /* Запрос на чтение */ output RdGnt, /* Запрос на чтение одобрен */ input [19:0] RdAddr, /* Адрес. Шина на 20 сигналов */ output reg [15:0] RdData, /* Прочитанные данные. Шина 16 сигналов */ output RdDataValid, /* Достовреность прочитанных данных. Выставляется в 1, если достоверны */ /* Запись */ input WrReq, /* Запрос на запись */ output WrGnt, /* Запрос на запись одобрен */ input [19:0] WrAddr, /* Адрес. Шина на 20 сигналов */ input [15:0] WrData, /* Записываемые данные. Шина 16 сигналов */ /* Управление SDRAM */ output SDRAM_CKE, /* Clock. Тактирование */ output SDRAM_WEn, /* Enable. Включение */ output SDRAM_RASn, /* Row address strobe. */ output SDRAM_CASn, /* Column Access strobe */ output reg [10:0] SDRAM_A, /* Address */ output reg [0:0] SDRAM_BA, /* Memory Bank */ output reg [1:0] SDRAM_DQM = 2'b11, /* Data mask */ inout [15:0] SDRAM_DQ ); /* На вход SDRAM.Enable всегда подаём лог. единицу, тем самым включая SDRAM */ assign SDRAM_CKE = 1'b1; /* Команды управления SDRAM`ом */ localparam [2:0] SDRAM_CMD_LOADMODE = 3'b000; /* Загрузка регистра управления. Сама команда подаётся по шине адреса(A) */ localparam [2:0] SDRAM_CMD_REFRESH = 3'b001; /* Автоматическая регенерация. Для поддержания заряда конденсаторов */ localparam [2:0] SDRAM_CMD_PRECHARGE = 3'b010; /* Деактивация. Деактивация открытого ряда в банке */ localparam [2:0] SDRAM_CMD_ACTIVE = 3'b011; /* Активация. Активировать ряд в отдельном банке. По шине адреса(A) задаётся ряд, по шине банка(BA) банк */ localparam [2:0] SDRAM_CMD_WRITE = 3'b100; /* Запись. Записывает данные в активный ряд */ localparam [2:0] SDRAM_CMD_READ = 3'b101; /* Чтение. Читает данные из активного ряда */ localparam [2:0] SDRAM_CMD_NOP = 3'b111; /* Нет операции. Предохраняет от выполнения нежелательных команд во время ожидания */ /* По-умолчанию в регистре SDRAM_CMD будет висеть команда NOP */ reg [2:0] SDRAM_CMD = SDRAM_CMD_NOP; /* Каждому управляещему выходу(пину) назначается свой сигнал из регистра SDRAM_CMD. При изменении SDRAM_CMD соотествующие выхода будут меняться. */ assign {SDRAM_RASn, SDRAM_CASn, SDRAM_WEn} = SDRAM_CMD; /* Установка приоритета командам чтение/запись */ wire read_now = RdReq; /* Приоритет у команды чтения */ wire write_now = ~RdReq & WrReq; /* Если нет команды чтения и есть запрос на запись, то разрешаем запись */ /* Регистр статуса. Для организации state-machine */ reg [1:0] state = 0; /* ?? BEGIN */ reg ReadSelected = 0; always @(posedge clk) if (state == 2'h0) ReadSelected <= read_now; wire WriteSelected = ~ReadSelected; wire ReadCycle = (state == 2'h0) ? read_now : ReadSelected; wire [19:0] Addr = ReadCycle ? RdAddr : WrAddr; reg [19:0] AddrR = 0; always @(posedge clk) AddrR <= Addr; /* ?? END */ /* Сравниваем строку и банк текущего и предыдущего чтений на предмет изменений */ wire SameRowAndBank = (Addr[19:8] == AddrR[19:8]); /* Выставляем флаг "Чтение разрешено" если 1) Статус "Ожидание" и есть запрос на чтение 2) Статус "Активирован" и есть выбранная строка блока, запрос на чтение, выборана та же строка что и на предыдущем чтении */ assign RdGnt = (state == 2'h0 & read_now) | (state == 2'h1 & ReadSelected & RdReq & SameRowAndBank); /* Аналогично чтению */ assign WrGnt = (state == 2'h0 & write_now) | (state == 2'h1 & WriteSelected & WrReq & SameRowAndBank); always @(posedge clk) case(state) /* Статус "Ожидание" */ 2'h0: begin /* Есть запрос на чтение/запись */ if(RdReq | WrReq) begin SDRAM_CMD <= SDRAM_CMD_ACTIVE; /* Команда "Активирован" */ SDRAM_BA <= Addr[19]; /* Банк памяти */ SDRAM_A <= Addr[18:8]; /* Строка */ SDRAM_DQM <= 2'b11; /* Выставляем в 11, чтобы не мешало чтению/записи. */ /* Меняем статус на "Активирован" */ state <= 2'h1; end /* Иначе тупим дальше */ else begin SDRAM_CMD <= SDRAM_CMD_NOP; SDRAM_BA <= 0; SDRAM_A <= 0; SDRAM_DQM <= 2'b11; /* Остаёмся в режиме "Ожидание" */ state <= 2'h0; end end /* Статус "Активирован" */ 2'h1: begin SDRAM_CMD <= ReadSelected ? SDRAM_CMD_READ : SDRAM_CMD_WRITE; /* Выставляем команду чтения или записи */ SDRAM_BA <= AddrR[19]; /* Банк памяти */ SDRAM_A[9:0] <= {2'b00, AddrR[7:0]}; /* Колонка */ SDRAM_A[10] <= 1'b0; /* Отключаем автоматическую деактивацию */ SDRAM_DQM <= 2'b00; /* */ /* Если есть запрос на чтение или запись, то остаёмся в режиме "Активирован", иначе переходим в "Деактивация" */ state <= (ReadSelected ? RdReq : WrReq) & SameRowAndBank ? 2'h1 : 2'h2; end /* Статус "Деактивация" */ 2'h2: begin SDRAM_CMD <= SDRAM_CMD_PRECHARGE; /* Команда деактивации */ SDRAM_BA <= 0; SDRAM_A <= 11'b100_0000_0000; /* Деактивация всех банков */ SDRAM_DQM <= 2'b11; state <= 2'h0; end /* Статус "Нет операции" */ 2'h3: begin SDRAM_CMD <= SDRAM_CMD_NOP; SDRAM_BA <= 0; SDRAM_A <= 0; SDRAM_DQM <= 2'b11; state <= 2'h0; end endcase /* ?? BEGIN */ localparam trl = 4; // total read latency is the SDRAM CAS-latency (two) plus the SDRAM controller induced latency (two) reg [trl-1:0] RdDataValidPipe; always @(posedge clk) RdDataValidPipe <= {RdDataValidPipe[trl-2:0], state == 2'h1 & ReadSelected}; assign RdDataValid = RdDataValidPipe[trl-1]; /* ?? END */ /* Выводим на шину RdData данные от SDRAM по фронту клока */ always @(posedge clk) RdData <= SDRAM_DQ; /* Сигнал(флаг) - команда записи Определяется по состоянию "Активирован" и признаку "запрос на запись" */ reg SDRAM_DQ_OE = 1'b0; always @(posedge clk) SDRAM_DQ_OE <= (state == 2'h1) & WriteSelected; /* Устранение метастабильности на входе WrData (?) */ reg [15:0] WrData1 = 0; reg [15:0] WrData2 = 0; always @(posedge clk) WrData1 <= WrData; always @(posedge clk) WrData2 <= WrData1; /* Если команда записи, то выставляем на шину SDRAM.DQ данные WrData2 */ assign SDRAM_DQ = SDRAM_DQ_OE ? WrData2 : 16'hZZZZ; endmodule Построчно я понимаю что происходит, но связать в общую схему некоторые куски кода у меня не получается. Непонятые мною моменты(сначала как я это понял, затем вопросы): 1) Тут мы по фронту клока, находясь в состоянии "Ожидание", заводим сигнал "Запрос на чтение" на регистр ReadSelected. Так понимаю это нужно, чтобы зафиксировать вход, устранить "дрыганье"? reg ReadSelected = 0; always @(posedge clk) if (state == 2'h0) ReadSelected <= read_now; wire WriteSelected = ~ReadSelected; 2) Если мы в состоянии "Ожидание", то берём read_now, иначе ReadSelected Почему мы в одном случае берём вход напрямую, а в другом из регистра ReadSelected? Почему wire называется ReadCycle, т.е. какой цикл тут имеется ввиду? wire ReadCycle = (state == 2'h0) ? read_now : ReadSelected; 3) В state-machine используется и ReadSelected и RdReq одновременно и я не понимаю зачем. Т.е. для каких целей служит ReadSelected? Он сигнализирует о том, что команда чтения выполнялась перед этим? 4) Устанавливаем сигнал "Достоверность прочитанных данных" спустя 4 такта. Два такта на работу самой SDRAM и два на работу SDRAM контроллера. Можете объяснить как тут происходит отсчёт четырёх тактов за счёт объединения сигналов через {}? localparam trl = 4; // total read latency is the SDRAM CAS-latency (two) plus the SDRAM controller induced latency (two) reg [trl-1:0] RdDataValidPipe; always @(posedge clk) RdDataValidPipe <= {RdDataValidPipe[trl-2:0], state == 2'h1 & ReadSelected}; assign RdDataValid = RdDataValidPipe[trl-1]; В RTL Viewer это разворачивается в и тут уже понятно, что есть задержка в 4 такта.
  4. К сожалению количество сообщений и ранг новичка не позволяет мне отправлять личные сообщения. Если у Вас есть время, то напишите пожалуйста в ЛС. Спасибо.
  5. Здравствуйте. Есть реализация SPI на Verilog в топике http://electronix.ru/forum/index.php?showt...127855&st=0 Я взял его и оставил только часть RX, получилось: module spi_slave_mine #(parameter DATA_LENGTH = 8) ( CLK_I, RST_I, RX_READY, CLK_SLAVE, CS_SLAVE, MOSI_SLAVE ); input CLK_I; input RST_I; output RX_READY; input CLK_SLAVE; input CS_SLAVE; input MOSI_SLAVE; reg[7:0] reg_rx_data; reg[7:0] reg_rx_shift_data; reg[5:0] reg_rx_cnt; reg reg_rx_ready; reg reg_rx_done; reg reg_rx_done_flip1; reg reg_rx_done_flip2; reg reg_rx_done_flip3; assign RX_READY = reg_rx_ready; /* reg_rx_data <= reg_rx_shift_data */ always @(posedge CLK_I or posedge RST_I) if(RST_I) reg_rx_data <= 'h0; else if(reg_rx_done_flip1 && !reg_rx_done_flip2) reg_rx_data <= reg_rx_shift_data; /* RX Data */ always @(posedge CLK_SLAVE or posedge RST_I) if(RST_I) reg_rx_shift_data <= 'h0; else if(!CS_SLAVE) reg_rx_shift_data <= {MOSI_SLAVE, reg_rx_shift_data[DATA_LENGTH - 1 : 0]}; /* RX Cnt */ always @(posedge CLK_SLAVE or posedge RST_I) if(RST_I) reg_rx_cnt <= 'h0; else if(!CS_SLAVE) reg_rx_cnt <= reg_rx_cnt + 1; else if(reg_rx_cnt == DATA_LENGTH - 1) reg_rx_cnt <= 'h0; /* RX Done */ always @(posedge CLK_SLAVE or posedge RST_I) if(RST_I) reg_rx_done <= 'h0; else if(reg_rx_cnt == DATA_LENGTH - 1) reg_rx_done <= 1'b1; else reg_rx_done <= 1'b0; /* reg_rx_done_flipX */ always @(posedge CLK_I or posedge RST_I) if(RST_I) begin reg_rx_done_flip1 <= 1'b0; reg_rx_done_flip2 <= 1'b0; reg_rx_done_flip3 <= 1'b0; end else begin reg_rx_done_flip1 <= reg_rx_done; reg_rx_done_flip2 <= reg_rx_done_flip1; reg_rx_done_flip3 <= reg_rx_done_flip2; end /* reg_rx_ready */ always @(posedge CLK_I or posedge RST_I) if(RST_I) reg_rx_ready <= 1'b0; else if (reg_rx_done_flip2 && !reg_rx_done_flip3) reg_rx_ready <= 1'b1; endmodule Затем хочу посмотреть как всё работает при помощи ModelSim. В результате вижу такую картинку: Т.е. reg_rx_shift_data, reg_rx_cnt ни как не реагируются, хотя если поставить точку останова, например тут: то отладчик встаёт и командами Step Over доходит до reg_rx_cnt <= reg_rx_cnt + 1; Подскажите, что я делаю не так? Спасибо.
  6. Здравствуйте. Недавно начал вникать в тему FPGA и поэтому возник вопрос.. В коде присутствуют регистры для устранения метастабильности rx_done. reg rx_done; reg rx_done_flip1; reg rx_done_flip2; reg rx_done_flip3; По фронту тактирующего сигнала CLK_I происходит запись в эти регистры always @(posedge CLK_I or posedge RST_I) if (RST_I) begin rx_done_flip1 <= #UDLY 1'b0; rx_done_flip2 <= #UDLY 1'b0; rx_done_flip3 <= #UDLY 1'b0; end else begin rx_done_flip1 <= #UDLY rx_done; rx_done_flip2 <= #UDLY rx_done_flip1; rx_done_flip3 <= #UDLY rx_done_flip2; end Меня интересует почему во время записи reg_rxdata <= rx_shift_data; используется проверка if (rx_done_flip1 && !rx_done_flip2) always @(posedge CLK_I or posedge RST_I) if(RST_I) reg_rxdata <= #UDLY 'h0; else if (rx_done_flip1 && !rx_done_flip2) reg_rxdata <= #UDLY rx_shift_data; А при установке регистра reg_rrdy используется проверка else if (rx_done_flip2 && !rx_done_flip3) always @(posedge CLK_I or posedge RST_I) if (RST_I) reg_rrdy <= #UDLY 1'b0; else if (rx_done_flip2 && !rx_done_flip3) reg_rrdy <= #UDLY 1'b1; else if (WR_RD && !CSn) reg_rrdy <= #UDLY 1'b0; И почему, например в (rx_done_flip2 && !rx_done_flip3), регистр rx_done_flip3 берётся с инверсией? Чтобы значение reg_rrdy было зафиксировано только когда rx_done_flip2 установлен, а rx_done_flip3 ещё нет? Спасибо.
×
×
  • Создать...