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)