590 likes | 604 Views
Nov. 24 , 2015 Kyu Ho Park. Lecture 11 Time Handling,GPIO and I/O Systems. 1. Time Management. Representing time in UNIX and LINUX: It is represented in seconds before or after the epoch January 1,1970 UTC(Universal Coordinated Time).
E N D
Nov. 24, 2015 Kyu Ho Park Lecture 11 Time Handling,GPIO and I/O Systems 1
TimeManagement • Representing time in UNIX and LINUX: It is represented in seconds before or after the epoch January 1,1970 UTC(Universal Coordinated Time). UTC is sometimes improperly referred to as UCT. • System call time(): #include <time.h> time_t time(time_t *t); /*time() returns the number in seconds since the epoch. It fills in t with the number of seconds since the epoch. */ • struct tm struct tm{ int tm_sec; int tm_min; int tm_hour; int tm_mday; /*day of month*/ int tm_mon; … }
gettimeofday( ) #include <sys/time.h> #include <unistd.h> int gettimeofday(struct timeval *tv, struct timezone *tz); struct timeval{ int tv_sec; /* seconds*/ int tv_usec;/*microseconds*/ }; struct timezone{ int tz_minuteswest;/*minutes west of Greenwich*/ int tz_dsttime; /type of dst(daylight saving time) correction*/ }
stime() #include <time.h> int stime( const time_t *tp); /* tp; UTC time to set return value: 0 normal, -1 error */
sleeping unsigned int sleep(unsigned int sec); void usleep(unsigned long usec); int nanosleep(struct timespec *req, struct timespec *rem); /* it causes the current process to sleep the amount of time specified in req, unless a signal is received by the process. if nanosleep()terminates due to a received signal,and if rem is not NULL, set rem to represent the amount of time remaining in the sleep peroid. */ struct timespec{ long int tv_sec; long int tv_nsec; }
interval timer • Interval timer delivers signals to a process on a regular period. #intclude <sys/time.h> int setitimer(int which, const struct itimerval *value, struct itimerval *oldvalue); , where which: one of {ITIMER_REAL, ITIMER_VIRTUAL,ITIMER_PROF}, value: value for time interval. struct itimerval { struct timeval it_interval; /* next value*/ struct timeval it_value; /* current value */ }; struct timeval { long tv_sec; /* seconds*/ longtv_usec; /* microseconds */ };
Three timers • ITIMER_REAL: It tracks time in terms of the clock on the wall, that is, real time and delivers a SIGALRM signal when the given time interval elapses. • ITIMER_VIRTUAL: It counts time only when the process is executing at user mode, excluding any system calls the process makes and delivers a SIGVTALRM. • ITIMER_PROF: It counts execution time of the process including at user mode and kernel mode.
example void stop_timer (pid_t child) { kill (child, SIGTERM); } int main (int argc, const char **argv) { pid_t timer = 0; printf(“Demonstrating itimers for 10 seconds, ” “please wait...\n”); timer = start_timer(1); sleep(10); stop_timer(timer); printf(“Done.\n”); return 0; } /* itimer.c */ #include <stdio.h> #include <stdlib.h> #include <sys/wait.h> #include <unistd.h> #include <string.h> #include <signal.h> #include <sys/time.h> void catch_signal (int ignored) { static int iteration=0; printf(“caught interval timer signal, iteration %d\n”, iteration++); } pid_t start_timer (int interval) { pid_t child: struct itimerval it; struct sigaction sa; if (!(child = fork())) { memset (&sa, 0, sizeof (sa)); sa.sa_handler = catch_signal; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sigaction(SIGALRM, &sa, NULL); memset(&it, 0, sizeof(it)); it.it_interval.tv_sec = interval; it.it_value.tv_sec = interval; setitimet(ITIMER_REAL, &it, NULL); while (1) pause(); } return child; }
HZ The Tick Rate: HZ The frequency of the system timer (the tick rate) is programmed on system boot based on a static preprocessor define, HZ. The value of HZ differs for each supported architecture. In fact, on some supported architectures, it even differs between machine types. The kernel defines the value in <asm/param.h>. The tick rate has a frequency of HZ hertz and a period of 1/HZ seconds. For example, in include/asm-i386/param.h, the i386 architecture defines: #define HZ 1000 /* internal kernel time frequency */ HZ : Number of timer interrupt per second, if HZ=1000 , every 1ms the timer interrupt occurs. tick : 1/HZ
jiffies • Global variable jiffies defined at <linux/jiffies.h> • jiffies_64 : Every time a timer interrupt occurs, the internal kernel counter is incremented. The counter is a 64-bit variable and is called jiffies_64. At system boot, it is initialized to 0. • 1 jiffy is 1 tick(=1/HZ sec) • in case of 32_bit jiffies, it will be overflowed after 49.7 days when HZ=1000. • in case of jiffies_64, no overflow during the whole life of a user.
Kernel Timer • kernel timer structure: struct timer_list #include <linux/timer.h> struct timer_list{ struct list_head entry; unsigned long expires; /* time of expiration in jiffy */ spinlock_t lock; void (*function)(unsigned long); /* timer handler */ unsigned long data; /* passed as the argument to function function is called*/ struct tvec_t_base_s *base; /*for internal use */ }
init_timer(), add_timer(), and del_timer() • init_timer() : Initialize the kernel timer struct. • add_timer(): Add the kernel timer to the kernel( timer_list at THE KERNEL). • del_kernel: Remove the added kernel timer from the timer_list at the kernel. The return value is 1 if successful, 0 otherwise.
Example of Kernel Timer char m_data[128]; struct timer_list kerneltimer; void init_timer(struct timer_list *kerneltimer); void kerneltimer_handler(unsigned long arg){ … } led_timer_init( …){ .. init_timer(&kerneltimer); timer_expires = get_jiffies_64() + (5*HZ/10);/* 0.5 sec later, the timer expires */ timer.data = (unsigned long) &m_data[0]; timer.function=kerneltimer_handler; add_timer(&kerneltimer); } led_timer_exit(void){ …. del_timer(&kerneltimer); }
GPIO Reference: Linux/Documenttion/gpio.txt
GPIO Characteristics • GPIO: General Purpose Input/Output. • Characteristics • Output values are writable( high=1, low=0). • Input values are readable(1,0). • Inputs can open be used as IRQ signals. • A GPIO can be configured as either input or output. • Most GPIOs can be accesses while holding spinlocks.
GPIO functions #include <linux/gpio.h> int gpio_is_valid(int number);/* to test whether the gpio number is valid */ To set the direction as input or output, int gpio_direction_input(unsigned gpio); int gpio_direction_output(unsigned gpio, int value); To get or set a value, int gpio_get_value(unsigned gpio); void gpio_set_value(unsigned gpio, int value);
GPIO functions #include <linux/gpio.h> int gpio_request(unsigned gpio, const char *label); /*request gpio, returning 0 or negative errno. non-null labels ,which is a string that can later appear in sysfs, may be useful for diagnosis. */ void gpio_free(unsigned gpio); /* release previously claimed gpio */
GPIO functions #include <linux/gpio.h> int gpio_to_irq(unsigned gpio); /* map gpio numbers to IRQ numbers */
registering and freeing the interrupt handler int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev); void free_irq(unsigned int, void *);
button_isr int led_state=0; static irqreturn_t button_isr(int irq, void *dev_id, struct pt_regs *regs) { gpio_set_value(149 /* gpio # */, led_state /* 0 or 1 */); gpio_set_value(150 /* gpio # */, (led_state = (led_state>0)?0:1) /* 0 or 1 */); return IRQ_HANDLED; }
How to get button_irq static struct gpio led_gpios[] = { {149, GPIOF_OUT_INIT_LOW, "USER LED 0" }, {150, GPIOF_OUT_INIT_LOW, "USER LED 1" }, }; static int button_gpio= 4; /* USER BUTTON */ static unsigned int button_irq; ….. static void led_button_init () { ….. ret = gpio_request_one(button_gpio, GPIOF_IN, "LED status change button"); if(ret < 0) { printk(KERN_ERR "failed to request GPIO %d, error %d\n", button_gpio, ret); goto error; } ret = gpio_direction_input(button_gpio); if(ret < 0) { target_gpio = button_gpio; goto error_conf; } // change button input to IRQ button_irq = gpio_to_irq(button_gpio); …… }
led_button_exit( ) module static void led_button_exit() { gpio_free(button_gpio); gpio_free_array(led_gpios, ARRAY_SIZE(led_gpios)); free_irq(button_irq, NULL); printk(KERN_ERR "Clearing ISR test setting completed.\n"); }
1 Principles of I/O hardware 2 Principles of I/O software 3 I/O software layers 4 Clocks Input/Output [Tanenbaum]
I/O Devices • Two categories: • Block devices and Character devices • Block devices: that store information in fixed-size blocks, each one with its own address. • Character devices: A character device delivers or accepts a stream of a characters without regard to any block structure. It is not addressable and does not have any seek operation.
I/O Devices • Some devices just do not fit in. • Clocks: • Not block addressable • Nor do they generate or accept character streams • All they do is cause interrupts at well-defined intervals • Memory-mapped screens:
Device Controllers • I/O devices have components: • mechanical component • electronic component • The electronic component is the device controller • may be able to handle multiple devices • Controller's tasks • convert serial bit stream to block of bytes • perform error correction as necessary • make available to main memory
Memory-Mapped I/O (1) • Separate I/O and memory space • Memory-mapped I/O • Hybrid
Memory-Mapped I/O (2) (a) A single-bus architecture (b) A dual-bus memory architecture
Direct Memory Access (DMA) Operation of a DMA transfer
Interrupts Revisited How interrupts happens. Connections between devices and interrupt controller actually use interrupt lines on the bus rather than dedicated wires
Principles of I/O SoftwareGoals of I/O Software (1) • Device independence • programs can access any I/O device • without specifying device in advance • (floppy, hard drive, or CD-ROM) • Uniform naming • name of a file or device a string or an integer • not depending on which machine • Error handling • handle as close to the hardware as possible
Goals of I/O Software (2) • Synchronous vs. asynchronous transfers • blocked transfers vs. interrupt-driven • Buffering • data coming off a device cannot be stored in final destination • Sharable vs. dedicated devices • disks are sharable • tape drives would not be
Programmed I/O (1) Steps in printing a string
Programmed I/O (2) Writing a string to the printer using programmed I/O
I/O Software Layers Layers of the I/O Software System
Device Drivers • Logical position of device drivers is shown here • Communications between drivers and device controllers goes over the bus
Device-Independent I/O Software (1) Functions of the device-independent I/O software
Device-Independent I/O Software (2) (a) Without a standard driver interface (b) With a standard driver interface
Device-Independent I/O Software (3) (a) Unbuffered input (b) Buffering in user space (c) Buffering in the kernel followed by copying to user space (d) Double buffering in the kernel
Device-Independent I/O Software (4) Networking may involve many copies
User-Space I/O Software Layers of the I/O system and the main functions of each layer
Linux Device files • Device file • Deviceaccess path is provided by the device node. • Major Number: device type, Minor Number: the device instance • Major number : • 0 ~ 255 • Include/linux/major.h • # mknod /dev/DUMMY_DEVICE c 254 0