Using GPIO with C ( permission problems )

2»

Comments

  • KurtKurt New Member Posts: 146 ✭✭
    Yes - as you mentioned the ILI9341 displays should be able to handle 25mhz and I have not had any issues at higher speeds of up to 30 mhz on a Teensy. However there are others who had issues... Maybe clones.

    I should mention that the higher speeds work for output. You need to go a a slower buss speed if you do reads from the display.

    However the other things I have found with the buss speeds on several of these processors, that increasing the speed does not necessarily speed things up much...

    That is for example I checked the total time it took to output a full page at 8mhz and it took about .20 seconds, when I told the system to run at 25mhz, it took about .18 seconds. Looking at the logic analyzer for the most part the difference was at 8mbs the output of each group of 256 bytes took up larger portion of the buss time (less gap) and at 25 mbs each group took a smaller portion of the buss and then a larger gap between groups... (Currently this test was done with default 4K SPIDEV buffer size.
  • WereCatfWereCatf New Member Posts: 201
    edited August 2017
    If you can't see much of any difference between 8MHz and 25MHz there's something wrong. Try e.g. this quick-and-dirty SPI-benchmark-like thingy I just wrote, just change the SPI_BUS and SPI_BUS_CS to whichever one you wish to use:
    #include<sys/stat.h>
    #include<fcntl.h>
    #include<mraa.h>
    #include<unistd.h>
    #include<stdint.h>
    #include<stdio.h>
    #include<string.h>
    #include<time.h>
    
    #define SPI_BUS 0
    #define SPI_BUS_CS 1
    #define DATA_SIZE 20*1024*1024 //20MB
    #define TEST1_FREQ_MHZ 8
    #define TEST2_FREQ_MHZ 25
    
    #define KNRM  "\x1B[0m"
    #define KRED  "\x1B[31m"
    #define KGRN  "\x1B[32m"
    #define KYEL  "\x1B[33m"
    #define KBLU  "\x1B[34m"
    #define KMAG  "\x1B[35m"
    #define KCYN  "\x1B[36m"
    #define KWHT  "\x1B[37m"
    
    void setMaxPrio(void){
    	struct sched_param sched;
    	memset(&sched, 0, sizeof(sched));
    	//Use FIFO scheduler with highest priority for the lowest chance of the kernel context switching.
    	sched.sched_priority = sched_get_priority_max(SCHED_FIFO);
    	sched_setscheduler(0, SCHED_FIFO, &sched);
    }
    
    void setDefaultPrio(void){
    	struct sched_param sched;
    	memset(&sched, 0, sizeof(sched));
    	//Go back to default scheduler with default 0 priority.
    	sched.sched_priority = 0;
    	sched_setscheduler(0, SCHED_OTHER, &sched);
    }
    
    int main(int argc, char** argv)
    {
    	int bufsiz=0;
    	mraa_spi_context spiBus;
    	uint8_t *dataBuffer=NULL;
    	struct timespec timeStart, timeEnd;
    	double accum;
    
    	FILE *fileSpidevBufsiz=fopen("/sys/module/spidev/parameters/bufsiz", "r");
    	if(fileSpidevBufsiz==NULL){
    		printf("%sError opening /sys/module/spidev/parameters/bufsiz!%s\n", KRED, KNRM);
    		exit(1);
    	}
    	fscanf(fileSpidevBufsiz,"%d", &bufsiz);
    	printf("\nBufsiz set to: %s%d%s\n", KCYN, bufsiz, KNRM);
    	fclose(fileSpidevBufsiz);
    
    	mraa_init();
    	spiBus=mraa_spi_init_raw(SPI_BUS, SPI_BUS_CS);
    	if(spiBus == NULL){
    		printf("%sError initializing SPI-bus.%s\n", KRED, KNRM);
    		exit(1);
    	}
    	if((dataBuffer = malloc(DATA_SIZE)) == NULL){
    		printf("%sCouldn't allocate %d bytes of RAM!%s\n", KRED, DATA_SIZE, KNRM);
    		mraa_spi_stop(spiBus);
    		exit(1);
    	}
    	printf("Allocated %s%d%s bytes RAM for the buffer.\n\n", KCYN, DATA_SIZE, KNRM);
    	//Come up with fancier data, if you wish
    	memset(dataBuffer, 0xAA, DATA_SIZE); //B10101010
    	if(mraa_spi_frequency(spiBus, TEST1_FREQ_MHZ * 1000000)!=MRAA_SUCCESS){
    		printf("%sError setting SPI-bus frequency to %dMHz!%s\n", KRED, TEST1_FREQ_MHZ, KNRM);
    		mraa_spi_stop(spiBus);
    		exit(1);
    	}
    	printf("SPI-bus %s%d%s, CS %s%d%s initialized at %s%dMHz%s.\n",
    		KCYN, SPI_BUS, KNRM,
    		KCYN, SPI_BUS_CS, KNRM,
    		KCYN, TEST1_FREQ_MHZ, KNRM);
    	uint8_t *tempPointer=dataBuffer;
    	//Blast the data out in bufsiz-sized portions
    	if(geteuid()==0) setMaxPrio();
    	clock_gettime(CLOCK_MONOTONIC, &timeStart);
    	for(int i=0; i<(DATA_SIZE / bufsiz); i++){
    		if(mraa_spi_transfer_buf(spiBus, tempPointer, NULL, bufsiz) != MRAA_SUCCESS){
    			printf("%sError writing data to the SPI-bus!%s\n", KRED, KNRM);
    			mraa_spi_stop(spiBus);
    			exit(1);
    		}
    		tempPointer+=bufsiz;
    	}
    	clock_gettime(CLOCK_MONOTONIC, &timeEnd);
    	if(geteuid()==0) setDefaultPrio();
    	accum=( timeEnd.tv_sec - timeStart.tv_sec )
    		+ ( timeEnd.tv_nsec - timeStart.tv_nsec )
    		/ 1E9;
    	printf("Transferring %s%d%s bytes took %s%.02f%s seconds, resulting in:\n",
    		KCYN, DATA_SIZE, KNRM,
    		KCYN, accum, KNRM);
    	printf(" * Bits per second: %s~%.02fbps%s\n", KCYN, DATA_SIZE / accum * 8, KNRM);
    	printf(" * Megabits per second: %s~%.02fMbps%s\n", KCYN, DATA_SIZE / accum * 8 / 1000 / 1000, KNRM);
    	printf(" * Bytes per second: %s~%.02fBps%s\n", KCYN, DATA_SIZE / accum, KNRM);
    	printf(" * Megabytes per second: %s~%.02fMBps%s\n", KCYN, DATA_SIZE / accum / 1024 / 1024, KNRM);
    	printf("\n");
    
    	if(mraa_spi_frequency(spiBus, TEST2_FREQ_MHZ * 1000000)!=MRAA_SUCCESS){
    		printf("%sError setting SPI-bus frequency to %dMHz!%s\n", KRED, TEST2_FREQ_MHZ, KNRM);
    		mraa_spi_stop(spiBus);
    		exit(1);
    	}
    	printf("SPI-bus %s%d%s, CS %s%d%s initialized at %s%dMHz%s.\n",
    		KCYN, SPI_BUS, KNRM,
    		KCYN, SPI_BUS_CS, KNRM,
    		KCYN, TEST2_FREQ_MHZ, KNRM);
    
    	tempPointer=dataBuffer;
    	//Blast the data out in bufsiz-sized portions
    	if(geteuid()==0) setMaxPrio();
    	clock_gettime(CLOCK_MONOTONIC, &timeStart);
    	for(int i=0; i<(DATA_SIZE / bufsiz); i++){
    		if(mraa_spi_transfer_buf(spiBus, tempPointer, NULL, bufsiz) != MRAA_SUCCESS){
    			printf("%sError writing data to the SPI-bus!%s\n", KRED, KNRM);
    			mraa_spi_stop(spiBus);
    			exit(1);
    		}
    		tempPointer+=bufsiz;
    	}
    	clock_gettime(CLOCK_MONOTONIC, &timeEnd);
    	if(geteuid()==0) setDefaultPrio();
    	accum=( timeEnd.tv_sec - timeStart.tv_sec )
    		+ ( timeEnd.tv_nsec - timeStart.tv_nsec )
    		/ 1E9;
    	printf("Transferring %s%d%s bytes took %s%.02f%s seconds, resulting in:\n",
    		KCYN, DATA_SIZE, KNRM,
    		KCYN, accum, KNRM);
    	printf(" * Bits per second: %s~%.02fbps%s\n", KCYN, DATA_SIZE / accum * 8, KNRM);
    	printf(" * Megabits per second: %s~%.02fMbps%s\n", KCYN, DATA_SIZE / accum * 8 / 1000 / 1000, KNRM);
    	printf(" * Bytes per second: %s~%.02fBps%s\n", KCYN, DATA_SIZE / accum, KNRM);
    	printf(" * Megabytes per second: %s~%.02fMBps%s\n", KCYN, DATA_SIZE / accum / 1024 / 1024, KNRM);
    	printf("\n");
    
    	free(dataBuffer);
    	mraa_spi_stop(spiBus);
    	exit(0);
    }
    

    On e.g. my Orange Pi+ 2E it spits out the following results:

    Bufsiz set to: 4096
    Allocated 20971520 bytes RAM for the buffer.

    SPI-bus 0, CS 1 initialized at 8MHz.
    Transferring 20971520 bytes took 20.58 seconds, resulting in:
    * Bits per second: ~8153755.62bps
    * Megabits per second: ~8.15Mbps
    * Bytes per second: ~1019219.45Bps
    * Megabytes per second: ~0.97MBps

    SPI-bus 0, CS 1 initialized at 25MHz.
    Transferring 20971520 bytes took 6.97 seconds, resulting in:
    * Bits per second: ~24056548.22bps
    * Megabits per second: ~24.06Mbps
    * Bytes per second: ~3007068.53Bps
    * Megabytes per second: ~2.87MBps
  • KurtKurt New Member Posts: 146 ✭✭
    edited August 2017
    Thanks,

    On my UP board:
    -------- end --------
    
    [email protected]:~/Raspberry_pi/testSPI$ ./testSPI
    
    Bufsiz set to: 4096
    Allocated 20971520 bytes RAM for the buffer.
    
    SPI-bus 2, CS 0 initialized at 8MHz.
    Transferring 20971520 bytes took 27.01 seconds, resulting in:
     * Bits per second: ~6211915.07bps
     * Megabits per second: ~6.21Mbps
     * Bytes per second: ~776489.38Bps
     * Megabytes per second: ~0.74MBps
    
    SPI-bus 2, CS 0 initialized at 25MHz.
    Transferring 20971520 bytes took 24.11 seconds, resulting in:
     * Bits per second: ~6957537.26bps
     * Megabits per second: ~6.96Mbps
     * Bytes per second: ~869692.16Bps
     * Megabytes per second: ~0.83MBps
    
    Which sort of confirms what I was seeing in other program

    Edit:
    I edited the program to try a couple of other speeds:
    At 4MHZ it took 41.1 seconds and at 16MHZ it took 24.10
  • WereCatfWereCatf New Member Posts: 201
    That's really interesting, I would love to know what the issue is. Something is very clearly slowing the SPI-bus operation down. Is there perhaps a BIOS-setting or something limiting the maximum SPI-bus frequency?

    https://github.com/intel-iot-devkit/mraa/blob/master/docs/up.md claims 25MHz, 12.5MHz, 8.33MHz, 6.25MHz, 5MHz, 4.167MHz, 3.571MHz, 3.125MHz are supported by the hardware and 25MHz should very, very definitely be much faster than what you're getting.
  • WereCatfWereCatf New Member Posts: 201
    Here's a very dirty snippet just to get the maximum SPI-bus frequency, mind testing and telling me what it says?
    #include <fcntl.h>
    #include <sys/ioctl.h>
    #include <linux/types.h>
    #include <linux/spi/spidev.h>
    #include <stdint.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    #define SPIDEV "/dev/spidev0.1"
    
    int main(int argc, char *argv[])
    {
            int fd;
            uint32_t speed = 1000000;
    
            fd = open(SPIDEV, O_RDWR);
            if(fd < 0){
                    fprintf(stderr, "Couldn't open SPIDEV %s!\n", SPIDEV);
                    exit(1);
            }
            ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
            printf("SPI-bus maximum frequency: %.02fMHz\n", (double)speed/1000/1000);
            close(fd);
            exit(0);
    }
    
  • KurtKurt New Member Posts: 146 ✭✭
    edited August 2017
    It says: 25mhz
    SPI-bus maximum frequency: 25.00MHz
    

    Again the interesting thing is that you can set the higher MHz (like you could on Edison), but it is something like: some underlying thing is running on a logical timeslice. That is it won't start up the next output of 256 bytes until a minimum of time X has elapsed... So again at lower MHz SPI uses up a higher percentage of X...

    Not sure if maybe it is running some process whose priority could be boosted?
    Looking at htop, the main test app, took almost no time in cpu usage and I did not see anything else jump up...

    Edit: I am guessing that the time is how long it is taking for the code/data to transition between User and kernel mode? That is looking at spidev souces, earlier I thought the buffer size was the size that was moved from user space to kernel space in one chunk... Actually now my guess is that is probably 256 bytes. Which is probably set by the source line that has: _IOC_SIZE(cmd)

    So increasing buffer size does nothing for us, it simply does internal iterations for us...
  • WereCatfWereCatf New Member Posts: 201
    Well, whatever it is, I am out of ideas. I don't know what else to try. Like you saw, it works fine on my non-Up boards, so this seems to be something that maybe dcleri might know about.
  • KurtKurt New Member Posts: 146 ✭✭
    edited August 2017
    Thanks,

    I am also out of ideas here. For what it is worth, I converted over to using Adafruit RPI 2.8" tft Hat instead of a PJRC display... Verified same results. Although I needed to edit which pins I was using for CS and DC. Again still same results.

    I then tried temporarily installing of the FBTFT from the page: https://up-community.org/wiki/TFT_Display_HATs

    I then tried displaying the image file using the fbi and it also showed a similar timing.

    I then tried the mplayer app and it also showed similar gaps between groups of bytes and if I am looking at the data correctly it is showing that the bytes were output at 25MHz and each page output took about .1761 s plus a slight gap, so the actual throughput was something like 4.4 frames per second.

    As you mentioned hopefully someone else like @dcleri has some other ideas.

    Here is a screen shot of the start of one frame being output from the mplayer. Where you can see the gaps between groups of bytes;
  • Nicola LunghiNicola Lunghi Emutex Posts: 131 mod
    Hi WereCatf

    we had to disable the writing access to the wiki because of the heavy spam that we get there.
    In the meantime please send me a message with the information that you want to share and I will provide to add it myself

    Regards
    Nicola Lunghi
  • KurtKurt New Member Posts: 146 ✭✭
    Hi WereCatf

    we had to disable the writing access to the wiki because of the heavy spam that we get there.
    In the meantime please send me a message with the information that you want to share and I will provide to add it myself

    Regards
    Nicola Lunghi
    That is always a shame, that the people doing spam have messed up so many useful things on the forms and the like!

    I wonder does it need to be all or nothing? That is it could not be something like:
    a) Only people who have so many dots next to their name (not sure if this is set by number of posts, or thank you, or Karma or...) are allowed to make edits.
    b) Maybe not have a list of people who have write access. Where maybe there is a sign up page and the moderators need to approve each person who is added to the list.
    c) All edits (or for those without enough ranking) must go through some moderation queue...
  • DCleriDCleri Administrator, AAEON Posts: 642 admin
    Hi Kurt,

    We are looking into options to enable people who contribute the most on the forums to be available to add content to the wiki, projects, etc.

    We will keep you posted!
  • WereCatfWereCatf New Member Posts: 201
    Eh, I can understand the concern with spam, no one likes that stuff. Also, I understand that you can't just blindly trust people here -- even including me -- so even if you never allow any of us to contribute directly to the wiki I won't complain. Just do what you guys think is best.
Sign In or Register to comment.