dEEP FPGA -kurssia Helsinki Hacklabillä
Suovulan muistipointteja kirjasta Real World FPGA Design with Verilog:
Latches vs. Flipflops
- generally both will sample the input signal at clock egde, but latch is transparent when clock signal is low
- Transparent Latch
- Reset Set Latch, RTL: LATRS
- Verilog:
- always @ (data_in or clock)
- if (!clock) begin
- end
- D Flipflop
- Data Flip-flop with Reset and Set, RTL: DFFERS
- Verilog:
- always @ (posedge clock)
- begin
- end
- VHDL:
- begin dff: process (D, CLK)
- begin
- if (rising_edge(CLK)) then
- end if;
- end process dff;
Synchronization
- s.59 "Each FPGA input should drive one and exactly one flipflop."
- s.4 "Always synchronize inputs that are not phase related to the system clock."
- s.4 "Use double-synchronizing flipflops for external signals to minimize metastability problems."
- Verilog:
- always @ (posedge clock)
- begin
- button_sync1 <= button_in;
- button_sync2 <= button_sync1;
- end
- Onko ylläolevat järkeviä päätelmiä?
- Karttu antaa hyväksyntänsä!
CPLD-ohjelmointi JTAGWhisperer-ohjelmalla
Esimerkit Windowsiin, mutta kaikki ohjelmat ovat saatavilla myös muihin käyttöjärjestelmiin.
1. JTAGWhisperer-ohjelma Arduinoon
- lataa JTAGWhisperer osoitteesta https://github.com/sowbug/JTAGWhisperer
- pura zip-paketti Arduinon libraries-hakemistoon
- purkaantuu oletuksena hakemistoon sowbug-JTAGWhisperer-0200a39, hakemiston nimi pitää muuttaa pelkäksi JTAGWhisperer:ksi
- Arduino IDE:ssä pitäisi nyt näkyä File->Examples->JTAGWhisperer->JTAGWhisperer
- avaa tämä, käännä ja uploadaa Arduinoon
2. Python-ympäristön asennus
- Lataa ja asenna Python 2.7 (ei 3.x !) sivulta
http://www.python.org/download/ (python-2.7.2.msi)
- Lataa ja asenna Pythonin sarjaporttikirjasto pyserial sivulta
http://sourceforge.net/projects/pyserial/ (pyserial-2.5.win32.exe)
3. Python-skriptin ja Arduinon yhteistyön testaus
- Windowsin command promptiin
- Siirry JTAGWhisperer-kirjaston hakemistoon
C:\Users\Jari\Documents\Arduino\libraries\JTAGWhisperer
- Anna komento (COM8 = Arduinon sarjaportin numero)
c:\python27\python send_xsvf -p COM8 xsvf\XC9572XL\DeviceID.xsvf
- Homma epäonnistuu, koska ei ole CPLD:tä perässä, mutta pitäisi tulostua suunnilleen:
Ready to send file of size 90 bytes.
Device is ready.
Sent: 64 bytes, 26 remaining
IMPORTANT: SDR check failed.
IMPORTANT: Failure at instruction #7
IMPORTANT: Processed 7 instructions.
IMPORTANT: Checksum 6c2/21.
Received device quit: Exiting!
Expected checksum: 10c1/5a.
Elapsed time: 0.04 seconds.
- Osa näistä tulosteista tulee Arduinon ohjelmalta, joten Python-skripti ja Arduino keskustelevat.
4. CPLD:n kytkeminen Arduinoon
- Kytke piuhat Arduinosta CPLD:hen JTAGWhispererin readme.md-tiedostossa kuvatun mukaisesti:
Arduino pin 8 = TMS
Arduino pin 9 = TDI
Arduino pin 10 = TDO
Arduino pin 11 = TCK
- Myös CPLD:n ja Arduinon maat pitää kytkeä yhteen.
5. CPLD:n ohjelmointi
- Tee iMPACTilla XSVF-muotoinen ohjelmointitiedosto
- Ohjelmoi se sisään samalla komennolla kuin kohdassa 3
- Tuloste pitäisi olla tämän tapainen:
Ready to send file of size 103964 bytes.
Device is ready.
Sent: 103964 bytes, 0 remaining
IMPORTANT: XCOMPLETE
IMPORTANT: Processed 11582 instructions.
IMPORTANT: Checksum 6e06ac/1961c.
Received device quit: Exiting!
Expected checksum: 6e06ac/1961c.
Elapsed time: 43.77 seconds.
- Rivi "IMPORTANT: XCOMPLETE" on merkki siitä, että ohjelmointi meni loppuun saakka.
--------8<----------------8<----------------8<----------------8<----------------8<--------
enum { BufferSize = 1*1024 };
uint8_t buffer[BufferSize];
enum {
SERIAL_DATA = 3,
SERIAL_CLK = 4,
SERIAL_ENABLE = 12,
SERIAL_DELAY = 10,
};
const uint8_t IntelHEXStartCode = ':';
void HALT(uint8_t) {
// Kääk -> HALT
while (true) {
digitalWrite(13, LOW);
delay(500);
digitalWrite(13, HIGH);
delay(500);
}
}
void setup() {
pinMode(13, OUTPUT);
pinMode(11, OUTPUT);
pinMode(SERIAL_DATA, OUTPUT);
pinMode(SERIAL_CLK, OUTPUT);
pinMode(SERIAL_ENABLE, OUTPUT);
digitalWrite(13, LOW);
// Test static allocation
for (size_t i = 0; i < BufferSize; ++i) {
buffer[i] = 0;
}
Serial.begin(9600);
Serial.flush(); // ??
while (Serial.available()) Serial.read(); // Clear input
// All Ok
Serial.print("OK");
Serial.println();
digitalWrite(13, HIGH);
digitalWrite(11, LOW);
delayMicroseconds(1);
digitalWrite(11, HIGH);
}
size_t bytesReceived = 0;
uint32_t lastPrintTime = 0;
bool dirty = false;
uint8_t readHex8() {
while (Serial.available() < 2) { };
int h1 = Serial.read();
int h2 = Serial.read();
uint8_t val = 0;
if (h1 >= '0' && h1 <= '9') val |= (h1 - '0') << 4;
if (h1 >= 'a' && h1 <= 'f') val |= (h1 - 'a' + 10) << 4;
if (h1 >= 'A' && h1 <= 'F') val |= (h1 - 'A' + 10) << 4;
if (h2 >= '0' && h2 <= '9') val |= (h2 - '0') << 0;
if (h2 >= 'a' && h2 <= 'f') val |= (h2 - 'a' + 10) << 0;
if (h2 >= 'A' && h2 <= 'F') val |= (h2 - 'A' + 10) << 0;
return val;
}
uint16_t readHex16BE() {
uint16_t b1 = readHex8();
uint16_t b2 = readHex8();
return (b1 << 8) + b2;
}
uint32_t readHex32BE() {
uint32_t b1 = readHex8();
uint32_t b2 = readHex8();
uint32_t b3 = readHex8();
uint32_t b4 = readHex8();
return (b1 << 24) + (b2 << 16) + (b3 << 8) + b4;
}
uint8_t send_serial_out(uint32_t val, size_t bits) {
uint8_t even_parity = 0;
digitalWrite(SERIAL_CLK, LOW);
digitalWrite(SERIAL_ENABLE, HIGH);
for(size_t i = 0; i < bits; i++) {
bool bit = (val >> (bits - i - 1)) & 0x1;
digitalWrite(SERIAL_DATA, bit); // siirretään taulukko vasemmalta oikealle
digitalWrite(SERIAL_CLK, HIGH);
//delay(SERIAL_DELAY);
digitalWrite(SERIAL_CLK, LOW);
//delay(SERIAL_DELAY);
even_parity = (even_parity ^ bit) & 0x01;
}
digitalWrite(SERIAL_ENABLE, LOW);
digitalWrite(SERIAL_CLK, LOW);
return even_parity;
}
// uint8_t send_serial_out(uint8_t table[], size_t tablesize) {
void loop() {
int c = 0;
if (Serial.available()) {
c = Serial.read();
if (c == IntelHEXStartCode) {
uint8_t byteCount = readHex8();
uint16_t address = readHex16BE();
uint8_t recordType = readHex8();
if (recordType == 00) {
Serial.print("byteCount = ");
Serial.print(byteCount);
Serial.print(" address = ");
Serial.print(address);
Serial.print(" recordType = ");
Serial.print(recordType);
// Data
for (size_t i = 0; i < byteCount; ++i) {
buffer[i] = readHex8();
}
// Tässä näin..
for (size_t i = 0; i < byteCount; ++i) {
send_serial_out((uint32_t(address + i) << 8) | buffer[i], 15+8);
}
Serial.print(" <> ");
bytesReceived += byteCount;
} else if (recordType == 01) {
// End Of File
Serial.println("<EOF>");
for (size_t i = 0; i < byteCount; ++i) readHex8();
dirty = true;
} else {
//Serial.print("Unknown record");
for (size_t i = 0; i < byteCount; ++i) readHex8();
}
uint8_t checksum = readHex8();
/*
Serial.print(" checksum = ");
Serial.print(int(checksum));
Serial.println();
*/
} else {
// Skip
//Serial.print("unknown char = ");
//Serial.print(int(c));
//Serial.println();
}
}
if (dirty && (millis() - lastPrintTime) > 5000) {
Serial.print("OK ");
Serial.print(bytesReceived);
Serial.print(" bytes received");
Serial.println();
lastPrintTime = millis();
dirty = false;
}
}