Download presentation
Presentation is loading. Please wait.
1
Zephyr Device Driver and Device Model
Computer Science & Engineering Department Arizona State University Tempe, AZ 85287 Dr. Yann-Hang Lee (480)
2
Device Model To support initializing all the drivers configured into the system The driver fills in the pointer to the structure containing the function pointers to its API functions during driver initialization. These structures are placed into the RAM section in initialization level order. To provide a generic type API for each type of driver (UART, SPI, I2C) can be used by fibers and tasks API calls may be blocked for synchronous IO operations must use proper mechanisms for blocking according to execution context, e.g., a nanokernel semaphore cannot be used when the context is a task. Synchronous calls API type device_sync_call_t inline functions device_sync_call_init() typedef struct { /** Nanokernel semaphore for fiber context */ struct nano_sem f_sem; #ifdef CONFIG_MICROKERNEL /* use microkernel semaphore */ struct _k_sem_struct _t_sem; ksem_t t_sem; enum device_sync_waiter waiter; bool device_ready;#endif } device_sync_call_t;
3
Driver APIs The runtime device struct per driver instance
DEVICE_INIT() create device object and set it up for boot time initialization. DEVICE_AND_API_INIT() Create device object and set it up for boot time initialization. This also takes a pointer to driver API struct for link time pointer assignment. DEVICE_NAME_GET() Expands to the full name of a global device object. DEVICE_GET() Obtain a pointer to a device object by name. DEVICE_DECLARE() Declare a device object. struct device { struct device_config *config; void *driver_api; void *driver_data; }; struct device_config { char *name; int (*init)(struct device *device); void *config_info; };
4
Device Initialization – DEVICE_INIT()
#define DEVICE_AND_API_INIT(dev_name, drv_name, init_fn, data, cfg_info, level, prio, api) \ \ static struct device_config __config_##dev_name __used \ __attribute__((__section__(".devconfig.init"))) = { \ .name = drv_name, \ .init = (init_fn), \ .config_info = (cfg_info) \ }; \ static struct device (__device_##dev_name) __used \ __attribute__((__section__(".init_" #level STRINGIFY(prio)))) = { \ .config = &(__config_##dev_name), \ .driver_api = api, \ .driver_data = data \ } defines a device object that is automatically configured by the kernel during system initialization two static struct __config##dev_name and __device_##dev_name place them in “.devconfig.init” and “init_ #level STRINGFFY(prio)” sections invoke_sys_device_do_config_level() to call all device->init()
5
Driver Example: i2c_dw initialization func – i2c_dw_initialize()
DEVICE_AND_API_INIT(i2c_0, CONFIG_I2C_DW_0_NAME, &i2c_dw_initialize, &i2c_0_runtime, &i2c_config_dw_0, SECONDARY, CONFIG_I2C_INIT_PRIORITY); initialization func – i2c_dw_initialize() driver API functions config_data and driver_data static struct i2c_driver_api funcs = { .configure = i2c_dw_runtime_configure, .transfer = i2c_dw_transfer, .suspend = i2c_dw_suspend, .resume = i2c_dw_resume, }; struct i2c_dw_dev_config { device_sync_call_t sync; union dev_config app_config; uint8_t *xfr_buf; uint32_t xfr_len; uint32_t rx_pending; uint16_t hcnt; uint16_t lcnt; volatile uint8_t state; /* last dir. of transfer */ uint8_t request_bytes; uint8_t xfr_flags; bool support_hs_mode; }; struct i2c_dw_rom_config { uint32_t base_address; uint32_t irq_num; uint32_t interrupt_mask; #ifdef CONFIG_PCI struct pci_dev_info pci_dev; #endif /* CONFIG_PCI */ i2c_isr_cb_t config_func; #ifdef CONFIG_I2C_DW_SHARED_IRQ char *shared_irq_dev_name; #endif /* CONFIG_I2C_DW_SHARED_IRQ */ };
6
Bit-Transfer on I2C Bus One clock pulse is generated for each data bit that is transferred Data Validity The data on the SDA line must be stable during the HIGH(1) period of the clock. The data line(SDA) can change data only when the clock signal (SCL) is LOW(0) Wired-and function open-drain or open-collector
7
Data Transfer With 7-Bit Device Address
After START condition (S), a slave address(7-bit) is sent. A read/write (R/W’) direction is then sent(8th bit) Data transfer occurs, and then always terminated by STOP condition. However, repeated START conditions can occur.
8
Master-Transmitter to Slave-Receiver Data Transfer
In this, the transmission direction never changes. The set-up and transfer is straight-forward
9
Master-Receiver and Slave-Transmitter Data Transfer
Master initiates the data transfer by generating the START condition followed by the start byte (with read/write bit set to 1 i.e. read mode) After the first ack from the slave, the direction of data changes and the master becomes receiver and slave transmitter. The STOP condition is still generated by the master (master sends not-ACK before generating the STOP)
10
Example I2C Device – 24FC256 EEPROM
32K bytes in 512 pages of 64 bytes I2C interface with A2, A1, A0 address pins Page write operation: Random read operation:
11
Use of I2C Driver in Galileo Board
CONFIG_I2C_0=y in /zephyr/boards/galileo/galileo_defconfig I2C interface wrapper in /zephyr/include/i2c.h static int i2c_transfer(struct device *dev, struct i2c_msg *msgs, uint8_t num_msgs, uint16_t addr) Need to find the “struct device” Search the device objects by configuration name With DEVICE_INIT macro, the objects are placed in memory by the linker. struct device *device_get_binding(char *name) { struct device *info; for (info = __device_init_start; info != __device_init_end; info++) { if (!strcmp(name, info->config->name)) { return info; } } return NULL;
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.