Low Cost FPGA Konfiguration
Einleitung
Wenn man FPGAs auf selbst entworfenen Platinen einsetzen möchte, stellt sich oft das Problem des Konfigurationsspeichers. Die meisten FPGAs sind SRAM-basiert und haben keinen nichtflüchtigen Speicher auf dem Chip bzw. im gleichen Gehäuse (Ausnahmen sind Spartan-3N von Xilinx, XP und XP2 von Lattice und die FPGAs von Actel in Antifuse-Technologie). Also muss irgendwie ein Speicher her. Dazu gibt es mehrere Möglichkeiten.
Konfigurationsmethode | Vorteile | Nachteile |
---|---|---|
PC mit Programmierkabel | einfache und schnelle Programmierung | Platine kann nur mit PC genutzt werden |
Spezial-PROM z. B. Xilinx XCFxxS |
einfachste Anwendung | hoher Preis schlechte Verfügbarkeit für Hobbybastler |
Standard-EEPROM mit SPI | einfache Anwendung billig |
nur bei einigen FPGA-Familien möglich (z. B. Spartan3E) |
Mikrocontroller mit internem oder externem Flash |
sehr gute Verfügbarkeit für Hobbybastler billig |
zusätzlicher Mikrocontroller nötig, wenn das FPGA allein auf der Platine betrieben wird Zusatzaufwand für die Programmierung des EEPROMs und Mikrocontrollers |
Dieser Artikel soll die letzte Methode näher beleuchten. Dabei wird ein FPGA vom Typ Spartan 2 von Xilinx sowie ein Mikrocontroller der AVR-Familie vom Typ Tiny12 von Atmel eingesetzt. Da die FPGAs anderer Hersteller aber sehr ähnlich konfiguriert werden, kann man das Ganze leicht anpassen.
FPGA Konfiguration mit Mikrocontroller
Für kleine bis mittlere FPGAs wird nur verhältnismässig wenig Konfigurationsspeicher benötigt. Auf der anderen Seite gibt es kleine EEPROMs im SO-8 Gehäuse mit I2C Schnittstelle. Damit kann sehr kostengünstig und platzsparend die Konfiguration gespeichert werden. Nun braucht man nur noch einen kleinen Mikrocontroller, welcher das EEPROM ausliest und die Daten zum FPGA schickt. Glücklicherweise gibt es auch die im sehr kleinen SO-8 Gehäuse. Damit ist die Lösung sehr platzsparend.
FPGA-Familie | Typ | Konfiguration [Bit] |
EEPROM-Anzahl | Konfigurations- zeit [s] I2C mit 400kBit/s | ||
---|---|---|---|---|---|---|
24C128 | 24C256 | 24C512 | ||||
Spartan 2 | XC2S15 | 197.696 | 2 | 1 | 1 | 0,5 |
XC2S30 | 336.768 | 3 | 2 | 1 | 0,8 | |
XC2S50 | 559.200 | 5 | 3 | 2 | 1,4 | |
XC2S100 | 781.216 | 6 | 3 | 2 | 2 | |
XC2S150 | 1.040.096 | 8 | 4 | 2 | 2,6 | |
XC2S200 | 1.335.840 | * | 6 | 3 | 3,3 | |
Spartan 3 | XC3S50 | 439.264 | 4 | 2 | 1 | 1,1 |
XC3S200 | 1.047.616 | 8 | 4 | 2 | 2,6 | |
XC3S400 | 1.699.136 | * | 7 | 4 | 4,2 | |
XC3S1000 | 3.223.488 | * | * | 7 | 8,1 |
Schaltung
Die Schaltung ist recht einfach. Über den I2C-Bus wird ein oder mehrere EEPROMs ausgelesen. Zur Konfiguration sind nur die vier Signale CCLK, Din, Done und PROGRAM benötigt. Der FPGA wird im Slave Serial Mode betrieben. Da der 8-polige Mikrocontroller aber nur 5 wirklich freie IO-Pins hat, müssen Reset und PROGRAM verbunden werden. Das ist aber kein Problem, im Gegenteil, hier werden FPGA und Mikrocontroller parallel in den Resetzustand versetzt, wenn die Versorgungsspannung angelegt wird oder manuell PROGAMM auf LOW gezogen wird. Es ist jeder beliebige AVR verwendbar, da das Programm sehr klein ist und keinerlei spezielle Resourcen benötigt, nicht einmal SRAM. Es können EEPROMs mit 128, 256 oder 512kbit eingesetzt werden. Allerdings müssen alle die gleiche Grösse haben. Eine LED am Signal SDA wird zur Fehleranzeige verwendet. Es sollte ein Low Current Typ mit niedriger Flusspannung sein (also keinen blauen oder weissen LEDs). R5 dient der Entkopplung von DONE zur ISP-Schnittstelle. Damit kann der AVR in der Schaltung programmiert werden.
Programmierung des Mikrocontrollers
Die Programmierung des Konfigurationsprogramms erfolgt in Assembler. Zum einen um eine minimale Programmgröße und maximale Geschwindigkeit zu erzielen. Zum anderen, weil kleine AVRs ohne SRAM vom AVR-GCC nicht unterstützt werden. Das ist aber unkritisch, das Programm ist klein und damit überschaubar.
Nach dem Reset wird der Oszillator auf maximalen Takt gestellt, der ist beim Tiny12 sowieso nicht so hoch, max. 2,5 MHz. Dann werden die IOs und Variablen initialisiert. Am I2C-Bus können maximal acht EEPROMs angeschlossen werden, weil diese ICs nur maximal drei konfigurierbare Adressbits besitzen, einige Typen sogar nur zwei. Wenn die Größe der Konfigurationsdatei die Größe eines einzelnen EEPROMS übersteigt, muss schrittweise aus den einzelnen EEPROMs gelesen werden. Dazu muss der jeweilige EEPROM zum Beginn adressiert werden. Danach können lückenlos die Daten aus dem EEPROM gelesen werden. Nachdem alle Bytes geladen wurden wird noch ein zusätzliches Byte geschickt, um die Startsequenz des FPGAs auszulösen. Ist die Konfiguration erfolgreich verlaufen ist danach der FPGA in Funktion. Das wird durch das Signal Done angezeigt.
.include "tn12def.inc"
;*******************************************************************************
;*
;* A small but fine FPGA configurator
;* using a Tiny 12 and serial EEPROMs
;*
;* Up to eigth EEPROMs can be cascaded on the I2C bus
;* All devices must be of same size
;*
;* theoritical limit is 8x64kB = 512 kB
;*
;* Examles for FPGA config size
;* Spartan-II : XC2S200(biggest family member): 166,980 Bytes
;* Spartan-3 : XC3S1000 : 402,936 Bytes
;*
;* Configuration speed is ~8.5kBytes/s @ 2MHz
;* Top speed is ~ 43kB/s @ 10 MHz, 400kHz limit of I2C
;*
;* example uses a Xilinx XC2S30 with 42.096 bytes config size
;* and a ST24C512 with 64 kB
.equ fpga_size = 42096; ; FPGA config file size
.equ EEPROM_size = 65536; ; EEPROM size per device
.equ F_CPU_MHz = 2; ; CPU clock in MHz, 1..10
.equ bitreverse = 0
;* = 0 , bits will be copied bit by bit from EEPROM to FPGA, faster configuration
;* binary files must have same bitorder as required by FPGA (MSB first)
;* For Xilinx, the bit files must be processed by bitdreher.exe!!!
;* = 1 , bits will be copied byte by bytes from EEPROM and written bit reversed to FPGA, slow configuration
;* binary files must have reverse bitorder as required by FPGA (LSB first)
;* For Xilinx, the bit files are generated this way by default
;*******************************************************************************
.equ cfg_port = portb
.equ cfg_ddr = ddrb
.equ cfg_pin = pinb
.equ DIN = PB0 ; FPGA serial configuration
.equ DONE = PB1
.equ CCLK = PB2
.equ SDA = PB3 ; Connection to I2C EEPROM
.equ SCL = PB4
; Reset is connected to FPGA AND AVR, so we have a automatic Power-on reset
; some marcos to support readability
.macro SDA_LOW
sbi cfg_ddr, sda ; open drain, low
.endmacro
.macro SDA_HIGH
cbi cfg_ddr, sda ; open drain, high
.endmacro
.macro SCL_LOW
sbi cfg_ddr, scl ; open drain, low
.endmacro
.macro SCL_HIGH
cbi cfg_ddr, scl ; open drain, high
.endmacro
.macro DIN_LOW
cbi cfg_port, din ; push pull
.endmacro
.macro DIN_HIGH
sbi cfg_port, din ; push pull
.endmacro
.macro CCLK_LOW
cbi cfg_port, cclk ; push pull
.endmacro
.macro CCLK_HIGH
sbi cfg_port, cclk ; push pull
.endmacro
.macro i2c_error_check
brts PC+2
rjmp error_i2c
.endmacro
; add a delay to reach given delay time
; usage
; delay_1 time [Unit 0.1us], clocks_already_done
.macro delay
; calculate number of remaining clocks
; +1 is safety margin to account for integer truncation
.set clks = @0*F_CPU_MHz/10-@1+1
; use optimized delay blocks with "nonsense" commands to have maximum
; delay with minimum code size
.if clks==1
nop
.endif
.if clks==2
ld null, z
.endif
.if clks==3
lpm
.endif
.if clks==4
lpm
nop
.endif
.if clks==5
lpm
ld null, z
.endif
.if clks==6
lpm
lpm
.endif
.if clks==7
lpm
lpm
nop
.endif
.if clks==8
lpm
lpm
ld null,z
.endif
.if clks==9
lpm
lpm
lpm
.endif
.if clks==10
lpm
lpm
lpm
nop
.endif
.if clks==11
lpm
lpm
lpm
ld null, z
.endif
.if clks==12
lpm
lpm
lpm
lpm
.endif
.if clks==13
lpm
lpm
lpm
lpm
nop
.endif
.if clks==14
lpm
lpm
lpm
lpm
ld null, z
.endif
.endmacro
.def zero = r1 ; always zero
.def one = r2 ; always one
.def null = r3 ; write only ;-)
.def tmp1 = r16 ; general purpose
.def tmp2 = r17
.def tmp3 = r18
.def cnt0 = r19 ; loop counter, 24 Bit
.def cnt1 = r20
.def cnt2 = r21
.def i2c = r22 ; I2C address, used for multiple devices
.def abs0 = r23 ; data counter, 24 Bit
.def abs1 = r24 ;
.def abs2 = r25
;*
;*******************************************************************************
.cseg
; lets go
; initialize stack
; hardware stack for Tiny12, no init necessary
; full speed, ~2 MHz with ATtiny12
ldi tmp1,0xFF
out osccal, tmp1
; config IOs
ldi tmp1, (1<<cclk) | (1<<din)
out cfg_ddr,tmp1
ldi tmp1, (1<<done)
out cfg_port,tmp1 ; internal pull up for DONE
; generate constant registers
sub zero,zero
ldi tmp1,1
mov one,tmp1
ldi i2c,0xA0 ; I2C base address
; set byte counter
ldi abs0,byte1(fpga_size)
ldi abs1,byte2(fpga_size)
ldi abs2,byte3(fpga_size)
; wait 10ms for FPGA to finish power up and clear config space
ldi tmp1,10
rcall wait
; when using multiple EEPROMs, we must address them individual
device_loop:
; number of remaining bytes >EEPROM_size ?
ldi tmp1,byte1(EEPROM_size)
ldi tmp2,byte2(EEPROM_size)
ldi tmp3,byte3(EEPROM_size)
cp abs0,tmp1
cpc abs1,tmp2
cpc abs2,tmp3
brge device_loop_big ; >= EEPROM_size
; less than EEPROM_size, copy remaining bytes
mov cnt0,abs0 ; remaining bytes
mov cnt1,abs1
mov cnt2,abs2
mov abs0,zero ; set zero
mov abs1,zero
mov abs2,zero
rjmp device_loop_init
device_loop_big:
mov cnt0,tmp1 ; EEPROM_size loop
mov cnt1,tmp2
mov cnt2,tmp3
sub abs0,tmp1 ; - EEPROM_size
sbc abs1,tmp2
sbc abs2,tmp3
device_loop_init:
subi cnt0,1 ; -1, since last byte must be read with no ACK
sbci cnt1,0 ; outside the loop
sbci cnt2,0
; write first adress
rcall i2c_start
mov tmp1, i2c ; load i2c address
rcall i2c_write
i2c_error_check
ldi tmp1, 0 ; write adress 0
rcall i2c_write
i2c_error_check
ldi tmp1, 0
rcall i2c_write
i2c_error_check
rcall i2c_stop
rcall i2c_start
mov tmp1, i2c ; load i2c address
subi tmp1,-1 ; +1, read access
rcall i2c_write
i2c_error_check
set ; set T-Flag, continous reading
main_loop:
.if bitreverse==1
; configuration uses online bit reverse, slow
rcall i2c_read
rcall fpga_write
.else
; configuration uses offline bit reverse, fast (bitdreher.exe)
; read a byte from I2C and parallel send it to the FPGA
; fast version
ldi tmp2, 8 ; loop counter
main_bit_loop:
scl_high ; SCL rising edge
sbic cfg_pin,sda ; copy SDA to Din
din_high
sbis cfg_pin,sda
din_low
delay 7, 6 ; minimum LOW time 0,6µs + 0.1µs safty margin
scl_low ; falling edge generates new bit
cclk_high ; LOW time min. 9 CLKs
cclk_low
delay 14, 9 ; minimum HIGH time 1,3µs + 0.1µs safty margin
dec tmp2
brne main_bit_loop
; write ACK to EEPROM
sda_low ; write ACK, more to read
delay 1, 0
scl_high
delay 7, 2
scl_low
sda_high
delay 14, 10
.endif
subi cnt0,1 ; decrement data counter
sbci cnt1,0
sbci cnt2,0
brne main_loop
clt ; no ACK for last byte of block
rcall i2c_read
rcall fpga_write
rcall i2c_stop
subi i2c,-2 ; +2, increment I2C address bits
; number of remaining data bytes = 0 ?
cp abs0,zero
cpc abs1,zero
cpc abs2,zero
breq main_end ; nothing left to copy, finish
rjmp device_loop ; process next data block
main_end:
ldi tmp1,0
rcall fpga_write ; one more dummy byte for FPGA startup
ldi tmp1,1
rcall wait ; wait for DONE to go HIGH (open drain)
sbis cfg_pin, done ; check if DONE is HIGH (= FPGA config OK)
rjmp error_fpga ; something went wrong during configuration
ldi tmp1, (1<<SE) | (1<<SM)
out mcucr,tmp1 ; power down sleep mode
sleep ; good night
; no wake up here, only through reset
; i2c has no ACK, fast blinking
error_i2c:
sda_low
ldi tmp1,100
rcall wait
sda_high
ldi tmp1,100
rcall wait
rjmp error_i2c
; FPGA configuration error, DONE stays low, slow blinking
error_fpga:
sda_low
ldi tmp1,250
rcall wait
ldi tmp1,250
rcall wait
sda_high
ldi tmp1,250
rcall wait
ldi tmp1,250
rcall wait
rjmp error_fpga
; *****************************************************************************
; functions
; *****************************************************************************
; just wait N*1ms, N is given in tmp1
wait:
ldi tmp2,20*F_CPU_MHz
wait_1:
ldi tmp3,16
wait_2:
dec tmp3
brne wait_2
dec tmp2
brne wait_1
dec tmp1
brne wait
ret
; *****************************************************************************
; write a byte to I2C
; input : tmp1 : data
; output : T-flag : ACK (0= NACK (SDA high), 1 = ACK (SDA low))
i2c_write:
ldi tmp2, 8 ; loop conter
i2c_write_loop:
sbrs tmp1,7 ; copy MSB to SDA
sda_low
sbrc tmp1,7
sda_high
delay 14, 8
scl_high
delay 7, 2
scl_low
lsl tmp1 ; get next bit
dec tmp2
brne i2c_write_loop
; check ACK from EEPROM
sda_high
delay 14, 5
scl_high
clt ; clear T-Flag, = no ACK!
sbis cfg_pin,sda ; check SDA is ACK=0 (positive ACK)
set ; ACK=0, OK
delay 7, 5
scl_low
delay 14, 7
ret
; *****************************************************************************
; read a byte from I2C
; input : T-flag : ACK, (0= NACK (SDA high), 1 = ACK (SDA low))
; output : tmp1 : data
i2c_read:
ldi tmp2, 8 ; loop conter
i2c_read_loop:
scl_high
clc ; copy SDA to carry
sbic cfg_pin, sda ; read SDA
sec ; set carry
rol tmp1 ; shift in next bit
delay 7, 6
scl_low ; minimum pulse width LOW = 1.3µs = 13 clks @10 MHz
delay 14, 5
dec tmp2
brne i2c_read_loop
; write ACK to EEPROM
brtc i2c_read_no_ack
sda_low ; write ACK, more to read
rjmp i2c_read_send_ack
i2c_read_no_ack:
sda_high ; no ACK, stop reading
i2c_read_send_ack:
delay 14, 6
scl_high
delay 7, 2
scl_low
sda_high ; release SDA
ret
; *****************************************************************************
; Create a I2C START Condition
i2c_start:
delay 5, 2
sda_low
delay 5, 2
scl_low
delay 30, 7
ret
; *****************************************************************************
; Create a I2C STOP Condition
i2c_stop:
delay 5, 2
sda_low
delay 5,2
scl_high
delay 5,2
sda_high
delay 30, 7
ret
; *****************************************************************************
; write a byte to FPGA, with bit reversal
; input : tmp1 : data
.if bitreverse==1
.message "Bit reverse ON, slow configuration."
; configuration uses online bit reverse, slow
; bit reverse, LSB first
fpga_write:
ldi tmp2, 8 ; loop conter
fpga_write_loop:
sbrs tmp1,0 ; copy LSB to DIN
din_low
sbrc tmp1,0
din_high
cclk_high ; generate cclk pulse
cclk_low
lsr tmp1 ; get next bit
dec tmp2
brne fpga_write_loop
ret
; *****************************************************************************
.else
.message "Bit reverse OFF, fast configuration."
; configuration uses offline bit reverse, fast (bitdreher.exe)
; no bit reverse, MSB first
fpga_write:
ldi tmp2, 8 ; loop conter
fpga_write_loop:
sbrs tmp1,7 ; copy MSB to DIN
din_low
sbrc tmp1,7
din_high
cclk_high ; generate cclk pulse
cclk_low
lsl tmp1 ; get next bit
dec tmp2
brne fpga_write_loop
ret
; *****************************************************************************
.endif
Fehlererkennung
Seitens des FPGAs ist Done ein Open Drain Ausgang. Im AVR wird der interne Pull-Up eingeschaltet, um das Signal auf HIGH ziehen zu können. Ist jedoch ein Fehler aufgetreten (CRC-Fehler im Datenstrom), bleibt Done auf LOW. Der AVR prüft Done am Ende der Konfiguration. Ist Done gleich HIGH, geht er in den Power Down Sleep Mode um Strom zu sparen. Ist aber ein Fehler aufgetreten und Done somit LOW, wird das durch langsames Blinken der LED an SDA angezeigt (~1 Hz). Tritt während der Adressierung des EEPROMs ein Fehler auf (kein ACK vom EEPROM), dann wird dies durch schnelles Blinken der LED angezeigt (~5 Hz). Im Normalfall treten diese Ereignisse nur sehr selten auf, z. B. bei einem EEPROM-Defekt durch Alterung/Datenverlust oder einer Störung der Datenübertragung durch starke Störimpulse. Aber zur Programmierung und zum Testen sind sie sehr nützlich.
Nutzung
Die Nutzung der Schaltung ist recht einfach. Im Quellcode müssen nur drei Variablen an das jeweilige Projekt angepasst werden. Soll ein anderer AVR-Typ verwendet werden können auch die Pins einfach zugewiesen werden. Danach wird das Programm assembliert und per ISP in den AVR geschrieben. Abschliessend sollten die Fuses gesetzt werden. Der Takt des interen RC-Oszillators sollte möglichst hoch gewählt werden, bis ca. 10 MHz ist das Progamm ohne Änderungen nutzbar. Wenn verfügbar sollte der Brown Out Detector eingeschaltet werden und mit ca. 2,7V Schwellspannung betrieben werden. Für den hier verwendeten Tiny12 muss das Fuse-Byte mit 0x12 beschrieben werden. HALT! Wenn jetzt der Reset gelöst wird läuft der AVR sofort los und versucht die Daten aus den EEPROMs zu lesen. Da diese aber noch nicht programmiert sind werden keine sinnvollen Daten ins FPGA geladen. Das schadet dem FPGA zwar nicht, aber die Konfiguration scheitert! In der Folge wird SDA vom AVR kontinuierlich zwischen LOW und HIGH umgeschaltet, um den Fehler durch Blinken der LED zu signalisieren. Damit ist aber keine Programmierung der EEPROMs mehr möglich!
Mögliche Auswege:
- RESET auf LOW halten
- die EEPROMs vor dem AVR programmieren
Im Normalfall wird man den zweiten Weg wählen. Denn während der Entwicklung wird man meist das FPGA über JTAG konfigurieren. Erst wenn alles komplett funktioniert wird man die Konfiguration einmalig in den EEPROM schreiben.
Hinweis! Wird während der Entwicklungsphase das FPGA über JTAG programmiert, muss in den Optionen für "Generate Programming File" unter Startup Options -> FPGA Start-up Clock "JTAG" gewählt werden.
Die Programmierung der EEPROMs erfolgt mit Ponyprog. Mittels einfachem Adapter kann man direkt auf den I2C-Bus gehen, es werden nur SDA, SCL und GND benötigt, die Pull-Ups sind schon auf dem Board. Das Board muss dazu natürlich mit Spannung versorgt werden.
Der Ablauf der EEPROM-Programmierung sieht wie folgt aus:
- In den Optionen für "Generate Programming File" muss unter Startup Options -> FPGA Start-up Clock "CCLK" gewählt werden.
- Im Xilinx ISE den kompletten Synthesezyklus inclusive "Generate Programming File" durchlaufen.
- IMPACT starten und eine PROM-Datei im BIN Format erzeugen.
- Jetzt hat man die Wahl zwischen zwei Möglichkeiten.
- Die Daten direkt in den EEPROM schreiben. Dann müssen sie beim Lesen und anschliessender Ausgabe zum FPGA in der Reihenfolge der Bits vertauscht werden, das kostet natürlich Zeit
- Die Daten mit einem kleinen Tool Bitdreher umwandeln. Dabei wird die Bitverdrehung vorher durchgeführt. Die Daten können damit ohne zusätzliche Verdrehung schnell ins FPGA geschrieben werden.
- Ponyprog starten, EEPROM Familie "IC Bus 16bit eeprom" auswählen, den jeweiligen Typ auch auswählen (25C128, 24C256, 24C512).
- Die Bin-Datei laden und "Write Device" ausführen.
- Das erfolgreiche Programmieren und Verifizieren wird von Ponyprog angezeigt.
Wenn die FPGA-Konfiguration grösser als ein EEPROM ist, muss die Datei in mehrere Stücke aufgeteilt werden. Das kann man mit IMPACT machen oder promgen direkt von der Kommandozeile aufrufen. Die Option -s <size> erlaubt das Aufteilen der Konfigurationsdaten in kleinere Dateien. Beachtet werden muss dabei, dass die einzelnen Blöcke exakt so gross sein müssen wie ein einzelner EEPROM. Ausser natürlich der letzte Block, dessen Länge ergibt sich aus (Dateigrösse MODULO EEPROM-Grösse). Die einzelnen Dateien können dann einfach per Ponyprog in die EEPROMs geschrieben werden.
Achtung!
- Dabei muss man aufpassen, dass die Reihenfolge nicht verwechselt wird! Der erste Block muss in den EEPROM mit Adresse 0, der zweite in den mit Adresse 1 usw.
- Wenn man mit Ponyprog mehrere EEPROMs an einem Bus programmieren will, muss die Adresse der EEPROMs manuell in der Datei PONYPROG2000.INI in der Zeile
I2CBaseAddress=0xA0
- eingetragen werden (0xA0, 0xA2, 0xA4, 0xA6, 0xA8, 0xAA, 0xAC, 0xAE). Nach jeder Änderung muss Ponyprog neu gestartet werden.
Leistung
Auf einem Tiny12 mit voll aufgedrehtem RC-Oszillator (ca. 2 MHz) und einer Online Bitverdrehung (bitreversal=1) erreicht man eine Geschwindigkeit von ca. 8,5kB/s, d.h. der im Test verwendete FPGA vom Typ XC2S30 mit 42096 Bytes Konfigurationsspeicher wird in ca. 5s konfiguriert. Nicht gerade berauschend, aber ausreichend. Der Grund dafür liegt nicht nur in der begrenzten Geschwindigkeit des I2C Busses (400kHz), sondern in einer Merkwürdigkeit der Konfigurationssoftware von Xilinx. Diese verdreht nämlich die Bits innerhalb der Bytes aus fadenscheinigen Gründen (Bit 0<->7, Bit 1<->6, etc.). Damit muss aber immer zunächst ein Byte vollständig gelesen werden (MSB zuerst) und dananch in umgekehrter Reihenfolge ausgegeben werden (LSB zuerst). Das kostet einiges an Zeit. Damit werden bei 2 MHz nur etwa 15% der maximalen Geschwindigkeit erreicht, dementsprechend sind die Konfigurationszeiten etwa sechs mal so lang wie in der Tabelle oben angegeben. Mit dem Parameter bitreversal=0 und der Bearbeitung der Konfigurationsdaten mit dem Tool Bitdreher erreicht man eine Konfigurationszeit von ca 3s, 40% schneller! Die erreichbaren Konfigurationszeiten sind in nachfolgender Tabelle exemplarisch angegeben, mit dem in Klammern angegebenen Faktor kann man direkt in die zweite Tabelle gehen und die reale Konfigurationszeit ausrechnen. Bei höherem Prozessortakt werden längere Pausen eingefügt, sodass die minimalen Pulszeiten für 400kHz auf dem I2C-Bus eingehalten werden. Dies wird mit dem schönen, leistungsfähigen Makro delay erreicht.
Takt [MHz] | Konfigurationszeit [s] (Faktor) | |
---|---|---|
bitreversal=0 | bitreversal=1 | |
2 | 3,0 (3,8) | 4,8 (6) |
5 | 1,2 (1,5) | 2,1 (2,6) |
10 | 0,9 (1,1) | 1,4 (1,8) |
Zukunftsaussichten
Für grössere FPGAs werden die seriellen EEPROMs irgendwann zu klein und zu langsam. Hier müssen andere Datenträger her. SD-Karten sind klein, billig und weit verbreitet. Auch wenn der Aufwand zu deren Ansteuerung plus Minimalfunktionalität für FAT12/FAT16 um einiges höher liegt, ist dies ein interessanter Ansatzpunkt, der in Zukunft einmal umgesetzt werden kann.
Als Zwischenlösung bieten sich Flashbausteine mit SPI im SO-8 Gehäuse an, die gibt es bis zu unglaublichen 32 Mbit zum Spottpreis, z.b. bei CSD. Allerdings muss dann ein AVR mit zwei zusätzlichen Pins her, hier muss man dann auf ein 20 poliges Gehäuse wechseln. Enthusiasten nehmen das platzsparende MLF20 ;-).
Alternativ könnte geprüft werden, ob der Dataflash eines AVR_Butterfly ausreicht. Siehe: FPGA_Konfiguration_mit_AVR_Butterfly
Diskussion im Forum
- Programm auf Spartan 3A laden
- FPGA synthetisierung
- Einsteigerfreundlicher FPGA
- Spartan 3E mit SPI-Flash
- Spartan 3e: Anfägerhilfe bei Flashspeicherung
- Programmier-Hardware Altera Cyclone-II /EPCS4
- FPGA und CPLD programmieren
Links
- FPGAs von Xilinx
- PonyProg
- Serielle EEPROMs bei Atmel
- Configuring High-density FPGAs using Atmel’s Serial DataFlash® and an AVR® Microcontroller (2003)
- XC-SPI55 Program SPI Serial Flash from Xilinx FPGAs and CPLDs (2005)
- XAPP445 Configuring Spartan-3E FPGAs with SPI Flash Memories (2007)
- XAPP693 CPLD-Based Configuration...for Xilinx Platform Flash PROMs and FPGAs (2005)
- XAPP176 Configuration and Readback of the Spartan-II and Spartan-IIE Families (2002)
- XAPP098 The Low-Cost, Efficient Serial Configuration of Spartan FPGAs (1998)