A simple Linux driver for a camera device
Transcription
A simple Linux driver for a camera device
Mirko Damiani A simple Linux driver for a camera device Better Embedded Conference Firenze, July 8-9, 2013 Terms of interest ● ● ● GNU/Linux ● GNU software ● Linux kernel Simple driver ● Easy to develop ● Easy to use from user-space Embedded system ● Custom boards ● Low resources 2 / 38 Mirko Damiani – [email protected] Prerequisites ● ● Entry level ● GNU/Linux kernel ● Locking primitives ● Operating systems ● Computer architectures Intermediate level ● GNU/Linux utilities ● SW development 3 / 38 Mirko Damiani – [email protected] Acquisition data path ● DM368 video process subsystem ● Camera sensor overview ● Color filter array 4 / 38 Reference board ● LeopardBoard 368 ● Texas Instruments DM368 ● ARM926EJ-S ● 432 MHz ● RAM 128MB ● NAND 256MB ● Camera parallel interface ● Video process subsystem ● Up to 32K pixels in both horizontal and vertical direction 5 / 38 Mirko Damiani – [email protected] Video process subsystem ● Image Sensor Interface (ISIF) ● ● ● ● Get raw data from sensor Output to RAM via a controller 12-to-8 bit conversion Paths to other subsystems 6 / 38 Mirko Damiani – [email protected] Camera board ● ● ● High resolution camera ● 2592 x 1944 (5Mp) ● 12 bit pixels @ 96MHz ● 14 fps ● Color Filter Array (Bayer Filter) Frame processing ● Binning, Skipping ● Black level calibration Programmable registers ● I2C interface 7 / 38 Mirko Damiani – [email protected] Sensor block diagram ● External clock: 24 MHz ● Pixel clock: 96 MHz ● Time needed to sample 1 pixel from the array Mirko Damiani – [email protected] 8 / 38 Color filter array ● Bayer format ● ● ● Invented by Bryce Bayer at Kodak in 1976 Human eye is more sensitive to green light Demosaicing ● ● Convert raw data into an RGB image Take neighborhood pixels 9 / 38 Mirko Damiani – [email protected] How to read frames ● Linux drivers ● System calls: read, mmap ● Camera parameters ● Frame rate 10 / 38 Types of Linux drivers ● ● Character driver ● A device accessed as a stream of bytes (like a file) ● Not always possible to move back and forth ● System calls: open, close, read, write ● e.g. serial port Block driver ● Host a filesystem ● I/O operations on whole blocks (e.g. 512 bytes) ● Random access and seeking ● e.g. hard disk 11 / 38 Mirko Damiani – [email protected] Accessing a Linux driver ● ● Filesystem nodes ● /dev folder ● mknod <name> [c|b] <major> <minor> Major and minor numbers ● Major: identifies the driver associated with a device – ● Serial port (major = 4) Minor: identifies a specific instance of the device – COM1 (minor = 64) – COM2 (minor = 65) 12 / 38 Mirko Damiani – [email protected] Camera device driver ● Character device! ● How frames are accessed? ● ● mmap ● read How many processes can get frames? ● ● One process only How can we apply camera setting? ● ioctl ● device parameters 13 / 38 Mirko Damiani – [email protected] System call: ioctl ● ● Usage ● int ioctl(int fd, int request, …) ● Quite simple Not useful for rapid prototyping ● Custom commands and structures must be defined ● Big switch statement over the command argument ● Programs must include a common header for definitions ● Command numbers should be unique over the system – Prevent issuing a right command to the wrong device 14 / 38 Mirko Damiani – [email protected] Sysfs attributes ● Camera parameters ● ● ● Exported as files in sysfs When a file is read or written, sysfs calls the appropriate show and store callbacks Sysfs ● Represents kernel objects ● Must be compiled with CONFIG_SYSFS ● mount -t sysfs sysfs /sys 15 / 38 Mirko Damiani – [email protected] Sysfs attributes ● ● No special programs needed for configuration ● echo to write ● cat to read ● Available choices can be shown Limitations ● Sysfs allocates a PAGE_SIZE buffer (e.g. 4K) and calls the methods only once ● No partial read and write operations ● Values must be simple – Avoid structured multi line values 16 / 38 Mirko Damiani – [email protected] Using camera attributes ● $> grep "" * ● ● modes:2592x1944,1296x972,864x648,648x486,432x324 resolution:2592x1944 window:0,0,2592,1944 framesize:5038848 exposure:500 gain:1000 running:0 $> echo 864x648 > resolution ● sh: write error: Device or resource busy ● We cannot change resolution when the camera is running 17 / 38 Mirko Damiani – [email protected] System call: mmap ● Usage ● ● ● void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) man mmap No copy of frames ● ● ● Buffers are shared between kernel space and user space User space have to handle a sort of lock/unlock or queue/dequeue on mmap'ed buffers Very hard to make it work 18 / 38 Mirko Damiani – [email protected] System call: read ● ● Usage ● ssize_t read(int fd, void *buf, size_t count) ● Simple and straightforward to use and implement A copy is required for every read frame ● copy_to_user ● Each frame is 4.8MB in size ● This might lead to performance issues... ● Anyway it is convenient to try the easy way first 19 / 38 Mirko Damiani – [email protected] Frame rate at full resolution ● $> dd if=/dev/cam0 of=/dev/null bs=5038848 count=1 ● ● 100 frames ● ● 1+0 records in 1+0 records out 5038848 bytes (4.8MB) copied, 0.387317 seconds, 12.4MB/s fps = 13.47 10000 frames ● fps = 13.95 16 14 12 10 fps 8 6 4 2 0 1 10 100 #frames Mirko Damiani – [email protected] 1000 10000 20 / 38 Driver details ● Data structure ● Continuous acquisition ● Interrupts ● Memory allocation ● Driver operations 21 / 38 Frames rotation ● We hold two list of frames ● Frames to be written with new data ● Frames that are ready to be read by user-space write-list prev next Frame A Frame B Frame C prev next prev next prev next read-list prev next 22 / 38 Mirko Damiani – [email protected] Frames rotation ● Frame completed ● Write data to the write-list head element ● Append the write-list head element to the tail of read-list write-list prev next read-list prev next Frame B Frame C prev next prev next Frame A prev next Mirko Damiani – [email protected] 23 / 38 Frames rotation ● Frame completed ● Check whether write-list is empty ● Take the read-list head write-list prev next read-list prev next Frame C prev next Frame A Frame B prev next prev next Mirko Damiani – [email protected] 24 / 38 Frames rotation ● Frame read by user space ● Append the read-list head element to the tail of write-list write-list prev next read-list prev next Frame C Frame A prev next prev next Frame B prev next Mirko Damiani – [email protected] 25 / 38 Copying to user takes time ● User pages might not be currently in memory ● Accessing the swap space ● Memory overcommit on Linux ● User space process is put to sleep write-list prev next Frame C Frame A prev next prev next read-list prev next frame-busy Frame B prev next 26 / 38 Mirko Damiani – [email protected] Interrupts ● At the middle of every frame ● Take an old buffer and discard its content ● Switch to the next capture buffer – ● Shadow / Event Latched registers At the end of every frame ● Make the current buffer available to the user ● Wake up the sleeping user space process Frame Sensor IRQ1 IRQ2 Mirko Damiani – [email protected] 27 / 38 Protect shared data ● ● Code that can not sleep ● There is not a user space process to be put to sleep ● Interrupt handler ● Mutexes cannot be used Spinlocks ● 2 states: locked / unlocked ● If the lock is available, code goes to the critical section... ● ...otherwise code waits in a tight loop 28 / 38 Mirko Damiani – [email protected] Request kernel memory ● We need a contiguous 5MB buffer in memory ● No more than 4MB ● Reserve the top of physical RAM – Kernel boot parameter: mem=112M – dma_declare_coherent_memory – dma_mark_declared_memory_occupied 0x00000000 0xC0000000 User space Kernel space 0GB 3GB 0xC0000000 112MB 0xFFFFFFFF 4GB 0xC8000000 16MB 0xC7000000 Mirko Damiani – [email protected] 29 / 38 Synchronous acquisition ● ● Camera doesn't run in continuous mode ● A frame is captured on request 16 ● Camera sensor must be triggered 14 ● One buffer only 12 ● One IRQ only 10 100 frames ● ● fps = 10.22 10000 frames ● fps = 10.55 fps 8 6 4 2 0 1 10 100 #frames Mirko Damiani – [email protected] 1000 10000 30 / 38 Compensation @ 50Hz ● Neon light is non-uniform during image acquisition ● Camera shutter must be synchronized ● Mains frequency is 50Hz in Europe 1 0.8 0.6 I(t) 0.4 0.2 0 0 0.01 0.02 0.03 0.04 0.05 0.06 t frame delay 31 / 38 Mirko Damiani – [email protected] Compensation @ 50Hz 32 / 38 Mirko Damiani – [email protected] Compensation @ 50Hz ● ● Camera shutter is continuously triggered ● Linux kernel high resolution timers 16 ● Average on 2 consecutive frames 14 100 frames ● ● 12 fps = 10.32 10000 frames ● fps = 10.52 10 fps 8 6 4 2 0 1 10 100 #frames Mirko Damiani – [email protected] 1000 10000 33 / 38 Driver operations: open ● Check whether the camera is not already open ● Check access mode ● Read-only ● Clear any previous acquired frames ● Configure board and camera sensor ● ● Resolution and window ● I2C registers Start acquiring ● Camera runs in continuous mode 34 / 38 Mirko Damiani – [email protected] Driver operations: read ● ● Take least recent frame from read-list ● Put user space process to sleep, if not available ● Lock the buffer Copy its content into the user space buffer ● ● Honor the “count” parameter of the read syscall Append the frame to the end of write-list ● Each read “consumes” one frame ● No partial reads 35 / 38 Mirko Damiani – [email protected] Driver operations: close ● Stop frames acquisition ● ● Halt camera sensor and DMA transfers Unregister the current user process ● Another process is now able to open the camera 36 / 38 Mirko Damiani – [email protected] Let's Talk office +39 055 3984627 e-mail / jabber [email protected] web www.develer.com License Creative Commons Attribution 3.0 Unported