Author Topic: ICE40 dev board programming from NanoPI Neo effort  (Read 1498 times)

0 Members and 1 Guest are viewing this topic.

Offline CM800Topic starter

  • Frequent Contributor
  • **
  • Posts: 882
  • Country: 00
ICE40 dev board programming from NanoPI Neo effort
« on: October 08, 2017, 07:02:10 pm »
So,

Following on from the $8 ICE40 dev board thread, I'm currently working on making a program to easily upload the program from a NanoPI Neo.

I'm using the SPI bus built in, rather then bit-banging it like other programmers. I figured this would be a good learning exercise, but I feel slightly out of depth.

Currently I've put together this code:

Code: [Select]
#include <unistd.h>
#include <wiringPi.h>
#include <wiringPiSPI.h>


int main ( int argc, char *argv[] )
{
    if ( argc != 2 ) /* argc should be 2 for correct execution */
    {
        /* We print argv[0] assuming it is the program name */
        printf( "usage: %s filename", argv[0] );
    }
    else
    {



        // We assume argv[1] is a filename to open
        FILE *hexFile = fopen( argv[1], "r" );

        /* fopen returns 0, the NULL pointer, on failure */
        if ( hexFile == 0 )
        {
            printf( "Could not open file\n" );
        }
        else  /* Hex File Open */
        {
int spi = wiringPiSPISetup(0, 1000000); // Setup SPI channel 0, 1MHz

fseek (hexFile, 0, SEEK_END);

int file_size = ftell(hexFile);

rewind(hexFile);

char* buffer = (char*) malloc (sizeof(char)*file_size);

fread(buffer, 1, file_size, hexFile);

for(int i = 0; i < file_size; i++)
{
write(spi, &buffer[i], sizeof(char));
}

        }
    }
}

This simply spits out data onto the SPI Bus.

I was planning to send it as a lump, but the file is just too big to do "sizeof(buffer)" (or whatnot)

I would like a little suggestion / input into the code that I've got now, along with suggestions on what direction to go in terms of implementing actually programming it, now I have a method of getting the data out.

From what I know, in terms of programming, the order of operation is as so:

- FPGA reset pin pulled HIGH

- wait for a period of time (2 seconds?)

- send .bin file

- send 2 empty bytes at the end (or more apparently?)

- once CDONE is high, programming is complete.


Apparently they bitbang because the Slave select pin can't be controlled independently? Is that a major issue?
 

Offline agehall

  • Frequent Contributor
  • **
  • Posts: 383
  • Country: se
Re: ICE40 dev board programming from NanoPI Neo effort
« Reply #1 on: October 08, 2017, 08:34:12 pm »
The code you put together might work, but there are a few problems that you should try to fix to improve the reliability of the code.

First of all, I absolutely hate the use of standard types like "int" and "long". While the standard does specify how these should be dealt with, they feel ambiguous to me. I prefer to use uintX_t (where X is the number of bits you want) for unsigned numbers and size_t for anything related to file sizes or buffer sizes. This gives the reader of your code a much more clear picture of what is going on and you may also avoid some nasty surprises where one architecture defines int as something other than what you expect... This may be a matter of style preference, but having had to write code that needs to compile for multiple architectures, this is something deeply rooted in the back of my mind.

One place where this actually becomes relevant, is where you read the file size using ftell(), which, at least on my system, returns a long, which is not neccessarily the same thing as an int... While an int may be a long, nothing guarantees you won't overflow there.

I would also think long and hard about doing malloc(sizeof(char) * file_size) - can sizeof(char)*file_size overflow the parameter size for your malloc()? Since sizeof(char) is 1 on every architecture I can think of, you probably won't be bitten by an overflow due to multiplication in this case, but it generally considered bad form to do a multiplication in the malloc() parameter list. Use calloc() instead if you are allocating space for structures larger than 1 byte.

As for outputing the data - don't write a byte at the time! Sure, it works, but it is super inefficient. For this code it might not be an issue, but if you want to use this as a chance learn, write a loop that outputs 1024 bytes (or something else that makes sense) at the time. You just need to make sure you handle the case when you are outputting the last few bytes from the buffer and there isn't 1024 bytes left...

If you want to do it like the cool kids would, have a look att mmap() and use that instead of reading the whole input file into memory. :)

All in all, not too bad of a job though. You seem to have gotten the most important bits right - checking for errors and dealing with them.
 

Offline CM800Topic starter

  • Frequent Contributor
  • **
  • Posts: 882
  • Country: 00
Re: ICE40 dev board programming from NanoPI Neo effort
« Reply #2 on: October 09, 2017, 07:09:07 am »
Thank you for your response Agehall,
I've done a bit of work on it. I have left the ints as they were, but will do the quick changeover later once everything is working.

Code: [Select]
#include <unistd.h>
#include <wiringPi.h>
#include <wiringPiSPI.h>
#include <sys/resource.h>


int main ( int argc, char *argv[] )
{

    if ( argc != 2 ) /* argc should be 2 for correct execution */
    {
        /* We print argv[0] assuming it is the program name */
        printf( "usage: %s filename", argv[0] );
    }
    else
    {
        FILE *hexFile = fopen( argv[1], "rb" );

if (!hexFile)
{
printf("Failed to open file.\n");
exit(-1);
}

int spi = wiringPiSPISetup(0, 1000000); // Setup SPI channel 0, 1MHz

fseek (hexFile, 0, SEEK_END);

size_t file_size = ftell(hexFile);

rewind(hexFile);

char * buffer = calloc(file_size, sizeof(char));
if (!buffer)
{
printf("Failed to allocate file buffer.\n");
exit(-1);
}

fread(buffer, file_size, file_size, hexFile);
fclose(hexFile);

/*
for (int index = 0; index < file_size; index += 9)
{
int size = file_size - index;

if(size > 9)
{
write(spi, &buffer[index], 10);
}
else
{
write(spi, &buffer[index], size);
}


}*/

char dat[5] = {0x01, 0x02, 0x03, 0x04, 0x05};

write(spi, dat , 5);
    }
}

I've got a bit of a problem right now, where this works:
Code: [Select]
char dat[5] = {0x01, 0x02, 0x03, 0x04, 0x05};

write(spi, dat , 5);

but not this....
Code: [Select]
for (int index = 0; index < file_size; index += 9)
{
int size = file_size - index;

if(size > 9)
{
write(spi, &buffer[index], 10);
}
else
{
write(spi, &buffer[index], size);
}


}

The latter one which is not working seems to be looping around just fine, and sending the correct final amount... however the SPI is just clocking and not outputting data, as if the entire thing is only zeros.
Now I know there are a lot of zeros in my bin file, from the ICE40 software, however I get nothing even if I set my logic analyser to trigger on the data line.....
 

Offline CM800Topic starter

  • Frequent Contributor
  • **
  • Posts: 882
  • Country: 00
Re: ICE40 dev board programming from NanoPI Neo effort
« Reply #3 on: October 11, 2017, 08:11:20 am »
*Applies a bump to*
 

Offline agehall

  • Frequent Contributor
  • **
  • Posts: 383
  • Country: se
Re: ICE40 dev board programming from NanoPI Neo effort
« Reply #4 on: October 11, 2017, 07:08:19 pm »
I think you got the arguments to fread() wrong so it probably fails and just leaves the memory as all 0's. I think you might have an off-by-one problem in your write loop as well, but I don't have time to double check right now.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf