A40i Usage Notes: First physical drive HX711 (no device tree used)

Posted by thom2002 on Thu, 21 Oct 2021 21:16:42 +0200

1. Preface

It was another late night, and I no longer know how many consecutive days I had no regular rest. Early in each day, I decided to go to bed earlier in the evening, but at night I came to think and study or to do something impulsively, so I quickly finished writing and sleeping.

This is my first Linux driver based on the Full Log a40i platform. It may not be a special standard or use the device tree. It is not perfect. Everything is difficult at the beginning. I will continue to update the series of A40i usage notes after the beginning.

2. Environment

Full log A40i

linux3.10

3. Body

This article is mainly to record the code, the detailed description of the function I also did not say, a large number of online teaching videos, are more professional.

Why do we have to write the underlying drivers? The main reason is that when it comes to the project of interface development, we have already used the qt interface development, which is equivalent to turning to the Linux platform, no longer using stm32 for interface development, or 32 for no interface development or small screen oled or dot matrix screen, some control classes are still used. Now that Linux is used as the upper machine, there are some underlying ic drivers to read information. Here I use the hx711 reading weight, but I don't want to attach a 32 to use serial port to communicate. The main reason is that I don't want to take up extra board space, because Linux can drive ic itself. Why give up using 32 just because I won't drive development? So just learn, it's almost a week to be in the current position, and to watch video + actually knock code to verify, you've got the basic framework.

In the following body, the hx711 driver uses a c file and an application layer file

The driver file core code is as follows:

//Entry: insmod
static int hx711_init(void)
{
	int err;
    int i;
	printk(KERN_INFO "hx711_drv_init\n");
	//Register Character Device
	major = register_chrdev(0, "hx711_drv", &hx711_drv);  //Parameter 1:0 assigns device number dynamically, parameter 2: device name, parameter 3: file operation structure//returns the requested device number

	//Create a class and register it with the kernel
	hx711_class = class_create(THIS_MODULE, "hx711_class");//Parameter 1:owner, parameter 2:class name//Return class struct pointer
	err = PTR_ERR(hx711_class);
	if (IS_ERR(hx711_class)) { 
		printk(KERN_ERR "hx711_class err\n");
		//Uninstall registered devices
 		unregister_chrdev(major, "hx711_drv");//Parameter 1: assigned device number, parameter 2: device name
		return -1;
	}
	//Create a device file informing the user that the name of the creation in the'/dev/'directory is hx711_ Device files for class-x
	device_create(hx711_class, NULL, MKDEV(major, 0), NULL, "hx711_class-0", 0); //Parameter 1:class structure pointer, parameter 3:device number, parameter 5:node name, parameter 6:secondary device number
	

	//Initialize io function
    for(i = 0; i < ARRAY_SIZE(led_info); i++) {//Traversing led_info structure
        int result = gpio_request(led_info[i].gpio,led_info[i].name);//Apply for GPIO hardware resources from the kernel first;
		if(result!=0){//Determine whether the GPIO resource requested is successful or not, and fail to return a prompt
			printk(KERN_ERR "GPIO%d has used...led init err!\n",led_info[i].gpio);//Print error message
			return -1;
		}		
    }
	gpio_direction_output(led_info[0].gpio, 0);//Set GPIO as output function, output 0//sclk
	gpio_direction_input(led_info[1].gpio);//Set GPIO as input function//sda	

	printk(KERN_INFO "hx711_drv_init ok...\n");
    return 0;
}

//Export: rmmod
static void hx711_exit(void)
{
    int i;	
	//Release gpio
    for(i = 0; i < ARRAY_SIZE(led_info); i++) {//Traversing led_info structure
        gpio_free(led_info[i].gpio);//Release GPIO hardware resources
    } 

	//Delete Device Class
	device_destroy(hx711_class, MKDEV(major, 0));//Parameter 1:class structure pointer, parameter 2:device number
	//Unregister class
	class_destroy(hx711_class);//Parameter: class struct pointer
	
	//Uninstall registered devices
	unregister_chrdev(major, "hx711_drv");//Parameter 1: assigned device number, parameter 2: device name
	
	printk(KERN_INFO "hx711_drv_exit\n");
}
unsigned long HX711_Read(void)  //Read data read by 711
{
    unsigned long val; 
    unsigned char i; 	
    HX711_SCL1_L(); 
    val = 0;
    while(HX711_SDA1_IN());
    udelay(1); 
    for(i=0;i<24;i++){ 
		HX711_SCL1_H(); 
		val=val<<1; 
		udelay(1);
		HX711_SCL1_L(); 
		if(HX711_SDA1_IN()) 
		    val++; 
		udelay(1);
    } 
    HX711_SCL1_H(); 
    val = val^0x800000; 
    udelay(1);
    HX711_SCL1_L(); 
    udelay(1);
	
    return val; 	
}


int hx711_buffer=0;//Define hx711_buffer to accept information read by hx711read
int weight_maopi=0;//Fur weight
int weight_shiwu=0;//Physical weight
//Obtain fur weight and record
int Get_Maopi(void)
{
    hx711_buffer=HX711_Read();
    weight_maopi=hx711_buffer;
    return weight_maopi;
}
//Obtain net weight and record
int Get_Weight(void)
{
    hx711_buffer=HX711_Read();
	if(hx711_buffer>weight_maopi)
		weight_shiwu=hx711_buffer-weight_maopi;
//    weight_shiwu=weight_shiwu/100;
//    weight_shiwu=(unsigned int)((float)weight_shiwu/4.30+0.05);// Each sensor needs to correct the divisor of 4.30. Increase this value when you find that the weight tested is too large. If the measured weight is small, reduce the change. This value is generally between 4.0 and 5.0. Depending on the linear slope of the sensor.			
    return weight_shiwu;
}

The application file code is as follows:

char *hx711_PATH = "/dev/hx711_class-0";
int main(int argc, char **argv)
{
	int fd;
	int weight_int;
	double weight_double;
	

	/* Open File */
	fd = open(hx711_PATH, O_RDWR);
	if (fd == -1){
		printf("can not open file %s\n", hx711_PATH);
		return -1;
	}

	/* read file */
	weight_int = 1;
	read(fd, &weight_int, sizeof(int));//Reading fur
	printf("maopi = %d\r\n",weight_int);
	while(1){
		usleep(100000);//100 ms delay
		weight_int = 2;
		read(fd, &weight_int, sizeof(int));//Read Net Weight
		weight_double = weight_int;
		weight_double = weight_double/100;
		weight_double=(unsigned int)((float)weight_double/4.30+0.05);//Each sensor needs to correct the divisor of 4.30. Increase this value when you find that the weight tested is too large. If the measured weight is small, reduce the change. This value is generally between 4.0 and 5.0. Depending on the linear slope of the sensor.			
		printf("weight = %.4fg\r\n",weight_double);
	}
	close(fd);
	return 0;
}

The previous section describes how to compile driver files and cross-compile application files, and finally compile to generate ko files and executable program files, as shown below. Downloads from resources are

  The following commands are used:

  • lsmod View Loaded Kernel Modules
  • insmod Load Kernel Module
  • rmmod Uninstall Kernel Module
  • dmesg View Log Information
  • Dmesg-c Clears Log Information
  • ls   / dev View Device Node
  • Cat/proc/devices View device number

The final test results are as follows:

 

IV. Conclusion

Quick Decision, Next Driver, Ready to Drive AD7606, Start~

Topics: Linux