FPGA (ПЛИС) — это программируемые логические интегральные схемы, которые могут выполнять параллельные вычисления со скоростью гигагерц. Мы подключим Lattice iCE40 через SPI и запрограммируем его на лету!
Схема подключения:
| Пин Arduino | Пин FPGA (iCE40) | Назначение |
|---|---|---|
| D10 (SS) | CS | Chip Select |
| D11 (MOSI) | SI | Master Out Slave In |
| D12 (MISO) | SO | Master In Slave Out |
| D13 (SCK) | SCK | Serial Clock |
| D9 | CRESET | Configuration Reset |
| D8 | CDONE | Configuration Done |
Код для программирования FPGA:
#include <SPI.h>
#include <avr/pgmspace.h>
#define FPGA_CS 10
#define FPGA_CRESET 9
#define FPGA_CDONE 8
// Битстрим FPGA (в PROGMEM)
const uint8_t fpga_bitstream[] PROGMEM = {
// ... (бинарные данные конфигурации)
};
void send_bitstream_bit(uint8_t bit) {
static uint8_t byte = 0;
static uint8_t bit_pos = 0;
if (bit) {
byte |= (1 << (7 - bit_pos));
}
bit_pos++;
if (bit_pos == 8) {
SPI.transfer(byte);
byte = 0;
bit_pos = 0;
}
}
void programFPGA() {
// Инициализация SPI
SPI.begin();
SPI.setDataMode(SPI_MODE0);
SPI.setBitOrder(MSBFIRST);
SPI.setClockDivider(SPI_CLOCK_DIV4); // 4 МГц
// Сброс FPGA
digitalWrite(FPGA_CRESET, LOW);
delay(10);
digitalWrite(FPGA_CRESET, HIGH);
delay(10);
// Ждем, пока FPGA будет готов
while (!digitalRead(FPGA_CDONE)) {
delay(1);
}
// Отправляем битстрим
digitalWrite(FPGA_CS, LOW);
uint16_t bitstream_size = sizeof(fpga_bitstream) * 8;
for (uint16_t i = 0; i < bitstream_size; i++) {
uint8_t bit = pgm_read_byte(&fpga_bitstream[i / 8]) & (1 << (7 - (i % 8)));
send_bitstream_bit(bit);
}
// Завершаем программирование
digitalWrite(FPGA_CS, HIGH);
delay(10);
// Проверяем успешность
if (digitalRead(FPGA_CDONE)) {
Serial.println("FPGA успешно запрограммирован!");
} else {
Serial.println("Ошибка программирования FPGA!");
}
}
// Отправка данных на FPGA (пример: управление светодиодами)
void sendToFPGA(uint8_t data) {
digitalWrite(FPGA_CS, LOW);
SPI.transfer(data);
digitalWrite(FPGA_CS, HIGH);
}
void setup() {
Serial.begin(115200);
pinMode(FPGA_CS, OUTPUT);
pinMode(FPGA_CRESET, OUTPUT);
pinMode(FPGA_CDONE, INPUT);
digitalWrite(FPGA_CS, HIGH);
programFPGA();
}
void loop() {
// Отправляем данные на FPGA каждые 100 мс
static uint8_t counter = 0;
sendToFPGA(counter++);
delay(100);
}
Verilog-код для FPGA (простой счетчик):
verilog
module counter (
input clk, // 16 МГц от Arduino
input rst,
input [7:0] data, // Данные от Arduino (SPI)
output reg [7:0] led
);
reg [31:0] counter = 0;
always @(posedge clk or posedge rst) begin
if (rst) begin
led <= 8'b0;
counter <= 0;
end else begin
counter <= counter + 1;
if (counter % 1000000 == 0) begin
led <= data; // Обновляем светодиоды из SPI-данных
end
end
end
endmodule