This is Altera's recommendation:
That's a lot of IO and something I wasn't particularly interested in connecting to the Wishbone Bus of the system I was working on. I did have a few things working for me that would simplify this problem.
1. The EPCS devices used by Altera to program their FPGA are just re-branded SPI EEPROMS. Some manufacturers will work some will not. A little researching allowed a substitution.
EPCS16SI8N (Digikey PN 544-2567-5-ND) is $17.10 while a Cyprus Semi 16Mbit SPI EEPROM (Digikey PN 1274-1124-1-ND) is $0.66.
2. The EPCS (or SPI EEPROM) is connected to four dual-purpose pins to the FPGA.
DATA1, ASDO/IO: SPI DO
FLASH_nCE, nCSO/IO: SPI CS
DCLK/DCLK: SPI CLK
DATA0/IO: SPI DI
These two pieces of information tell me that I can use pre-built Wishbone Bus to SPI bus Core and that I can use the same programming pins as Regular IO.
To change ASDO, nCSO, DCLK and DATA0 into regular IO (after FPGA programmed), edit Dual-purpose pins in the Device properties.
In addition, DCLK pin had errors during Quartus compiling that the pin could not be used as a clock. After hours of online searching, I found that there was an additional compiling directive that I had to added.
Error (169181): Cannot place I/O pin SPI_P2_MOSI_O with I/O standard 3.3-V LVCMOS in pin location 13 -- possible switch coupling with I/O pin SPI_P2_CLK_O in pin location 12.
In Assignment Editor, select Category "I/O Features" from the drop-down list. Add an entry To the SPI Clock signal that is assigned to the EPCS part and set "I/O Maximum Toggle Rate" to "0". See SPI_P2_CLK_O below.
The final setup to generate a programmable file is that the bits in the byte need to be reversed. This was probably the most confusing, but I was able to discern from a few mentions in forum posts and from checking the EEPROM contents between identical files that were programmed with Quartus and my own EEPROM writing.
This is the sequence:
Compile->SOF->POF->RPD->Reverse->EEPROM Write.
This is what I do:
- Quartus compiles bit image and creates SOF and POF.
- I verify that SOF file works by programming the FPGA via JTAG.
- Convert POF file to RPD file with "Convert Programming File"
- Run "rpd_reverse.exe" (see the end of the article for code) which will make a BIN file
- Use Xmodem to upload BIN File to FPGA running a small processor+memory+serial port.
- Another program on FPGA processor loads the uploaded BIN File to SPI EEPROM
- Bonus: use RSU from the previous article to boot new FPGA Bit Image.
Please direct questions to
page.#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PAGESIZE 0x80000
static unsigned char reverse(unsigned char b);
//reverse bits in a byte
unsigned char reverse(unsigned char b) {
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return b;
}
int main(int argc, char *argv[])
{
FILE * pFile;
char filename[80] = "a.out";
long lSize = PAGESIZE;
int m = 0;
int adr_start;
unsigned char * buffer;
size_t result;
FILE *f; // txt output file
FILE *d; // binary output file
if (argc > 1)
{
while(argv[1][m] != '\0')
{
filename[m] = argv[1][m];
m++;
}
}
pFile = fopen (filename , "rb" );
if (pFile==NULL)
{
printf("Cannot open file 'a.out'\n");
exit (1);
}
// obtain file size:
// allocate memory to contain the whole file:
buffer = (unsigned char*) malloc (sizeof(unsigned char)*lSize);
if (buffer == NULL)
{
printf("Memory error\n");
exit (2);
}
// copy the file into the buffer:
result = fread (buffer,1,lSize,pFile);
if (result != lSize)
{
printf("Reading error\n");
exit (3);
}
// Open dat output file
d = fopen("fpga_reverse.bin","wb+");
if(d == NULL)
{
printf("Error creating binary output file\n");
exit(11);
}
unsigned long mnemonic_beginning = 0;
unsigned long mnemonic_length = lSize;
if(mnemonic_length == 0)
{
printf("Invalid assembler file\n"); //x38 x58
exit(4);
}
if (mnemonic_length == 0)
{
printf("Assembler file is empty\n");
exit(5);
}
printf("Program start: 0x%.8X\n", mnemonic_beginning);
printf("Program size: 0x%.8X\n", mnemonic_length-4);
int j = mnemonic_beginning;
int i = 0;
int k = 0;
char txt_string[32];
char dat_string;
i = 0;
while (j != (mnemonic_length + mnemonic_beginning))
{
dat_string = (signed char) buffer[j];
fputc(reverse(dat_string), d);
j++;
}
fclose(pFile);
fclose(d);
free (buffer);
return 0;
}