fpga-systems-magazine

Сага о светодиодах. Часть 4.

Главная » Статьи » Intel/Altera » Прочее
sergebalakshiy
19.04.2023 08:04
908
0
0.0

Оглавление

Введение

Мой контроллер i2c

Техническое задание

Отладочный стенд

Сборка и отладка

Распределение регистров по портам

Заглядываю внутрь FPGA

Программа для отладочного стенда

Логический анализатор сигналов

Выводы

Практическая философия

Список литературы

Введение

В интернете можно найти множество описаний устройств реализующих протокол i2c. В основном в этих описаниях рассматривается реализация и работа самого протокола i2c и довольно мало уделяется внимания разработке интерфейсов для управления такими устройствами. В этой работе я буду уделять основное внимание интерфейсам управления для устройств, реализующих протокол i2c.

Мой контроллер i2c

Устройство i2c можно отнести к приёмо-передающим устройствам. И как любое такого класса устройство, оно имеет как минимум два интерфейса:

  1. Интерфейс модуля управления для связи с самим устройством;
  2. Интерфейс линии связи.

Это можно представить как на рисунке

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

Техническое задание

Цель: Разработать интерфейс для подключения к приёмо передающему устройству, которое реализует протокол i2c.
Ограничения: Предполагается, что устройство i2c будет подключено к дисплею lcd_1620. И в первом варианте, устройство будет работать только на передачу.
Требования:

  1. Для обмена данными с устройством использовать одну шину как на передачу так и на приём.
  2. Данные как на шине данных так и на адресной шине должны быть стробированы.
  3. Для указания адреса подчинённого устройства использовать шину адреса.
  4. Определить и разработать другие необходимые сигналы управления.
  5. Разработать внутреннее устройство управления реализующее данный интерфейс.

За основу самого устройства i2c я взял устройство i2c_master, представленное здесь. Эта реализация отличается простотой и ясностью, что и повлияло на мой выбор. Конечно, пришлось немного изменить логику заложенную в данную реализацию.

Я изменил последовательность операций в модуле i2c так, что первым выполняется передача адреса ведомого устройства и если получен сигнал ACK, то передается последовательность байт, пока не будет получен сигнал управления STOP, который транслируется на линию в стоп-последовательность для завершения транзакции i2c. После чего устройство переходит в состояние IDLE, ожидая начала новой транзакции. Передача каждого байта сопровождается получением ACK  последовательности, согласно протокола i2c.

Кроме того в исходной реализации нет механизма, который позволял бы согласованно выставлять байты для передачи на шине данных. Для выполнения этой задачи я определил в модуле i2c регистр rde (data empty) регистр подтверждения данных. Состояние 1 этого регистра говорит о том, что байт данных считан с шины данных во внутренний регистр. Переход из состояния 1 в состояние 0 говорит о начале передачи байта данных в линию i2c. Переход из состояния 0 в состояние 1 говорит о том, что передача байта данных завершена и следующий байт считан.

Это можно изобразить так. Операция


sended_data <= i_data_to_send;
rde <= 1;

размещает байт данных с внещней шины во внутреннем регистре для последующей передачи.
Вторая строка устанавливает бит РДП (регистр данных пуст) в 1. Как только этот бит установлен в 1 можно загрузить РД новым байтом для передачи. Ниже представлена схема взаимодействия двух устройств при обмене данными.


 Источник             | Потребитель
     if (rde == 1)    |
     data; --->       |
     rde <= 0 --->     | ---> if (rde == 0) get_data;
                       | ... работа с данными
                       | ... запрос новых данных
                       |<---rde <= 1;

Рис. 2: Схема взаимодействия при обмене данными

Здесь устройство “источник” поставляет байты к устройству “потребитель”. Источник ожидает запрос данных от потребителя. Получив флаг rde==1, источник  выставляет данные на шину данных и устанавливает rde в 0, подтверждая что данные на шине действительны. Потребитель, принимая флаг rde==0 считывает данные во внутренний регистр, работает с данными и, когда необходимо снова устанавливает rde в 1, запрашивая новые данные. Другими словами, источник не меняет данные на шине, пока rde установлен в 0.

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

После внесённых изменений интерфейс к модулю i2c приобрёл следующий вид.


module i2c_master #(
    parameter DATA_WIDTH = 8,
    parameter REG_WIDTH = 8,
    parameter ADDR_WIDTH = 7 )
  (
    input i_clk,
    input i_rst,
    input i_enable,
    input i_rw,
    input [DATA_WIDTH-1:0] i_mosi_data,
    input [ADDR_WIDTH-1:0] i_device_addr,
    input wire [15:0] i_divider,
    // ======== CONTROL ===============================
    input i_rde,
    output o_rde,
    input i_stop,
    // ======== CONTROL ===============================
    output reg o_busy = 0,
    inout io_sda,
    inout io_scl,
    // ======== DEBUG =================================
    output wire [7:0] master_state,
    output wire [3:0] gdb_proc_counter
    // ======== DEBUG =================================
  );

Где

  •  i_clk общая тактовая частота;
  •  i_rst общий сброс;
  •  i_enable сигнал, разрешающий работу модуля i2c;
  •  i_rw направление потока данных, 0 - передача, 1 - приём;
  •  i_mosi_data - байт данных для передачи;
  •  i_device_addr - адрес ведомого устройства;
  •  i_divider - коэффициент деления для определения тактовой частоты на линии i2c;
  •  i_rde входной сигнал регистра подтверждения данных;
  • o_rde выходной сигнал регистра подтверждения данных;
  •  i_stop конец передачи:
  •  o_busy сигнал “устройство занято” 1, “устройство свободно” 0;
  •  io_sda линия данных i2c;
  •  io_scl линия тактирования i2c;
  •  master_state отладочная шина для контроля состояний устройства i2c;
  •  gdb_proc_counter отладочная шина для контроля номера процесса внутри состояния.

Отладочный стенд

Так как передо мной стояла задача не только создать устройство i2c, но и отладить его работу, я решил, для отладки использовать плату Arduino Due. Просто она была у меня в наличии. Arduino Due я подключил к портам de10_lite ARDUINO_IO. Также для отладки я использовал элементы платы de10_lite, а именно имеющиеся на ней светодиоды, кнопки, переключатели и 7-ми сегментные индикаторы.

Кроме того, я использовал цифровой логический анализатор сигналов для контроля линии SDA и SCL. Передаваемые данные я выводил на дисплей lcd_1602.

Общая схема отладочного стенда представлена на рисунке 3.

Сборка и отладка

Сборку модуля i2c я производил на плате de10_lite. Для подключения модуля i2c требуется разработать модуль dev_top, через который и будет осуществляться управление модулем i2c.

Представлю некоторые особенности модуля dev_top. Этот модуль находится на самом верхнем уровне в иерархии модулей. Следовательно, управление этим модулем осуществляется через находящиеся на плате de10_lite порты ввода вывода. И, поэтому интерфейс к модулю dev_top выглядит так.


module dev_top #(parameter SIZE=8)
 (
  output [ 9:0] led,
  output led_clk,
  input [ 1:0] key,
  input [ 9:0] sw,
  input max10_clk1_50,
  output [ 7:0] hex0,
  output [ 7:0] hex1,
  output [ 7:0] hex2,
  output [ 7:0] hex3,
  output [ 7:0] hex4,
  output [ 7:0] hex5,
  inout [35:0] GPIO,
 ////////// ARDUINO //////////
  inout [15:0] ARDUINO_IO,
  inout ARDUINO_RESET_N
 ////////// ARDUINO //////////
 );

Рис. 4: Интерфейс модуля dev_top

Все что есть в этом интерфейсе это просто порты платы de10_lite. Для подключения модуля i2c_master необходимо соединить порты платы de10_lite с портами модуля i2c_master.

Для этого я определил имена локальных параметров, где каждый параметр обозначает имя сигнала в интерфейсе и это имя инициализировано номером пина, к которому подключен данный сигнал.


localparam L_STOP = 13; // сигнал СТОП
localparam L_BUSY = 12; // сигнал Занятости устройства
localparam L_ENABLE = 11; // сигнал Разрешения работы
localparam L_RST = 10; // сигнал СБРОС
localparam L_ORDE = 9; // сигнал подтверждения данных
localparam L_IRDE = 8; // сигнал запроса данных

Рис. 5: Линии управления.

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

reg [7:0] data2send; // к ARDUINO_IO[7:0]

Рис. 6: Регистр данных.

Распределение регистров по портам

Подключение модуля i2c_master я выполнил следующим образом.


i2c_master #(.DATA_WIDTH(8),.REG_WIDTH(8),.ADDR_WIDTH(7))
i2c_master_inst
 (
 .i_clk(max10_clk1_50),
 .i_rst(!rst_n),
 .i_enable(ARDUINO_IO[L_ENABLE]), // 11 to i2c
 .i_rw(rw), // Always 0. ARDUINO_IO[9]),
 .i_mosi_data(data2send), //mosi to i2c
 .i_device_addr(device_addr),
 .i_divider(divider),
 .o_busy(ARDUINO_IO[L_BUSY]), // 12 from i2c
 .i_rde(ARDUINO_IO[8]), // L_IRDE to i2c
 .o_rde(ARDUINO_IO[9]), // L_ORDE from i2c
 .i_stop(ARDUINO_IO[13]), // L_STOP to i2c
 .io_sda(ARDUINO_IO[14]),
 .io_scl(ARDUINO_IO[15]),
 //============= DEBUG ================
 .master_state(st_master),
 .gdb_proc_counter(gdb_proc_counter)
 //============= DEBUG ================
 );

При этом


reg [ 7-1:0] device_addr = 7’h27;
reg [16-1:0] divider = 16’h00FF;
reg rw = 0; // Only write

Где,

  • .i_clk(max10_clk1_50) тактовая частота;
  • .i_rst(!rst_n) сигнал СБРОС;
  • .i_enable(ARDUINO_IO[L_ENABLE]) сигнал на разрешение работы модуля i2c подключаю к пину L_ENABLE;
  •  .i_rw(rw) направление передачи данных, в данном случае просто всегда 0;
  •  .i_mosi_data(data2send) шина данных, подключена к портам платы de10_lite ARDUINO_IO[7:0];
  •  .i_device_addr(device_addr) аппаратно задан 0x27;
  •  .i_divider(divider) коэффициент деления тактовой частоты задан аппаратно;
  •  .o_busy(ARDUINO_IO[L_BUSY]) сигнал занятости устройства;
  •  .i_rde(ARDUINO_IO[8]) запрос байта данных;
  •  .o_rde(ARDUINO_IO[9]) подтверждение байта данных;
  • .i_stop(ARDUINO_IO[13]) сигнал СТОП;
  • .io_sda(ARDUINO_IO[14]) линия данных i2c;
  • .io_scl(ARDUINO_IO[15]) линия тактирования i2c;
  • .master_state(st_master) состояние автомата i2c;
  • .gdb_proc_counter(gdb_proc_counter) счётчик номера процесса в состоянии i2c.

Таким образом весь интерфейс состоит из

  • 6 программно управляемых линий управления, рисунок 5;
  • 8 линий шины данных, рисунок 6;

Используя эти линии можно программно управлять работой модуля i2c. Я намеренно сделал минимальное количество сигналов управления и режимов работы модуля i2c, просто для того, чтобы запустить в работу модуль i2c и посмотреть насколько правильно я сделал схему и сам стенд.

Заглядываю внутрь FPGA

Для того, чтобы посмотреть что происходит внутри FPGA я подключил регистр состояний автомата i2c к шине master_state а счётчик процесса к шине gdb_proc_counter.
Определяю дисплей


 // Display
 reg [24-1:0] display;
 wire [6:0] abcdefg_display0;
 wire [6:0] abcdefg_display1;
 wire [6:0] abcdefg_display2;
 wire [6:0] abcdefg_display3;
 wire [6:0] abcdefg_display4;
 wire [6:0] abcdefg_display5;

Определяю 6 индикаторов


 seven_segment_digit i_ssg0
 (
 .dig(display[3:0]),
 .gfedcba(abcdefg_display0)
 );
 ...

 seven_segment_digit i_ssg5
 (
 .dig(display[23:20]),
 .gfedcba(abcdefg_display5)
 );

Присваиваю


 assign hex0 = abcdefg_display0;
 assign hex1 = abcdefg_display1;
 assign hex2 = abcdefg_display2;
 assign hex3 = abcdefg_display3;
 assign hex4 = abcdefg_display4;
 assign hex5 = abcdefg_display5;

И далее соединяю индикаторы с соответствующими шинами


always @(posedge max10_clk1_50) begin
    data2send ⇐ ARDUINO_IO[7:0];
  case(sw[3:0])
     0: begin // state A2[5] Data[4:3] A2
     // State A1[2] Data A1[1:0]
    display[ 3: 0] <= ARDUINO_IO[3:0];
    display[ 7: 4] <= ARDUINO_IO[7:4];
    display[11: 8] <= st_master[3:0];
    display[15:12] <= st_master[7:4];
    display[19:16] <= gdb_proc_counter;
    end
  endcase // case (sw[3:0])
  rde <= ARDUINO_IO[L_ORDE]; // 0
end // always @ (posedge clk or negedge rst)

Таким образом я контролирую состояние, в котором находится i2c.

Вывожу сигналы на светодиоды


 assign led[8] = rst_n; // rst_n
 assign led[5] = ARDUINO_IO[L_STOP]; // stop OK! 
 assign led[4] = ARDUINO_IO[L_BUSY]; // busy
 assign led[3] = ARDUINO_IO[L_ENABLE]; // enable OK! 
 assign led[2] = ARDUINO_IO[L_RST]; // rst check it ok!
 assign led[1] = ARDUINO_IO[L_ORDE]; // o_rde
 assign led[0] = ARDUINO_IO[L_IRDE]; // i_rde

Определившись с “железом” и что куда подключать я собрал схему отладочного стенда и приступил к написанию программы для ардуино, которая должна была все это “оживить”.

Программа для отладочного стенда

В терминологии ардуино данная программа представляет собой простой скетч. Само слово скетч [sketch] означает набросок, зарисовка. Конечно, программу на с++ трудно назвать зарисовкой, но “набросать” по быстрому такую программу можно, тем более, что для ардуино написано множество простых и удобных библиотек.

Для начала я определил номера пинов, с которыми буду работать и дал названия этим пинам. Простой enum без заморочек.


enum {
  RST = 38,
  EN, // 39
  BUSY, // 40
  STOP, // 41
  BIT0=44, // 44
  BIT1, // 45
  BIT2, // 46
  BIT3, // 47
  BIT4, // 48
  BIT5, // 49
  BIT6, // 50
  BIT7, // 51
  I_RDE, // 52 -> 8 .i_rde
  O_RDE // 53 <- 9 .o_rde
};

Первая колонка это имя пина. В комментариях номер пина. Номера пинов взяты с колодки X10 платы ардуино [1].

Здесь

  • RST - (reset) пин, через который подаётся сигнал сброс на de10_lite;
  • EN - (enable) пин, для подачи сигнала на начало цикла передачи;
  • BUSY - пин, через который плата ардуино принимает сигнал готовности от de10_lite;
  • STOP - сигнал стоп, завершает цикл передачи;
  • I_RDE - приём сигнала шина данных занята/свободна;
  • O_RDE - передача сигнала шина данных занята/свободна;

Далее я определил некоторые константы и переменные

  • mask - маска для выделения i-го бита в байте данных;
  • cmd_arr - массив байт, содержащий команды для управления дисплеем lcd_1602;
  • symb_arr - массив символов для отображения на дисплее;
  • flag_cmd_symb - флаг определяющий с чем работать. С символом или с командой;
  • up - байт, содержащий в своих старших 4-х битах 4-е старших бита символа или команды.
  •  lo - байт, содержащий в своих старших 4-х битах 4-е младших бита символа или команды.
  • data_arr - массив байт, содержащий в своих младших 4-х битах суффиксы взятые из массива sufx_arr так, что для команды здесь будет два байта up и два  байта lo с суффиксами 0x0C, 0x08 каждый. Для символов соответственно суффиксы будут 0x0D, 0x09;
  • sufx_arr - массив суффиксов для команд и символов;
  • cnt_byte - счетчик переданных байт;
  • q_rst - переменная, состояние которой 1/0 подается на пин RST для выполнения аппаратного сброса на плате de10_lite.

Функция setup выполняет инициализацию пинов и переменных.


void setup() {
    Serial.begin(9600);
    // Скорость для i2c
    pinMode(I_RDE, INPUT); // 1/0 pin53<-[9] o_rde
    pinMode(O_RDE, OUTPUT); // 1/0 pin52->[8] i_rde
    pinMode(BIT7, OUTPUT); // 7 bit pin51
    pinMode(BIT6, OUTPUT); // 6 bit pin50
    pinMode(BIT5, OUTPUT); // 5 bit pin49
    pinMode(BIT4, OUTPUT); // 4 bit pin48
    pinMode(BIT3, OUTPUT); // 3 bit pin47
    pinMode(BIT2, OUTPUT); // 2 bit pin46
    pinMode(BIT1, OUTPUT); // 1 bit pin45
    pinMode(BIT0, OUTPUT); // 0 bit pin44
    pinMode(STOP, OUTPUT); // stop bit13 pin41
    pinMode(BUSY, INPUT); // busy bit12 pin40
    pinMode(EN, OUTPUT); // EN bit11 pin39
    pinMode(RST, OUTPUT); // rst bit10 pin38
    flag_cmd_symb = 0;
}

Комментарии и названия параметров дают представление о том, что инициализируется и о режиме ввода вывода для конкретного пина.

Несколько об алгоритме тестирования. Собственное тестирование свелось к передаче команд и символов на дисплей lcd_1602.

Цикл для передачи команд и символов. Первое, что необходимо сделать перед началом передачи это предварительно обработать команду либо символ и подготовить к передаче массив байт, которые может воспринять дисплей lcd_1602.


for(int k = 0; k < 4; k++){ // cmd_arr[3..0], 0
  if (flag_cmd_symb == 0) { // prepare command 0x30
    up = cmd_arr[k] & 0xF0; // cnt_cmd 0, 1..3
    lo = (cmd_arr[k] << 4) & 0xF0; // 0x10
    data_arr[0] = up | sufx_arr[0]; // 0x0C; (0x3C)
    data_arr[1] = up | sufx_arr[1]; // 0x08; (0x38)
    data_arr[2] = lo | sufx_arr[0]; // 0x0C; (0x0C)
    data_arr[3] = lo | sufx_arr[1]; // 0x08; (0x08)
  }else{ // prepare symbol
    up = symb_arr[k] & 0xF0; // cnt_symb 0, 1..3 0x41
    lo = (symb_arr[k] << 4) & 0xF0; // 0x10
    data_arr[0] = up | sufx_arr[2]; // 0x0D; (0x4D)
    data_arr[1] = up | sufx_arr[3]; // 0x09; (0x49)
    data_arr[2] = lo | sufx_arr[2]; // 0x0D; (0x1D)
    data_arr[3] = lo | sufx_arr[3]; // 0x09; (0x19)
  }
  ...
  flag_cmd_symb = flag_cmd_symb==0 ? 1:0;

Обработка команды.

Взять команду из массива команд. Создать из байта команды два байта up и lo так, что каждый будет содержать в старших битах старший и младший полубайты исходной команды. Затем, из этих двух байт создать 4 байта с соответствующими суффиксами 0x0C, 0x08. Предварительная подготовка символа отличается только суффиксами 0x0D, 0x09.

Итого, для каждого одного байта команды или символа создаётся 4 байта, которые и будут переданы в устройство lcd_1602. Так требует сам дисплей.

Далее начинается цикл передачи подготовленных байт. Беру первый байт и по битно устанавливаю его на пинах (шине) данных.


for (int l = 0; l< 4; l++) { // set byte to bus
    for (int i = 0; i < 8; i++) {
        if (data_arr[l] & mask) {
            digitalWrite(i + 44, HIGH);
        } else {
            digitalWrite(i + 44, LOW);
        }
        mask = mask << 1;
    } // i

Далее следует процедура передачи подготовленного байта в модуль i2c. Передача байта осуществляется в соответствии с алгоритмом представленном на рисунке 2.


for(int i = 0; i < 8; i++){
  signal_l(O_RDE, HIGH);
  switch(opt_proc){
    case 0: // START
    digitalWrite(O_RDE, HIGH);
    if(digitalRead(BUSY) == 0){
      delay(10000);
      opt_proc = 1;
    }
  break;
  case 1:
    if(digitalRead(O_RDE) == 0){
      digitalWrite(O_RDE, LOW);
      delay(10000);
      opt_proc = 2;
    }
  break;
  case 2:
    if(digitalRead(I_RDE) == 1){
      digitalWrite(O_RDE, HIGH);
      delay(10000);
      opt_proc = 3;
    }
  break;

В первых трёх кейсах осуществляется передача первого байта. Далее, при помощи сигналов EN/BUSY активируется устройство i2c и передаются остальные байты, пока не будут переданы все.

Далее, я визуально определяю правильность управления этим дисплеем. Это достигалось путём наблюдения за светодиодами, которые зажигались на экране дисплея так, чтобы из них сложилось слово “Hello”. Надо отметить, что такая комбинация светодиодов получилась далеко не сразу.

Логический анализатор сигналов

Также, я использовал WeAct USB логический 8-ми канальный анализатор, 24 МГц. Стоимость этого анализатора на Алиэкспресс около 600 рублей. Софт установил с github. Всё заработало. Этот анализатор позволил отслеживать сигналы на линии связи i2c. Анализатор делает выборку сигналов с линии и отображает как бы стационарную картинку. Значения байт данных каждый раз определялось верно. При указании протокола, который используется на линии, анализатор хорошо распознавал этот протокол. Я пользовался протоколом i2c. О других протоколах ничего сказать не могу.

Выводы

Что достигнуто

Работа со стендом, рисунок 3, позволила мне быстро достигнуть следующего:

  • создать физически воплощённый стенд, на котором я мог физически наблюдать сигналы и работу проектируемого устройства во взаимодействии как с оконечным устройством, так и с устройством управления;
  • так как, в качестве устройства управления я использовал микроконтроллер и программу к нему, то это позволило быстро определить минимальный необходимый интерфейс для того, чтобы проектируемое устройство начало работать;
  • такая конфигурация позволяет программно определять дополнительные функции для реализации в устройстве управления и потом поэтапно реализовывать эти функции в схеме FPGA, что значительно упрощает разработку и отладку конечного устройства;

Над чем нужно еще поработать

Основное направление дальнейшей работы это расширение функций устройства
управления:

  • внедрение в устройство управления в качестве буфера данных стека FIFO, это сейчас модно;
  • внедрение регистров управления, чтобы можно было задавать различные режимы работы приёмо передатчика i2c;
  • внедрение регистра статуса для возможности отслеживания состояния приёмо передатчика i2c, обработки ошибок;
  • внедрение регистра прерываний для управления устройством по прерываниям.

Конечно, можно придумать и еще массу других фишек, например, если представить работу i2c в составе SoC. Сам приёмо передатчик также может быть доработан. И здесь не имеет смысла много об этом говорить, так как эти вещи зависят от конкретных потребностей и конкретного окружения.

Практическая философия

Или ответы на вопросы “Почему...?”

Почему Ардуино? Я пытался вначале обойтись одним верилогом. Пытался честно и добросовестно. Но не получилось. Получались какие-то громоздкие схемы, которые также приходилось отлаживать сами по себе. Это отнимало время от отладки основной схемы и от проведение исследований по разработке непосредственно устройства управления схемой i2c. А задача у меня стояла именно разработка интерфейса и схемы управления. Порыв в интернете я посмотрел как народ пытается отлаживать свои схемы. В этом направлении разработанно множество подходов и инструментов. Я сейчас не веду речь о закрытых, фирменных, проприетарных инструментах. Они хороши, но на данный момент могут быть не доступны, они дороги и они не наши. Поэтому я исследовал только открытые инструменты. В большинстве использовался язык Python. Я не хотел тратить время на то, чтобы вкуривать философию питона. Есть и другие подходы с использованием языка С и С++. Это мне было ближе, но в целом эти инструменты либо очень наворочены и громоздки, либо находятся на зачаточном уровне курсовой студенческой работы. Я хочу сказать, что диапазон очень широк.

Я хотел что-то, чем я мог бы пользоваться на “живом” железе и при этом обходиться минимумом сторонних средств, не тратя много времени на их изучение. Таким образом я и пришел к связке Ардуино - FPGA. Это позволило мне очень быстро написать отладочную программу. И я выполнил свою первую задачу. Я увидел, что устройство i2c работает так, как я задумал. Что этим устройством можно управлять и строить на его основе более функциональные устройства i2c

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

Так же, ни что не мешает создать отладочный модуль и на FPGA, но это уже будет другая история с RISC-V процессором и всеми делами.

Список литературы

[1]  Схема электрическая принципиальная. Arduino Due. Arturo Guadalupi. 2.22.2021. URL: https://content.arduino.cc/assets/ArduinoDUE_V02g_sch.pdf.

      Мотивировать автора     

     Поддержать FPGA комьюнити     

Оставить комментарий/отзыв

 

908
0
0.0

Всего комментариев : 0
avatar

FPGA-Systems – это живое, постоянно обновляемое и растущее сообщество.
Хочешь быть в курсе всех новостей и актуальных событий в области?
Подпишись на рассылку

ePN