Note: The first version of the architecture is: APP+JNI(NDK)+Driver(linux), the advantage is simple development, short cycle, also as my graduation project
Now updated to the second version, FM service is completely embedded in the Android system and becomes a system service. The architecture is: APP+Frameworks+JNI+HAL+Driver
The entire system design is roughly divided into three articles, including:
1. Driver design
2. System API Interface
3. APP Function Implementation
---------------------------------------------------(I) Driver Design-----------------------------------------------------------------
I have previously introduced the method of writing character drivers for iTop4412, so I will not go into detail here about the driver writing process. Here is the link: http://www.cnblogs.com/pngcui/p/4766504.html
The FM radio chip here uses the TEA5767HN module and uses I2C for communication, so our first step is to find the chip datasheet and find the device address of the chip, which is 0xC0
At the same time, you need to find the I2C communication protocol in the datasheet
It should be noted here that the standard I2C protocol is not so concise, but it is written in the datasheet, so let's write the code according to it.
Attached is the standard I2C communication protocol:
Write operation: START+device address+ACK+write register address+ACK+write data+ACK+STOP
Read operation: START+(device address+write flag)+ACK+write register address+ACK+(device address+read flag)+ACK+read data+STOP
START signal: When SCL is high, SDA changes from high to low
STOP signal: When SCL is high, SDA changes from low to high
With the I2C communication protocol, we next need to select the pin of the development board to connect the TEA5767HN chip.
Since the camera interface on the board is not occupied, we find the camera interface on the schematic, which is j27
I have selected the CAM_HREF pin and CAM_PCLK pin as the SDA and SCL lines of I2C respectively. Next, we need to find the definition of these two pins in the kernel's gpio configuration file.
{ EXYNOS4212_GPJ0(0), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, //CAM_D6 by pngcui
{ EXYNOS4212_GPJ0(1), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, //CAM_D7 by pngcui
{ EXYNOS4212_GPJ0(2), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, //CAM_PCLK by pngcui
{ EXYNOS4212_GPJ0(3), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, //CAM_D1 by pngcui
{ EXYNOS4212_GPJ0(4), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, //CAM_D2 by pngcui
{ EXYNOS4212_GPJ0(5), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, //CAM_D4 by pngcui
{ EXYNOS4212_GPJ0(6), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, //CAM_D3 by pngcui
{ EXYNOS4212_GPJ0(7), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, //CAM_VSYNC by pngcui
{ EXYNOS4212_GPJ1(0), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, //I2C_SCL7 by pngcui
{ EXYNOS4212_GPJ1(1), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, //CAM2M_RST by pngcui
{ EXYNOS4212_GPJ1(2), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, //CAM_HREF by pngcui
{ EXYNOS4212_GPJ1(3), S3C_GPIO_SLP_OUT0, S3C_GPIO_PULL_NONE}, //I2C_SDA7 by pngcui
{ EXYNOS4212_GPJ1(4), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, //NC-CAM2M_PWDN low=0v high=0.3v bu pngcui
It should be noted here that the comments inside do not correspond to the pins on the board, so it is best to write a test program in advance and then use a multimeter to test whether the pins correspond.
At this point, we can use the gpio_set_value function to control the two I2C lines. Next, we will write the official driver program!!!
1. Configure device information in the platform file
Reference: http://www.cnblogs.com/pngcui/p/4766504.html
2. Register driver information
1 struct platform_driver tea5767_driver = {
2.probe = tea5767_probe,
3.remove = tea5767_remove,
4.shutdown = tea5767_shutdown,
5. suspend = tea5767_suspend,
6.resume = tea5767_resume,
7.driver = {
8.name = DRIVER_NAME,
9.owner = THIS_MODULE,
10 }
11 };
12
13 /* init the driver */
14 static int __init tea5767_init(){
15
16 int err;
17
18 printk("tea5767 init start...n");
19
20 err = platform_driver_register(&tea5767_driver);
twenty one
22 printk("state is %dnn",err);
twenty three
24 return 0;
25 }
26
27 /* cleanup the driver */
28 static void __exit tea5767_exit(){
29
30 int i;
31
32 printk("tea5767 exit ..and free gpion");
33 gpio_free(SCL);
34 gpio_free(SDA);
35
36 platform_driver_unregister(&tea5767_driver);
37 }
38
39 MODULE_LICENSE("Dual BSD/GPL");
40 MODULE_AUTHOR("PNGCUI");
41
42 module_init(tea5767_init);
43 module_exit(tea5767_exit);
Note: include/linux/init.h describes the loading order of driver functions, with detailed description link: http://blog.csdn.net/maopig/article/details/7375933
3. When the name configured in the platform file matches the name in the driver successfully, it will automatically enter the probe function of the driver program.
1 static int tea5767_probe(struct platform_device *pdv){
2 int ret,i;
3 printk("tea5767_probe start..n");
4
5 pll = default_pll;
6
7
8 for(i=0; i 10 ret = gpio_request(tea5767_gpios[i], "tea5767"); 11 if (ret < 0) { 12 printk("%s: request GPIO %d for tea5767 failed, ret = %dn", DEVICE_NAME,i, ret); 13 goto exit; 14 } 15 else{ 16 printk("%s: request GPIO %d for tea5767 success, ret = %dn", DEVICE_NAME,i, ret); 17 s3c_gpio_cfgpin(tea5767_gpios[i], S3C_GPIO_OUTPUT); 18 gpio_set_value(tea5767_gpios[i], 0); 19 //gpio_free(tea5767_gpios[i]); 20 } twenty one twenty two } twenty three 24 //Enable chip 25 //mute=1&stby=1 26 write_data[0]=0xac; 27 write_data[1]=0x7a; 28 write_data[2]=0xd0; 29 write_data[3]=0x57; 30 write_data[4]=0x00; 31 32 tea5767_write(); 33 tea5767_read(); 34 35 //Initialize the chip 36 //Set to mute=1&freq=87400&stby=0 37 write_data[0]=0xa9; 38 write_data[1]=0x9d; 39 write_data[2]=0xa0; 40 write_data[3]=0x17; 41 write_data[4]=0x00; 42 tea5767_write(); 43 tea5767_read(); 44 45 ret = misc_register(&tea5767_dev); 46 if(ret<0) 47 { 48 printk("tea5767:register device failed!n"); 49 goto exit; 50 } 51 52 return 0; 53 54 exit: 55 misc_deregister(&tea5767_dev); 56 return ret; 57 } In this function, you can perform some chip initialization operations, enable the chip, etc. Here you need to check the specific registers in the chip datasheet to see what they mean. Write mode: Read Mode: Here I summarize here: /* * Read in 5 bytes of data -----------8---------------4------------------2-----------------1------------|----8----------------4---------------2--------------------1---- *1st byte: MUTE (mute = 1) SM (auto search = 1) PLL13 PLL12 -|- PLL11 PLL10 PLL9 PLL8 *2nd byte: PLL7 PLL6 PLL5 PLL4 -|— PLL3 PLL2 PLL1 PLL0 *3rd byte: SUD (SearchUp = 1) SSL1 (Search stop) SSL0 (Search stop) HLSI (LO) -|- MS (mono = 1) MR (right channel mute = 1) ML (left channel mute = 1) SWP1 (port 1 is high = 1) *4th byte: SWP2 (port 2 is high = 1) STBY (standby = 1) BL (US/Europe = 0) XTAL (clock frequency) -|- SMUTE (soft mute) HCC (High Cut) SNC (stereo noise cancellation 1) SI (SWPORT1 ready flag is 1) *5th byte: PLLREF (clock frequency) DTC (de-emphasis time) - - -|- - - - - */ /* * Read data 5 bytes -----------8-----------------4------------------2-----------------1----------|----8----------------4---------------2-----------------1------ *1st byte: RF (radio station found = 1) BLF (search end = 1) PLL13 PLL12 -|- PLL11 PLL10 PLL9 PLL8 *2nd byte: PLL7 PLL6 PLL5 PLL4 -|— PLL3 PLL2 PLL1 PLL0 *3rd byte: STEREO (stereo = 1) IF6 (intermediate frequency count result) IF5 (same as before) IF4 (same as before) -|- IF3 (same as before) IF2 (same as before) IF1 (same as before) IF0 (same as before) *4th byte: LEV3 (signal ADC) LEV2 (same as before) LEV1 (same as before) LEV0 (same as before) -|- CI3 (chip mark) CI2 (same as before) CI1 (same as before) 0 *5th byte: 0 0 0 0 -|- 0 0 0 0 */ For more specific instructions, please look up the chip's datasheet. 4. Finally, you can use the ioctl interface to implement specific functions 1 static int tea5767_ioctl(struct file *files, int cmd, int arg){ 2 int ret; 3 printk("Hello tea5767 and cmd is %d,arg is %dn",cmd,arg); 4 5 switch(cmd){ 6 7 //Turn on mute 8 case OPENMUTE: 9 openMute(); 10 break; 11 12 //Turn off mute 13 case CLOSEMUTE: 14 closeMute(); 15 break; 16 17 //Manual search 18 cases Search: 19 search(arg); 20 break; twenty one 22 //Automatic search 23 case AutoSearch: 24 return auto_search(arg,1); 25 //break; 26 //Get signal strength 27 case ADC: 28 return getADC(); 29 30 //Get the current channel 31 case FREQ: 32 get_frequency(); 33 return Frequency_Read; 34 35 //Set channel 36 case SETFREQ: 37 return setFreq(arg); 38 //break; 39 40 //Standby, silent mode 41 case SHUTDOWN: 42 setShutDown(); 43 break; 44 45 default: 46 printk("default--cmd=%d,arg=%dn",cmd,arg); 47 //test(cmd,arg); 48 //break; 49 return -1; 50 } 51 52 return 0; 53 } 5. Attach the complete drive test program 1 #include 2 #include 3 4 5 #include 6 #include 7 #include 8 9 10 #define MAXC 10 11 12 main() 13 { 14 int fd; 15 char state[MAXC],cmd[MAXC]; 16 char drv[] = "/dev/tea5767"; 17 18 if((fd = open(drv, O_RDWR|O_NOCTTY|O_NDELAY))<0) 19 printf("open %s failed",drv); 20 else{ 21 while(1){ twenty two 23 printf("Input cmd state: "); 24 scanf("%s %s",cmd,state); 25 printf("Your Input :cmd = %d,state=%dn",atoi(cmd),atoi(state)); 26 if(atoi(state) < 0 || atoi(cmd) < 0) 27 break; 28 ioctl(fd,atoi(cmd),atoi(state)); 29 30 } 31 } 32 return 0; 33 }
Previous article:Android development process based on Xunwei 4412 development board
Next article:Design of FM radio system based on iTop4412 (Part 2)
- Popular Resources
- Popular amplifiers
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- CGD and Qorvo to jointly revolutionize motor control solutions
- CGD and Qorvo to jointly revolutionize motor control solutions
- Keysight Technologies FieldFox handheld analyzer with VDI spread spectrum module to achieve millimeter wave analysis function
- Infineon's PASCO2V15 XENSIV PAS CO2 5V Sensor Now Available at Mouser for Accurate CO2 Level Measurement
- Advanced gameplay, Harting takes your PCB board connection to a new level!
- Advanced gameplay, Harting takes your PCB board connection to a new level!
- A new chapter in Great Wall Motors R&D: solid-state battery technology leads the future
- Naxin Micro provides full-scenario GaN driver IC solutions
- Interpreting Huawei’s new solid-state battery patent, will it challenge CATL in 2030?
- Are pure electric/plug-in hybrid vehicles going crazy? A Chinese company has launched the world's first -40℃ dischargeable hybrid battery that is not afraid of cold
- Zhongke Bluexun Bluetooth Headset SDK Analysis and Sharing
- I don't know much about motors, so I would like to ask a question about three-phase stepper motor drive!
- PCB failure analysis technology and some cases
- Analysis of competition control questions
- 14:00 PM Live: TI desktop DLP 3D printing, 3D scanning and industrial display applications based on DLP Pico technology
- How to efficiently solve the problem of Kelvin test pin selection for high-precision resistors in PCBA?
- Original and Source
- Analysis of transistor voltage stabilization circuit
- Share and summarize the problems in lithium-ion battery production
- Thanks to the forum administrators for helping me find a good job in Tianjin. Thank you!