Thursday, February 3, 2022

[SOLVED] errors with C code (reads GPIO input off a Raspberry Pi Zero W), compiles on Jessie but doesn't compile on Buster Lite

Issue

I am very new to C (had one semester class like 5 years ago). To summarize my problem, I have code written in C that compiles on Raspbian Jessie, but not Buster Lite.

I'm using a Raspberry Pi Zero W + ADCs to input an analog signal, digitize it, and transmit it wirelessly and the code I'm having issues with takes the data from the GPIOs and stores it in a buffer that I can read from. I previously was running Raspbian Jessie on my pi and I had NO issues compiling the code (no warnings, no errors). It was correctly reading data from the ADCs and storing it in the buffer. When I installed Raspbian Buster Lite on my Pi, and have been getting multiple errors/warnings when compiling. (I'm not concerned about the warnings/notes, know how to fix them, just the errors. partly included because I don't understand why they appeared on Buster but not on Jessie)

make -C /lib/modules/4.19.97+/build M=/home/pi modules
make[1]: Entering directory '/usr/src/linux-headers-4.19.97+'
  CC [M]  /home/pi/adc.o
/home/pi/adc.c:132:9: warning: useless storage class specifier in empty declaration
         };
         ^
/home/pi/adc.c: In function ‘readScope’:
/home/pi/adc.c:176:13: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
             struct timespec ts_start,ts_stop;
             ^~~~~~
/home/pi/adc.c:218:29: error: assignment to ‘unsigned char *’ from incompatible pointer type ‘struct DataStruct *’ [-Werror=incompatible-pointer-types]
             ScopeBufferStart=&dataStruct;
                             ^
/home/pi/adc.c: At top level:
/home/pi/adc.c:225:9: warning: "/*" within comment [-Wcomment]
         /*

In file included from ./include/linux/printk.h:7,
                 from ./include/linux/kernel.h:14,
                 from /home/pi/adc.c:1:
/home/pi/adc.c: In function ‘init_module’:
./include/linux/kern_levels.h:5:18: warning: too many arguments for format [-Wformat-extra-args]
 #define KERN_SOH "\001"  /* ASCII Start Of Header */
                  ^~~~~~
./include/linux/kern_levels.h:9:20: note: in expansion of macro ‘KERN_SOH’
 #define KERN_ALERT KERN_SOH "1" /* action must be taken immediately */
                    ^~~~~~~~
/home/pi/adc.c:248:24: note: in expansion of macro ‘KERN_ALERT’
                 printk(KERN_ALERT,"Failed to map the physical GPIO registers into the virtual memory space.\n");
                        ^~~~~~~~~~
/home/pi/adc.c:283:13: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
             struct bcm2835_peripheral *p=&myclock;
             ^~~~~~
/home/pi/adc.c:290:13: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
             int speed_id = 6; //1 for to start with 19Mhz or 6 to start with 500 MHz
             ^~~
/home/pi/adc.c: In function ‘device_read’:
/home/pi/adc.c:359:35: warning: comparison of distinct pointer types lacks a cast
             while (length && buf_p<ScopeBufferStop) {
                                   ^
In file included from /home/pi/adc.c:4:
./arch/arm/include/asm/uaccess.h:387:33: error: incompatible types when initializing type ‘char’ using type ‘struct DataStruct’
   __typeof__(*(ptr)) __pu_val = (x);   \
                                 ^
./arch/arm/include/asm/uaccess.h:404:2: note: in expansion of macro ‘__put_user_switch’
  __put_user_switch((x), (ptr), __pu_err, __put_user_check); \
  ^~~~~~~~~~~~~~~~~
/home/pi/adc.c:361:23: note: in expansion of macro ‘put_user’
                 if(0!=put_user(*(buf_p++), buffer++))
                       ^~~~~~~~
At top level:
/home/pi/adc.c:111:26: warning: ‘ScopeBuffer_Ptr’ defined but not used [-Wunused-variable]
         static uint32_t *ScopeBuffer_Ptr;
                          ^~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
make[2]: *** [scripts/Makefile.build:310: /home/pi/adc.o] Error 1
make[1]: *** [Makefile:1522: _module_/home/pi] Error 2
make[1]: Leaving directory '/usr/src/linux-headers-4.19.97+'
make: *** [Makefile:4: all] Error 2

What I've tried: One of the first errors I got (code updated since then, used to have buf_ declared as const char *buf_p;) is that I'm using incompatible pointer types:

/home/pi/adc.c:262:19: error: assignment to ‘unsigned char *’ from incompatible pointer type ‘struct DataStruct *’ [-Werror=incompatible-pointer-types]
   ScopeBufferStart=&dataStruct;

When I fix this (by redefining the variable buf_p as a struct DataStruct), I get a new error in the device_read function that I haven't been able to fix:

In file included from /home/pi/adc.c:13:
./arch/arm/include/asm/uaccess.h:387:33: error: incompatible types when initializing type ‘char’ using type ‘struct DataStruct’
   __typeof__(*(ptr)) __pu_val = (x);   \

I also noticed that the output from the Makefile on Buster Lite I get

make -C /lib/modules/4.19.97+/build M=/home/pi modules
make[1]: Entering directory '/usr/src/linux-headers-4.19.97+'
...
...
make[1]: Leaving directory '/usr/src/linux-headers-4.19.97+'

while on Jessie I get

make -C /lib/modules/`uname -r`/build M=$PWD
make[1]: Entering directory '/usr/src/linux-source-4.4.50+'
  Building modules, stage 2.
  MODPOST 1 modules
make[1]: Leaving directory '/usr/src/linux-source-4.4.50+'

Here is my code...

    #include <linux/kernel.h>
    #include <linux/module.h>
    #include <linux/fs.h>
    #include <asm/uaccess.h>
    #include <linux/time.h>
    #include <linux/io.h>
    #include <linux/vmalloc.h>
    #include <linux/delay.h>
    #include <linux/fcntl.h> /*Helps fix O_ACCMODE*/

    #include <linux/sched.h> /*Helps fix TASK_UNINTERRUPTIBLE */

    #include <linux/fs.h> /*Helps fix the struct intializer */

    int __init init_module(void);
    void __exit cleanup_module(void);
    static int device_open(struct inode *, struct file *);
    static int device_release(struct inode *, struct file *);
    static ssize_t device_read(struct file *, char *, size_t, loff_t *);
    static ssize_t device_write(struct file *, const char *, size_t, loff_t *);

    #define SUCCESS 0
    #define DEVICE_NAME "stdin"// Dev name
    #define BUF_LEN 80//Max length of device message 

    //---------------------------------------------------------------------------------------------------------
    //Things for the GPIO Port 

    #define BCM2708_PERI_BASE       0x20000000
    //if you're using a RPi3, PERIBASE value should be changed to 0x3F000000    
    #define GPIO_BASE               (BCM2708_PERI_BASE + 0x200000)  // GPIO controller   
    // depends on the RPi

    #define INP_GPIO(g)   *(gpio.addr + ((g)/10)) &= ~(7<<(((g)%10)*3)) 
    #define OUT_GPIO(g)   *(gpio.addr + ((g)/10)) |=  (1<<(((g)%10)*3)) //001
    //alternative function
    #define SET_GPIO_ALT(g,a) *(gpio.addr + (((g)/10))) |= (((a)<=3?(a) + 4:(a)==4?3:2)<<(((g)%10)*3))

    #define GPIO_SET  *(gpio.addr + 7)  // sets   bits which are 1 ignores bits which are 0
    #define GPIO_CLR  *(gpio.addr + 10) // clears bits which are 1 ignores bits which are 0

    #define GPIO_READ(g)  *(gpio.addr + 13) &= (1<<(g))


    //GPIO Clock
    #define CLOCK_BASE              (BCM2708_PERI_BASE + 0x00101000)
    #define GZ_CLK_BUSY (1 << 7)

    //---------------------------------------------------------------------------------------------------------

    //How many samples to capture
    #define SAMPLE_SIZE     10000 // 2x2500 pts in one line 
    #define REPEAT_SIZE     10 // 10 captures   

    //Define GPIO Pins

    //ADC 1
    #define BIT0_ADC1 16
    #define BIT1_ADC1 17
    #define BIT2_ADC1 18
    #define BIT3_ADC1 19
    #define BIT4_ADC1 20
    #define BIT5_ADC1 22
    #define BIT6_ADC1 25
    #define BIT7_ADC1 26
    #define BIT8_ADC1 27

    //ADC 2
    #define BIT0_ADC2 7
    #define BIT1_ADC2 8
    #define BIT2_ADC2 9
    #define BIT3_ADC2 10
    #define BIT4_ADC2 11
    #define BIT5_ADC2 12
    #define BIT6_ADC2 13
    #define BIT7_ADC2 14
    #define BIT8_ADC2 15

    // Pulser
    #define Puls_ON  23
    #define Puls_OFF 24

    #define PPWWMM 6

    #define MY_NOP(__N)                 __asm ("nop");    // or sth like "MOV R0,R0"


    //---------------------------------------------------------------------------------------------------------

    // IO Acces
    struct bcm2835_peripheral {
        unsigned long addr_p;
        int mem_fd;
        void *map;
        volatile unsigned int *addr;

    };

    static int map_peripheral(struct bcm2835_peripheral *p);
    static void unmap_peripheral(struct bcm2835_peripheral *p);
    static void readScope(void);


    static int Major;       /* Major number assigned to our device driver */
    static int Device_Open = 0; /* Is device open?  
                     * Used to prevent multiple access to device */
    static char msg[BUF_LEN];   /* The msg the device will give when asked */
    static char *msg_Ptr;


    static uint32_t *ScopeBuffer_Ptr;
    // static unsigned char *buf_p;


    static struct file_operations fops = {
        .read = device_read,
        .write = device_write,
        .open = device_open,
        .release = device_release
    };

    //--------------------------------------------------------------------------------------------------------

    static struct bcm2835_peripheral myclock = {CLOCK_BASE};

    static struct bcm2835_peripheral gpio = {GPIO_BASE};


    static struct DataStruct{
        uint32_t Buffer[REPEAT_SIZE*SAMPLE_SIZE];
        uint32_t time;
    };

    struct DataStruct dataStruct;
   struct DataStruct *buf_p;
    static unsigned char *ScopeBufferStart;
    static unsigned char *ScopeBufferStop;

    //---------------------------------------------------------------------------------------------------------

    static int map_peripheral(struct bcm2835_peripheral *p)
    {
        p->addr=(uint32_t *)ioremap(GPIO_BASE, 41*4); //41 GPIO register with 32 bit (4*8)
       return 0;
    }

    static void unmap_peripheral(struct bcm2835_peripheral *p) {
        iounmap(p->addr);//unmap the address
    }


    //---------------------------------------------------------------------------------------------------------

    static void readScope(){

        int counter=0;
        int counterline = 0;
        int limit = 0;

        int Pon=0; 
        int Poff=0;
        //int Fail=0;

        OUT_GPIO(Puls_ON); 
        OUT_GPIO(Puls_OFF);

        GPIO_SET = 1 << Puls_ON; 
        GPIO_CLR = 1 << Puls_OFF;

        msleep(10);

        //disable IRQ
        local_irq_disable();
        local_fiq_disable();

        struct timespec ts_start,ts_stop;
        //Start time

        set_current_state(TASK_UNINTERRUPTIBLE);
        getnstimeofday(&ts_start);

        while(counterline<REPEAT_SIZE){ 
            Pon = 0; 
            Poff = 0;
            limit = (counterline+1)*SAMPLE_SIZE;


            while(counter<(limit) ){
                dataStruct.Buffer[counter++]= *(gpio.addr + 13); 
            }

            // to avoid freezes
        //  msleep(0.5);

            counterline++;
        }



        //Stop time
        getnstimeofday(&ts_stop);

        INP_GPIO(Puls_ON); 
        INP_GPIO(Puls_OFF);

        set_current_state(TASK_INTERRUPTIBLE);
        //enable IRQ
        local_fiq_enable();
        local_irq_enable();

        //save the time difference
        dataStruct.time=timespec_to_ns(&ts_stop)-timespec_to_ns(&ts_start);//ns resolution


//        buf_p=&dataStruct;//cound maybe removed
        buf_p=&dataStruct;//cound maybe removed

        ScopeBufferStart=&dataStruct;

        ScopeBufferStop=ScopeBufferStart+sizeof(struct DataStruct);
    }

    //---------------------------------------------------------------------------------------------------------
    /*
    /*
     * This function is called when the module is loaded
     */
    int init_module(void)
    {
        Major = register_chrdev(0, DEVICE_NAME, &fops);

        if (Major < 0) {
          printk(KERN_ALERT "Registering char device failed with %d\n", Major);
          return Major;
        }

        printk(KERN_INFO "I was assigned major number %d. To talk to\n", Major);
        printk(KERN_INFO "the driver, create a dev file with\n");
        printk(KERN_INFO "'mknod /dev/%s c %d 0'.\n", DEVICE_NAME, Major);
        printk(KERN_INFO "Try various minor numbers. Try to cat and echo to\n");
        printk(KERN_INFO "the device file.\n");
        printk(KERN_INFO "Remove the device file and module when done.\n");

        //Map GPIO

        if(map_peripheral(&gpio) == -1) 
        {
            printk(KERN_ALERT,"Failed to map the physical GPIO registers into the virtual memory space.\n");
            return -1;
        }

        //Define Scope pins
        // ADC1
        INP_GPIO(BIT0_ADC1);
        INP_GPIO(BIT1_ADC1);
        INP_GPIO(BIT2_ADC1);
        INP_GPIO(BIT3_ADC1);
        INP_GPIO(BIT4_ADC1);
        INP_GPIO(BIT5_ADC1);
        INP_GPIO(BIT6_ADC1);
        INP_GPIO(BIT7_ADC1);
        INP_GPIO(BIT8_ADC1);

        // ADC2
        INP_GPIO(BIT0_ADC2);
        INP_GPIO(BIT1_ADC2);
        INP_GPIO(BIT2_ADC2);
        INP_GPIO(BIT3_ADC2);
        INP_GPIO(BIT4_ADC2);
        INP_GPIO(BIT5_ADC2);
        INP_GPIO(BIT6_ADC2);
        INP_GPIO(BIT7_ADC2);
        INP_GPIO(BIT8_ADC2);

        // Setting pins for pulser
        OUT_GPIO(Puls_ON); 
        OUT_GPIO(Puls_OFF);

        GPIO_CLR = 1 << Puls_ON; // set pulser at 0
        GPIO_SET = 1 << Puls_OFF; // set damper at 1

        //Set a clock signal on Pin 4
        struct bcm2835_peripheral *p=&myclock;
        p->addr=(uint32_t *)ioremap(CLOCK_BASE, 41*4);

        INP_GPIO(4);
        SET_GPIO_ALT(4,0);

        // Preparing the clock
        int speed_id = 6; //1 for to start with 19Mhz or 6 to start with 500 MHz
        *(myclock.addr+28)=0x5A000000 | speed_id; //Turn off the clock
        while (*(myclock.addr+28) & GZ_CLK_BUSY) {}; //Wait until clock is no longer busy (BUSY flag)
        *(myclock.addr+29)= 0x5A000000 | (0x29 << 12) | 0;//Set divider //divide by 50 (0x32) -- ideally 41 (29) to fall on 12MHz clock
        *(myclock.addr+28)=0x5A000010 | speed_id;//Turn clock on

        return SUCCESS;
    }
    //---------------------------------------------------------------------------------------------------------
    /*
     * This function is called when the module is unloaded
     */
    void cleanup_module(void)
    {
        unregister_chrdev(Major, DEVICE_NAME);
        unmap_peripheral(&gpio);
        unmap_peripheral(&myclock);
    }
    //---------------------------------------------------------------------------------------------------------
    /* 
     * Called when a process tries to open the device file, like
     * "cat /dev/mycharfile"
     */
    static int device_open(struct inode *inode, struct file *file)
    {
        static int counter = 0;

        if (Device_Open)
            return -EBUSY;

        Device_Open++;
        sprintf(msg, "I already told you %d times Hello world!\n", counter++);
        msg_Ptr = msg;

        readScope();//Read n Samples into memory

        try_module_get(THIS_MODULE);

        return SUCCESS;
    }
    //---------------------------------------------------------------------------------------------------------
    /* 
     * Called when a process closes the device file.
     */
    static int device_release(struct inode *inode, struct file *file)
    {
        Device_Open--;      /* We're now ready for our next caller */
        module_put(THIS_MODULE);
        return 0;
    }
    //---------------------------------------------------------------------------------------------------------
    /* 
     * Called when a process, which already opened the dev file, attempts to
     * read from it.
     */
    static ssize_t device_read(struct file *filp,   
                   char *buffer,    
                   size_t length,
                   loff_t * offset)
    {

        // Number of bytes actually written to the buffer 
        int bytes_read = 0;

        if (*msg_Ptr == 0)
            return 0;

        //Check that we do not overfill the buffer

        while (length && buf_p<ScopeBufferStop) {

            if(0!=put_user(*(buf_p++), buffer++))
                printk(KERN_INFO "Problem with copy\n");
            length--;
            bytes_read++;
        }

        return bytes_read;
    }
    //---------------------------------------------------------------------------------------------------------
    /*  
     * Called when a process writes to dev file: echo "hi" > /dev/hello 
     */
    static ssize_t
    device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
    {
        printk(KERN_ALERT "Sorry, this operation isn't supported.\n");
        return -EINVAL;
    }

Thank you


Solution

So I think I have an answer. I realized I need to compile the linux kernel module on Buster before I can compile my adc code. On the Jessie disk image version I was using, I realized the linux kernel module had already been compiled, I think that's why on Jessie it's able to enter the linux source directory to compile while on Buster it enters the linux headers directory. Thank you



Answered By - Dev123
Answer Checked By - Marilyn (WPSolving Volunteer)