2

I am using a raspberry pi to grab data through a SPI port. Attached to the SPI port is a PIC, programmed so that it samples on an A/D at 12.8kHz, and stores the samples in a 256 long buffer. (to cope with linux process pause and runs).

I have a linux program that reads the SPI and writes to a file. a couple of times per second I am getting missing data, I believe because linux is taking too long to return to my C program.

I understand that Linux (Raspbian) is not real-time and a process/program can be interrupted at any time, and that is why I am using a buffer in the PIC, to ride through these interruptions.

The problem is that sometimes the delay where the program waits is too large, and so I am missing some of the data. This happens maybe once every few seconds:

I would like suggestions for reducing the time, or at least setting a maximum time between process run time slices.

I have tried running with a nice level of -15 and -20.

Is there a way to reduce time slices?

Is there a memory disk on Raspbian that I can try writing my file to, incase it is the writing of the file that is causing it?

Here is some output from top:

top - 14:01:23 up  2:25,  3 users,  load average: 1.91, 2.09, 2.18
Tasks:  76 total,   1 running,  75 sleeping,   0 stopped,   0 zombie
%Cpu(s):  7.6 us, 28.9 sy,  0.0 ni, 63.2 id,  0.0 wa,  0.0 hi,  0.3 si,  0.0 st
KiB Mem:    185732 total,   105708 used,    80024 free,    21112 buffers
KiB Swap:   102396 total,        0 used,   102396 free,    43916 cached

  PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND                                                  
  353 root      20   0     0    0    0 D  15.3  0.0  17:01.87 spi0                                                     
13296 root       5 -15  2652 1468 1344 D  12.1  0.8   0:09.21 a.out                                                    
13386 pi        20   0  4708 2500 2064 R   1.6  1.3   0:00.40 top                                                      
 4707 pi        20   0  4176 2572 1976 S   1.0  1.4   2:48.66 watch                                                    
11547 root      20   0     0    0    0 S   0.6  0.0   0:03.59 kworker/u2:1                                             
   16 root      20   0     0    0    0 S   0.3  0.0   0:05.60 kworker/0:1                                              
 2524 pi        20   0  9288 3296 2708 S   0.3  1.8   0:00.62 sshd                                                     
12448 root      20   0     0    0    0 S   0.3  0.0   0:02.98 kworker/u2:4                                             
    1 root      20   0  2168 1368 1260 S   0.0  0.7   0:02.22 init                                                     
    2 root      20   0     0    0    0 S   0.0  0.0   0:00.00 kthreadd                                                 
    3 root      20   0     0    0    0 S   0.0  0.0   0:06.88 ksoftirqd/0                                              
    5 root       0 -20     0    0    0 S   0.0  0.0   0:00.00  

I can see from top that the a.out and spi0 process are using the most CPU time, but they are not maxing it out. Here you can see my process has a nice of -15.

Maybe one of the processes that is running is interfering? Here are my running processes, a.out is my SPI reading program.

pi@raspberrypi ~/frd/src/raspi/xcodefrd $ ps -ae
  PID TTY          TIME CMD
    1 ?        00:00:02 init
    2 ?        00:00:00 kthreadd
    3 ?        00:00:07 ksoftirqd/0
    5 ?        00:00:00 kworker/0:0H
    7 ?        00:00:00 khelper
    8 ?        00:00:00 kdevtmpfs
    9 ?        00:00:00 netns
   10 ?        00:00:00 perf
   11 ?        00:00:00 khungtaskd
   12 ?        00:00:00 writeback
   13 ?        00:00:00 crypto
   14 ?        00:00:00 bioset
   15 ?        00:00:00 kblockd
   16 ?        00:00:06 kworker/0:1
   17 ?        00:00:00 rpciod
   18 ?        00:00:00 kswapd0
   19 ?        00:00:00 fsnotify_mark
   20 ?        00:00:00 nfsiod
   26 ?        00:00:00 kthrotld
   27 ?        00:00:00 VCHIQ-0
   28 ?        00:00:00 VCHIQr-0
   29 ?        00:00:00 VCHIQs-0
   30 ?        00:00:00 iscsi_eh
   31 ?        00:00:00 dwc_otg
   32 ?        00:00:00 DWC Notificatio
   34 ?        00:00:00 kworker/0:2
   35 ?        00:00:01 mmcqd/0
   36 ?        00:00:00 VCHIQka-0
   37 ?        00:00:00 SMIO
   38 ?        00:00:00 deferwq
   40 ?        00:00:00 jbd2/mmcblk0p6-
   41 ?        00:00:00 ext4-rsv-conver
  156 ?        00:00:00 udevd
  286 ?        00:00:00 udevd
  293 ?        00:00:00 udevd
  321 ?        00:00:00 cfg80211
  353 ?        00:18:14 spi0
  411 ?        00:00:00 kworker/0:1H
 1792 ?        00:00:06 ifplugd
 1795 ?        00:00:01 ifplugd
 1797 ?        00:00:01 ifplugd
 1800 ?        00:00:00 wpa_supplicant
 1877 ?        00:00:00 dhclient
 2246 ?        00:00:00 rsyslogd
 2248 ?        00:00:00 thd
 2296 ?        00:00:00 cron
 2326 ?        00:00:00 dbus-daemon
 2393 ?        00:00:01 ntpd
 2422 ?        00:00:00 sshd
 2513 tty1     00:00:00 getty
 2514 tty2     00:00:00 getty
 2515 tty3     00:00:00 getty
 2516 tty4     00:00:00 getty
 2517 tty5     00:00:00 getty
 2518 tty6     00:00:00 getty
 2519 ?        00:00:00 getty
 2520 ?        00:00:00 sshd
 2524 ?        00:00:04 sshd
 2525 pts/0    00:00:02 bash
 2545 ?        00:00:00 sshd
 2549 ?        00:00:39 sshd
 2550 ?        00:00:13 sftp-server
 2551 ?        00:00:00 sshd
 2555 ?        00:00:00 sshd
 2556 pts/1    00:00:01 bash
 2583 ?        00:00:00 sshd
 2587 ?        00:00:03 sshd
 2588 pts/2    00:00:01 bash
 4707 pts/2    00:02:56 watch
 8843 ?        00:00:06 kworker/u2:0
11547 ?        00:00:04 kworker/u2:1
12448 ?        00:00:03 kworker/u2:4
13186 ?        00:00:03 kworker/u2:2
13295 pts/0    00:00:00 sudo
13296 pts/0    00:01:09 a.out
13690 ?        00:00:01 kworker/u2:3
14083 pts/0    00:00:00 ps

This is what my data stream looks like, you can spot the bit where the SPI reads were delayed:

The data stream, you can see missing data for about half a cycle around sample 3850

You may of course want a look at my code. I have tried different buffer sizes.

#include <stdio.h>
#include <stdlib.h>
#include <wiringPi.h>
#include <sys/timeb.h>
#include <time.h>
#include <sys/timeb.h>

#include "frdSPI.h"
#include "frdBuffer.h"

#define TRIGGERVAL 50

#define BUFF_SIZE 32

int main(void){

    unsigned char buffer[BUFF_SIZE];
    int i, sample, channel = 0 , triggerdifference, oldsample, qtytowriteout = 0;
    unsigned long int samplenumber=0;
    unsigned long int differencenumber=0;

    FILE *fp;
    char filename[100];

    struct timeb recordtime;


    // Following is test code to see how to make filename and use it to write a file.
    ftime( &recordtime );
    sprintf( filename, "/frd/data/%ld%03ld.startup", recordtime.time, recordtime.millitm);

    fp = fopen( filename ,"w" );
    fprintf( fp, "test and more %lu", samplenumber);
    fclose(fp);



    if ( wiringPiSPISetup (channel, 500000) < 0){
        fprintf (stderr, "SPI Setup failed! Check module is loaded and run app as root.\n");
        exit(-1);
    }

    while(1){
        wiringPiSPIDataRW ( channel, &buffer, BUFF_SIZE );

        for(i=0; i<BUFF_SIZE; i++){
            sample=parseSPIDataStream(buffer[i]);
            if( sample > -1 ){
                samplenumber++;
                oldsample = circularbufferreadwrite( sample );

                if( calculateDifferenceValue(sample, &triggerdifference))
                {
                    differencenumber++;
                    if( triggerdifference > TRIGGERVAL || triggerdifference < (-1 * TRIGGERVAL) ){
                        //printf("%d \n", triggerdifference);
                        if( qtytowriteout == 0 )
                        {
                            ftime( &recordtime );
                            sprintf( filename, "/tmp/%ld%03ld.csv", recordtime.time, recordtime.millitm);
                            fp = fopen(filename,"w");
                            samplenumber=0;
                        }
                        if( qtytowriteout < 4000 )
                            qtytowriteout = qtytowriteout + 12800;
                    }
                }

                if( qtytowriteout && (fp!=(FILE *)NULL))
                {
                    //printf("%lu,%d\n", samplenumber, oldsample);
                    fprintf(fp, "%lu,%d\n", samplenumber, oldsample);
                    qtytowriteout--;
                    if( qtytowriteout == 0 ){
                        fclose(fp);
                        printf("\b");
                    }
                }
            }
        }
    }
}

Thank you for any help and suggestions in advance.

EDIT I just ran dd if=/dev/zero of=/dev/null as well, to take up some CPU time, and this has made the problems significantly worse, so I think I am on the right track, but I could do with some pointers as to how to fix it. Here is a graph of the data when using more CPU time:

enter image description here

A comment below queried parseSPIDataStream, so I've included it here:

int parseSPIDataStream( char databyte ){

    static int state=0;
    static int result=0;
    static int ignorebytes=10;
    static int synced=FALSE;

    if( ignorebytes==0 )
    {

        switch( databyte )
        {
            case 0X7E:          //0x7E Filler and sync
                state=0;
                synced=TRUE;
                return(-1);

            case 0x7D:          //Next Char is escaped
                state=2;
                return(-1);

            default:
                break;
        }

        switch( state )
        {
            case 0:         //High Byte of result
                result = 256 * databyte;
                state=1;
                return(-1);

            case 1:         //Low byte of result
                result = result + databyte;
                state=0;
                if( synced )
                    return(result);
                else
                    return(-1);

            case 2:         //Escaped Low Byte
                result = result + 0x20 + databyte;
                state=0;
                if( synced )
                    return(result);
                else
                    return(-1);

            default:            //There is an error!!!
                return(-2);
        }

    }else{
        ignorebytes--;
        return(-3);
    }

}

closed as off-topic by slm Jul 29 '17 at 17:36

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "This question has been posted on multiple sites. Cross-posting is strongly discouraged; see the help center and community FAQ for more information." – slm

  • regarding this statement: if( triggerdifference > TRIGGERVAL | triggerdifference < (-1 * TRIGGERVAL) ) the single | is a boolean OR. What you really want is a logical OR || – user3629249 Jul 28 '17 at 15:22
  • when calling fopen(), always check (!=NULL) the returned value to assure the operation was successful – user3629249 Jul 28 '17 at 15:25
  • regarding: sprintf( filename, "/frd/data/%ld%03ld.startup", recordtime.time, recordtime.millitm); and char filename[20]; the array filename is not long enough to hold all the characters being written into it by the call to sprintf() This buffer overrun results in undefined behavior and can lead to a seg fault event. – user3629249 Jul 28 '17 at 15:29
  • @user3629249. I appreciate your very insightful comments, and will modify the code accordingly. Thank you. – J Rodgers Jul 28 '17 at 15:50
  • the variable channel is not initialized. so using that uninitialized value in your posted code results in undefined behavior. There are several other problems with the posted code. – user3629249 Jul 28 '17 at 15:59