Computer Science amp Engineering Department Arizona State University Tempe AZ 85287 Dr YannHang Lee yhleeasuedu 480 7277507 Device Model To support initializing all the drivers configured into the system ID: 756012
Download Presentation The PPT/PDF document "Zephyr Device Driver and Device Model" is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.
Slide1
Zephyr Device Driver and Device Model
Computer Science & Engineering Department
Arizona State University
Tempe, AZ 85287
Dr. Yann-Hang Lee
yhlee@asu.edu
(480) 727-7507Slide2
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 operationsmust 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() device_sync_call_init() device_sync_call_init()
1
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
;Slide3
Driver APIs
The runtime device
struct
per driver instanceDEVICE_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.2struct device {
struct device_config *config
;
void *
driver_api
;
void *driver_data; };
struct
device_config
{
char *name;
int
(*
init
)(
struct
device *device);
void *
config_info
;
};Slide4
Device Initialization – DEVICE_INIT()
defines a device object that is automatically configured by the kernel during system initialization
two static
struct __config##dev_name and __device_##dev_nameplace them in “.devconfig.init” and “init_ #level STRINGFFY(prio)” sectionsinvoke_sys_device_do_config_level() to call all device->init()3
#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 \
}Slide5
Driver Example: i2c_dw
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 functionsconfig_data and driver_data4static 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 */
};Slide6
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 functionopen-drain or open-collector
5Slide7
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.
6Slide8
Master-Transmitter to Slave-Receiver Data Transfer
In this, the transmission direction never changes. The set-up and transfer is straight-forward
7Slide9
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)
8Slide10
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:
9Slide11
Use of I2C Driver in Galileo Board
CONFIG_I2C_0=y in /zephyr/boards/
galileo
/galileo_defconfigI2C 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 nameWith DEVICE_INIT macro, the objects are placed in memory by the linker. 10
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;}