Nios® V/II Embedded Design Suite (EDS)
Support for Embedded Development Tools, Processors (SoCs and Nios® V/II processor), Embedded Development Suites (EDSs), Boot and Configuration, Operating Systems, C and C++
12589 Discussions

boot NIOS and FPGA from EPCS flash

Altera_Forum
Honored Contributor II
3,494 Views

Hi all, 

 

I am having problems booting up my Nios C code from EPCS. I am building my own FPGA board, not using a demo board. I'm using Quartus 15.0 and DE0 NanoBoard( Cyclone IV as FPGA) 

My application contains: 

 

1. Clock Source 

2. Nios II Processor 

3. System ID 

4. JTAG UART 

5. EPCS Serial Flash Controller 

6. PIO 

7. SDRAM Controller 

 

I want to use SDRAM to store instructions and data for NIOS application. In the NIOS II Processor properties reset vector is set to base address of EPCS controller. Exceptions vector is set to base address to SDRAM. In the NIOS EDS for Eclipce I can debug my application, it works. Then, want to store the FPGA configuration data and the nios firmware in the EPCS following the steps below : 

 

1) I generate the file.hex in NIOS terminal  

 

2) Using Convert Programming Files in Quartus, I create a JIC file using the steps below:  

 

2-a) Select EPCS64 (that is the flash chip i'm using) 

2-b) Add SOF Page -> Page 0 -> Properties -> Address mode for selected pages: Set to START and Start Address = 0x0 

2-c) Add file to SOF page: Add file.sof 

2-d) Properties of file.sof select Compression 

2-e) Add HEX data 

2-f) Add File -> file.hex 

2-g) Use absolute addressing offset( the offset was given in reset vector )  

 

3) Generate JIC file -> NO issues. 

 

4) Program EPCS device using Active Serial Programming. Add my JIC file. Programming succesful. 

 

5) Power cycle my board. The hardware file starts, but the NIOS never boots?  

 

So what is going wrong? I am programming using the USB Blaster. I am also not going through JTAG.  

 

Any ideas? 

 

Thanks in advance  

 

Best regards  

0 Kudos
23 Replies
Altera_Forum
Honored Contributor II
1,278 Views

When you generate the jic file you should have an output.jic and an output.map file created. Check the output.map file it will tell you the EPCS addresses of the sof and hex files. Make sure the hex file starts right after the sof file. So if the address range of the sof is 0x000 - 0xAAA, the the hex file should start with 0xAAB.

0 Kudos
Altera_Forum
Honored Contributor II
1,278 Views

The EPCS is not directly addressable. You need to get a small boot loader program and load that into an embedded memory and set the embedded memory as the reset vector. Check out the wiki article http://www.alterawiki.com/wiki/epcs_bootloaders

0 Kudos
Altera_Forum
Honored Contributor II
1,278 Views

As krasner suggested, you probably have the addresses wrong. See this article: https://www.altera.com/support/support-resources/knowledge-base/solutions/rd10132010_126.html 

Using elf2flash and the 'after' argument is how you get them concatenated in the EPCS (there's other ways to do it, this article is just one way).
0 Kudos
Altera_Forum
Honored Contributor II
1,278 Views

Thank for you all. It working now, i had to change to offset in RESET VECTOR. 

 

Best regards,
0 Kudos
Altera_Forum
Honored Contributor II
1,278 Views

Hi again,  

 

I'm actually trying to READ/Write the Flash EPCS64 device from NIOS II , unfortunately i doesn't work correctly. 

 

First of all i open my device using this code : 

 

int epcs_open(void) { int ret_code; int i; fd = alt_flash_open_dev("/dev/epcq_controller_avl_mem"); if (fd== NULL) { printf("** Can't open flash device **\n\n"); }else { printf("\n<----> Running Flash Tests <---->\n\r"); printf("-Testing flash info retrieval..."); ret_code = alt_get_flash_info(fd, &regions, &number_of_regions); //ret_code =alt_epcq_controller_get_info(fd, &regions, &number_of_regions); if (ret_code) { printf( "\nERROR: function alt_get_flash_info failed. ret_code %d\n",ret_code); goto finished; } printf("\n\rThis is NIOSII Board Designed by flash Logic\n\r"); printf("Flash name %s\n\r",fd->name); printf("This flash has %d erase regions\n\r", number_of_regions); for (i=0;i<number_of_regions;i++) { printf("Start 0x%08x End 0x%08x Number of Blocks %3d Block Size 0x%08x\n\r",(regions+i)->offset, (regions+i)->region_size+(regions+i)->offset, (regions+i)->number_of_blocks, (regions+i)->block_size); } } printf("passed.\n\r"); printf("Exiting Flash Tests\n\r"); finished: alt_flash_close_dev(fd); return ret_code; } 

it's ok. 

 

Then i Write/read the device using the code below: 

 

int test_programming( alt_flash_fd* fd, int test_offset) { int i; alt_u8 data_written; alt_u8 data_read; int ret_code = 0; int test_length = sizeof(data_written); for(i=0;i<sizeof(data_written);i++){ data_written = i; printf( "data_written= 0x%08x\n\r",i,data_written); } ret_code = alt_write_flash(fd, test_offset, data_written, test_length); if (!ret_code) { ret_code = alt_read_flash(fd, test_offset, data_read, test_length); if(!ret_code) { for(i=0;i<sizeof(data_read);i++) printf( "Flash+%d= 0x%08x\n\r",i,data_read); } } printf("*"); if (ret_code) { printf( "\nERROR: function alt_write_flash failed. ret_code %d\n", ret_code); return ret_code; } return ret_code; } 

 

The problem is that the written/read data is not the same as shown the picture joined. 

 

Do you have any idea why ? 

 

Best regards.
0 Kudos
Altera_Forum
Honored Contributor II
1,278 Views

Hi all, 

 

I still have the problem with the EPCS64 flash, the write operation can be done( because when i write in sectors where the FPGA configuration is saved, I can't boot from the EPCS64). 

I noticed that the problem comes from the read function because i get always 0xFF from the flash. 

Do you have an idea about this issue ? I really need your help, because i spent a lot of time without success. 

 

Thank you in advance. 

Best regards.
0 Kudos
Altera_Forum
Honored Contributor II
1,278 Views

Maybe tryprintf( "Flash+%d= 0x%08x\n\r",i,data_read);

0 Kudos
Altera_Forum
Honored Contributor II
1,278 Views

Thank you Daixiwen for your answer. 

After some modification in the code given above.Now, i can write and read to/from my flash device. 

But the problem i'm facing is that my data written to the flash are shifted, i can see that in the debug mode using the Memory. 

For example when i Write in the address 0x04FC0000, the data 0x3fa00000, Instead i see 0xF1050000. It seems to be shifted. 

The routine that writes is : 

/* write to flash 32 bits at a time */ 

IOWR_32DIRECT(epcq_flash_info->data_base, write_offset, word_to_write); 

word_to_write = 0x3fa00000. 

It's very strange. Do you have an idea what would be the problem? 

Thank you in advance. 

Best regards
0 Kudos
Altera_Forum
Honored Contributor II
1,278 Views

You are using a serial flash so it can't be accessed with IOWR/IORD macros. You need to use the alt_write_flash / alt_read_flash functions.

0 Kudos
Altera_Forum
Honored Contributor II
1,278 Views

Unfortunately, even with using theses functions, i have the same behavior.

0 Kudos
Altera_Forum
Honored Contributor II
1,278 Views

Could you post the exact code you are using for your test? Including all inputs and outputs? 

Try to read the flash location before you write it too. A flash chip can only switch 1 bits to 0's and not the other way round so in some cases it can explain why you don't see the same values. Try to only write to an area that reads as ff's.
0 Kudos
Altera_Forum
Honored Contributor II
1,278 Views

These are my different functions used for the serial flash : 

 

1) Open the device  

 

int epcs_open(void) { int ret_code; int i; fd = alt_flash_open_dev("/dev/epcq_controller_avl_mem"); if (fd== NULL) { printf("** Can't open flash device **\n\n"); }else { printf("\n<----> Running Flash Tests <---->\n\r"); printf("-Testing flash info retrieval..."); ret_code = alt_get_flash_info(fd, &regions, &number_of_regions); //ret_code =alt_epcq_controller_get_info(fd, &regions, &number_of_regions); if (ret_code) { printf( "\nERROR: function alt_get_flash_info failed. ret_code %d\n",ret_code); goto finished; } printf("\n\rThis is NIOSII Board Designed by flash Logic\n\r"); printf("Flash name %s\n\r",fd->name); printf("This flash has %d erase regions\n\r", number_of_regions); for (i=0;i<number_of_regions;i++) { printf("Start 0x%08x End 0x%08x Number of Blocks %3d Block Size 0x%08x\n\r",(regions+i)->offset, (regions+i)->region_size+(regions+i)->offset, (regions+i)->number_of_blocks, (regions+i)->block_size); } } printf("passed.\n\r"); printf("Exiting Flash Tests\n\r"); finished: alt_flash_close_dev(fd); return ret_code; } 

 

2) Write into device  

 

int Write_flash( alt_flash_fd* fd, alt_u8 *Ks_par,int test_offset) { int i; int ret_code = 0; int test_length =16; // before writing in a sector, we should erase it before ret_code=alt_erase_flash_block(fd, test_offset,test_length); if(!ret_code){ for(i=0;i<test_length;i++){ printf( "data_written= 0x%08x\n\r",i,Ks_par); } ret_code=alt_write_flash_block(fd,test_offset,test_offset,Ks_par,test_length); } if (ret_code) { printf( "\nERROR: function alt_write_flash failed. ret_code %d\n",ret_code); return ret_code; } return ret_code; } 

 

3) Reading from the device  

 

float Read_flash( alt_flash_fd* fd,int test_offset) { int test_length = 4; alt_u8 data_read; int i=0; union conv2float read_flash; float Ks_para=0.0; int ret_code = 0; if (!ret_code) { ret_code=alt_read_flash(fd, test_offset, data_read, test_length); if(!ret_code) { for(i=0;i<test_length;i++){ read_flash.V_In=data_read; printf( "Flash+%d= 0x%08x\n\r",i,read_flash.V_In); } Ks_para=(float)read_flash.V_Fl; } } return Ks_para; } 

 

Best regards,
0 Kudos
Altera_Forum
Honored Contributor II
1,278 Views

Having a quick look at your code I don't see anything wrong. Now let's look for less obvious bugs. 

In epcs open, is the information returned by the function correct (number of blocks, block size) ? 

I see in epcs_open() that you close the flash device after being finished with it. Do you reopen it before the call to the next two functions ? If yes are you sure you are reopening it with the same path? 

It seems that "fd" in epcs_open() is a global variable, whereas it is a local variable in Write_flash and Read_flash. If all those functions are in the same file it can create a confusion, where a local variable takes precedence over the global one. I suggest removing the global variable and make fd local in epcs_open() (or make epcs_open return it if you don't want to close it). 

Could you show the result of your printf's? Do you get the same wrong values each time, or are they different ? 

What value are you using for the test_offset? Are you sure it is not out of bounds, given the size of the flash you are using? 

Try putting some printf's at the beginning of Write_flash and Read_flash to check that both functions are using the same values for fd and test_offset. 

 

Hope this helps...
0 Kudos
Altera_Forum
Honored Contributor II
1,278 Views

Oh and I forgot... The %x in printf is expecting an int (4 bytes) argument, but you are giving it a byte. It's not a problem if it's the last argument in the printf call, but if you decide to add more debugging information later it will probably get confusing. I suggest casting your arguments to (int) in the printf call.

0 Kudos
Altera_Forum
Honored Contributor II
1,278 Views

Hi Daixiwen, 

 

Thank you for taking time to resolve my problem, I appreciate it. 

 

1) Yes, i can get the correct information about the device as shown below : 

This flash has 1 erase regions  

start 0x00000000 End 0x00800000 Number of Blocks 128 Block Size 0x00010000 

 

2) The device is closed only when is fails to open. So i don't need to reopen it when i want to write or read. 

 

3) I removed the global to local variables as you suggested and always the samehttps://www.alteraforum.com/forum/attachment.php?attachmentid=11017 thing. 

 

4) I put printf of the fd and test_offset before Write_flash and Read_flash and are the same for both function. The offset is tested and it is not out of bounds. 

 

5) I get the same wrong values each time, you find enclosed a picture about these values. 

 

 

Best regards
0 Kudos
Altera_Forum
Honored Contributor II
1,278 Views

May be it's a configuration problem. 

With my EPCS device i can boot both the FPGA configuration and Nios II software.  

I'm using the Quartus 15.0, When i add the EPCS controller, the DATA, DCLK, ASDI, and nCS signals are not exported to Nios entity.To add the EPCS controller i have two choice, altera serial flash controller or legacy epcs/epcqx1 flash controller, i took the first one, it's right ?. In device and pin options, I configured DCLK & nCEO as as as compiler, ASDI & cCS as compiler configured, if not I can't boot from the Flash.  

Hope that help to understand my problem. 

Best regards
0 Kudos
Altera_Forum
Honored Contributor II
1,278 Views

 

--- Quote Start ---  

2) The device is closed only when is fails to open. So i don't need to reopen it when i want to write or read. 

--- Quote End ---  

 

It's not the case in the example code you presented here: 

printf("passed.\n\r"); printf("Exiting Flash Tests\n\r"); finished: alt_flash_close_dev(fd); return ret_code; }You write "Exiting Flash Tests" but you still execute alt_flash_close_dev() before returning, even if the test succeeded. 

 

 

--- Quote Start ---  

May be it's a configuration problem. 

With my EPCS device i can boot both the FPGA configuration and Nios II software.  

I'm using the Quartus 15.0, When i add the EPCS controller, the DATA, DCLK, ASDI, and nCS signals are not exported to Nios entity.To add the EPCS controller i have two choice, altera serial flash controller or legacy epcs/epcqx1 flash controller, i took the first one, it's right ?. In device and pin options, I configured DCLK & nCEO as as as compiler, ASDI & cCS as compiler configured, if not I can't boot from the Flash.  

Hope that help to understand my problem. 

Best regards 

--- Quote End ---  

 

 

No, I think your configuration is correct. The fact that your init function displays the correct flash size shows that the driver managed to ask the flash it's ID and got a valid answer. So I think the flash is connected correctly and you are using the correct controller. 

 

Your image is difficult to see (the forum has the nasty habit of resizing down all images, it's in fact better to past text directly instead of attaching an image) but I don't see any obvious pattern such as a problem with the erasing part. I'm sorry I don't have any more ideas to help you right now, except looking directly at the serial lines (either with a scope or with signaltap) to see which commands the controller is sending to the flash. Another and maybe easier alternative would be to edit the flash driver to print out on the terminal all the commands sent to the SPI master.
0 Kudos
Altera_Forum
Honored Contributor II
1,278 Views

Ok Daixiwen, thank you. 

 

You said in one post that serial flash can't be accessed with IOWR/IORD macros 

/* write to flash 32 bits at a time */ 

IOWR_32DIRECT(epcq_flash_info->data_base, write_offset, word_to_write); 

But, even if I use the alt_write_flash / alt_read_flash functions, the alt_epcq_controller_write_block/ alt_epcq_controller_read functions are called by the first one. And so IOWR/IORD macros. 

It's normal ?  

Also I would like to explain you a situation that debug mode gives me. The written data is 0x3fe3d70a. 

3f e3 d7 0a - written data 

0a d7 e3 3f - endian swapped 

9f f1 6b 05 - it's like right shifted (when write in the memory) 0x9ff16b05>1 = 3FE2D60A 

 

0x04800000 : 0x4800000 <Hex> 

Address 0 - 3 4 - 7 8 - B C - F  

04FB0000 056BF19F FFFFFFFF FFFFFFFF FFFFFFFF  

04FB0010 FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  

04FB0020 FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  

 

the data is being endian swapped first then shifted right between the time it is written and when its read, which means somewhere there are an incorrect number of serial shifts to load all the data being written or read back.  

How can I looking at the serial lines with signaltap ? I didn't find them in my entity. 

Best regards
0 Kudos
Altera_Forum
Honored Contributor II
1,278 Views

 

--- Quote Start ---  

Ok Daixiwen, thank you. 

 

You said in one post that serial flash can't be accessed with IOWR/IORD macros 

/* write to flash 32 bits at a time */ 

IOWR_32DIRECT(epcq_flash_info->data_base, write_offset, word_to_write); 

But, even if I use the alt_write_flash / alt_read_flash functions, the alt_epcq_controller_write_block/ alt_epcq_controller_read functions are called by the first one. And so IOWR/IORD macros. 

It's normal ? 

--- Quote End ---  

 

The IORD/IOWR macros are used for direct memory mapped access. If you had a parallel flash that was connected with the usual address/data busses, you could directly access its contents with those macros and the parameters (base, offset, word) as you suggest, and it would work. But the EPCS flash is a serial chip, accessed through SPI. You need to send it an SPI command with the offset you want to read/write first, and then you can access the data with more SPI transactions. The alt_read_flash and alt_write_flash functions use a bunch of IORD/IOWR macros, but they are to talk to the SPI master, not directly to the flash. 

 

 

--- Quote Start ---  

 

Also I would like to explain you a situation that debug mode gives me. The written data is 0x3fe3d70a. 

3f e3 d7 0a - written data 

0a d7 e3 3f - endian swapped 

9f f1 6b 05 - it's like right shifted (when write in the memory) 0x9ff16b05>1 = 3FE2D60A 

 

0x04800000 : 0x4800000 <Hex> 

Address 0 - 3 4 - 7 8 - B C - F  

04FB0000 056BF19F FFFFFFFF FFFFFFFF FFFFFFFF  

04FB0010 FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  

04FB0020 FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  

 

the data is being endian swapped first then shifted right between the time it is written and when its read, which means somewhere there are an incorrect number of serial shifts to load all the data being written or read back.  

How can I looking at the serial lines with signaltap ? I didn't find them in my entity. 

Best regards 

--- Quote End ---  

 

 

The pins are hidden because Quartus directly connects them, but now that you mention it I don't know if/how you can access them within Signaltap. Maybe have a look inside the EPCS controller? There should be a SPI master with the chip select, clock and data signals somewhere. 

The fact that the data seems to be shifted is interesting.... Is it a custom board or a development kit? It could be a good idea to use a scope instead of Signaltap and check the quality of the signals to the EPCS. Pay special attention to the clock signal, if you have some ringing the EPCS could hop over some data bits when it is accessed.
0 Kudos
Altera_Forum
Honored Contributor II
1,135 Views

1)It's a development board(DE0-Nano Development and Education Board). 

2) In altera_epcq_controller_core.vhd i can see signals below that correspond to the serial ones. 

 

epcq_dclk : out std_logic; -- conduit_epcq_dclk 

epcq_scein : out std_logic_vector(0 downto 0); -- conduit_epcq_scein 

epcq_sdoin : out std_logic_vector(0 downto 0);  

epcq_dataout : in std_logic_vector(0 downto 0) := (others => '0'); -- epcq_dataout.conduit_epcq_dataout 

 

I still have a doubt how i can configure Dual purpose pins of DCLK,nCEO and ... If there are configured as regular I/O, i can't boot both hardware and software. 

I had to configure dclk and nceo as programming pin and DATA[0] and nCSO as compiler configured. I didn't find any datasheet about how to do that. 

I seems to be different with the other version of Quartus, because the serial signals were exported not the case with Quartus 15.0.
0 Kudos
Reply