Documentation: migrate the rest of drivers readmes
This commit is contained in:
parent
d98ae9d3e4
commit
443e900188
@ -44,3 +44,100 @@ Block device drivers have these properties:
|
|||||||
Can be used to set up a block of memory or (read-only) FLASH as
|
Can be used to set up a block of memory or (read-only) FLASH as
|
||||||
a block driver that can be mounted as a file system. See
|
a block driver that can be mounted as a file system. See
|
||||||
include/nuttx/drivers/ramdisk.h.
|
include/nuttx/drivers/ramdisk.h.
|
||||||
|
|
||||||
|
EEPROM
|
||||||
|
======
|
||||||
|
|
||||||
|
EEPROMs are a form of Memory
|
||||||
|
Technology Device (MTD). EEPROMs are non-volatile memory like FLASH, but
|
||||||
|
differ in underlying memory technology and differ in usage in many respects:
|
||||||
|
They may not be organized into blocks (at least from the standpoint of the
|
||||||
|
user) and it is not necessary to erase the EEPROM memory before re-writing
|
||||||
|
it. In addition, EEPROMs tend to be much smaller than FLASH parts, usually
|
||||||
|
only a few kilobytes vs megabytes for FLASH. EEPROM tends to be used to
|
||||||
|
retain a small amount of device configuration information; FLASH tends
|
||||||
|
to be used for program or massive data storage. For these reasons, it may
|
||||||
|
not be convenient to use the more complex MTD interface but instead use
|
||||||
|
the simple character interface provided by the EEPROM drivers.
|
||||||
|
|
||||||
|
EEPROM Device Support
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
drivers/eeprom/spi_xx25xx.c
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
This is a driver for SPI EEPROMs that use the same commands as the
|
||||||
|
25AA160::
|
||||||
|
|
||||||
|
Manufacturer Device Bytes PgSize AddrLen
|
||||||
|
Microchip
|
||||||
|
25xx010A 128 16 1
|
||||||
|
25xx020A 256 16 1
|
||||||
|
25AA02UID 256 16 1
|
||||||
|
25AA02E48 256 16 1
|
||||||
|
25AA02E64 256 16 1
|
||||||
|
25xx040 512 16 1+bit
|
||||||
|
25xx040A 512 16 1+bit
|
||||||
|
25xx080 1024 16 1
|
||||||
|
25xx080A 1024 16 2
|
||||||
|
25xx080B 1024 32 2
|
||||||
|
25xx080C 1024 16 x
|
||||||
|
25xx080D 1024 32 x
|
||||||
|
25xx160 2048 16 2
|
||||||
|
25xx160A/C 2048 16 2 TESTED
|
||||||
|
25xx160B/D 2048 32 2
|
||||||
|
25xx160C 2048 16 2
|
||||||
|
25xx160D 2048 32 2
|
||||||
|
25xx320 4096 32 2
|
||||||
|
25xx320A 4096 32 2
|
||||||
|
25xx640 8192 32 2
|
||||||
|
25xx640A 8192 32 2
|
||||||
|
25xx128 16384 64 2
|
||||||
|
25xx256 32768 64 2
|
||||||
|
25xx512 65536 128 2
|
||||||
|
25xx1024 131072 256 3
|
||||||
|
Atmel
|
||||||
|
AT25010B 128 8 1
|
||||||
|
AT25020B 256 8 1
|
||||||
|
AT25040B 512 8 1+bit
|
||||||
|
AT25080B 1024 32 2
|
||||||
|
AT25160B 2048 32 2
|
||||||
|
AT25320B 4096 32 2
|
||||||
|
AT25640B 8192 32 2
|
||||||
|
AT25128B 16384 64 2
|
||||||
|
AT25256B 32768 64 2
|
||||||
|
AT25512 65536 128 2
|
||||||
|
AT25M01 131072 256 3
|
||||||
|
|
||||||
|
drivers/mtd/at24xx.c
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
This is a driver for I2C-based at24cxx EEPROM (at24c32, at24c64, at24c128,
|
||||||
|
at24c256, at24c512). This driver is currently provided as an MTD driver
|
||||||
|
but could easily be modified to support the character driver interface.
|
||||||
|
|
||||||
|
File Systems
|
||||||
|
------------
|
||||||
|
|
||||||
|
Most EEPROM parts are too small to be candidates for use with a file
|
||||||
|
system. The character driver interface is optimal for these small parts
|
||||||
|
because you can open and access the EEPROM part as if it were a single,
|
||||||
|
fixed size file.
|
||||||
|
|
||||||
|
It is also possible to use these character drivers with a file system.
|
||||||
|
The character driver can converted to a block device using the NuttX loop
|
||||||
|
device. The loop device can be found the file drivers/loop.c. Interface
|
||||||
|
function prototypes can be found in include/nuttx/fs/fs.h::
|
||||||
|
|
||||||
|
int losetup(FAR const char *devname, FAR const char *filename,
|
||||||
|
uint16_t sectsize, off_t offset, bool readonly);
|
||||||
|
|
||||||
|
Given a file or character devices at 'filename', losetup will create the
|
||||||
|
block device 'devname' using a bogus sector size of sectsize. 'offset' is
|
||||||
|
normally zero but can be used to provide an offset into the EEPROM where
|
||||||
|
the block driver data starts; The EEPROM block driver can also be read-
|
||||||
|
only.
|
||||||
|
|
||||||
|
There is a corresponding function that will destroy the loop device::
|
||||||
|
|
||||||
|
int loteardown(FAR const char *devname);
|
||||||
|
@ -35,3 +35,5 @@ following section.
|
|||||||
usbdev.rst
|
usbdev.rst
|
||||||
rwbuffer.rst
|
rwbuffer.rst
|
||||||
regmap.rst
|
regmap.rst
|
||||||
|
sensors.rst
|
||||||
|
video.rst
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
.. note:: See also the usage of the LCD driver in the graphics/ directory.
|
||||||
|
|
||||||
=====================
|
=====================
|
||||||
LCD Character Drivers
|
LCD Character Drivers
|
||||||
=====================
|
=====================
|
||||||
@ -52,6 +54,96 @@ details on how an LCD screen is bound to an LCD character driver.
|
|||||||
* ``include/nuttx/lcd/lcd.h`` provides structures and APIs needed to work
|
* ``include/nuttx/lcd/lcd.h`` provides structures and APIs needed to work
|
||||||
with LCD screens, whether using the framebuffer adapter or the :doc:`lcd`;
|
with LCD screens, whether using the framebuffer adapter or the :doc:`lcd`;
|
||||||
|
|
||||||
|
Supported devices
|
||||||
|
=================
|
||||||
|
|
||||||
|
Re-usable LCD drivers reside in the drivers/lcd directory:
|
||||||
|
|
||||||
|
LCDs
|
||||||
|
----
|
||||||
|
|
||||||
|
- ``mio283qt2.c``
|
||||||
|
|
||||||
|
This is a driver for the MI0283QT-2 LCD from Multi-Inno
|
||||||
|
Technology Co., Ltd. This LCD is based on the Himax HX8347-D LCD
|
||||||
|
controller.
|
||||||
|
|
||||||
|
- ``mio283qt9a.c``
|
||||||
|
|
||||||
|
This is a driver for the MI0283QT-9A LCD from Multi-Inno
|
||||||
|
Technology Co., Ltd. This LCD is based on the Ilitek ILI9341 LCD
|
||||||
|
controller.
|
||||||
|
|
||||||
|
- ``ssd12989.c``
|
||||||
|
|
||||||
|
Generic LCD driver for LCDs based on the Solomon Systech
|
||||||
|
SSD1289 LCD controller. Think of this as a template for an LCD driver
|
||||||
|
that you will probably have to customize for any particular LCD
|
||||||
|
hardware. (See also boards/arm/stm32/hymini-stm32v/src/ssd1289.c below).
|
||||||
|
|
||||||
|
- ``st7567.c``
|
||||||
|
|
||||||
|
LCD Display Module, ST7567, Univision Technology Inc.
|
||||||
|
Used with the LPCXpresso and Embedded Artists base board.
|
||||||
|
|
||||||
|
- ``memlcd.c``
|
||||||
|
|
||||||
|
Sharp Memory LCD Suite, LS013B7DH01, LS013B7DH03, etc.
|
||||||
|
There are some more different models, they are basically controlled
|
||||||
|
by similar logics, thus this driver can be extended.
|
||||||
|
|
||||||
|
- ``ra8875.c``
|
||||||
|
|
||||||
|
RAiO Technologies RA8875 LCD controller. Contributed by Marten Svanfeldt.
|
||||||
|
|
||||||
|
OLEDs
|
||||||
|
-----
|
||||||
|
|
||||||
|
- ``p14201.c``
|
||||||
|
|
||||||
|
Driver for RiT P14201 series display with SD1329 IC controller.
|
||||||
|
Based on the SD1329 controller. This OLED is used with
|
||||||
|
older versions of the TI/Luminary LM3S8962 Evaluation Kit. Example
|
||||||
|
usage::
|
||||||
|
|
||||||
|
boards/arm/tiva/lm3s6965-ek/src
|
||||||
|
boards/arm/tiva/lm3s8962-ek/src
|
||||||
|
|
||||||
|
- ``ug-2864ambag01.c``
|
||||||
|
|
||||||
|
OLED Display Module, UUG-2864AMBAG01, Univision Technology Inc.
|
||||||
|
Based on the SH1101A controller. Example usage::
|
||||||
|
|
||||||
|
boards/arm/stm32/stm32f4discovery
|
||||||
|
boards/arm/lpc214x/zp214xpa
|
||||||
|
|
||||||
|
- ``ug-9664hswag01.c``
|
||||||
|
|
||||||
|
OLED Display Module, UG-9664HSWAG01, Univision Technology Inc.
|
||||||
|
Based on the SSD1305 controller. Used with the
|
||||||
|
LPC Xpresso and Embedded Artists base board. Example usage::
|
||||||
|
|
||||||
|
boards/arm/lpc71xx_40xx/lpcxpresso-lpc1768
|
||||||
|
|
||||||
|
- ``ssd1306.c``
|
||||||
|
|
||||||
|
OLED Display Modules based on the SSD1306 controllers.
|
||||||
|
This includes the UG-2864HSWEG01 and UG2832HSWEG04, both from Univision
|
||||||
|
Technology Inc. The latter is used with the OLED1 module that comes
|
||||||
|
with the Atmel SAM4l Xplained Pro board. This driver also supports
|
||||||
|
Densitron Technologies DD-12864WO-4A which is based on SSD1309 LCD
|
||||||
|
controller. Example usage::
|
||||||
|
|
||||||
|
boards/arm/stm32/stm32f4discovery
|
||||||
|
boards/arm/sam34/sam4l-xplained
|
||||||
|
|
||||||
|
Segment LCDS (SLCDs)
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
- ``pcf8574_lcd_backpack.c``
|
||||||
|
|
||||||
|
See pcf8574_lcd_backpack_readme.txt.
|
||||||
|
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
========
|
========
|
||||||
@ -132,3 +224,82 @@ built with the LCD character interface.
|
|||||||
* The LVGL demo application (``lvgldemo``) makes use of the ``ioctl`` system
|
* The LVGL demo application (``lvgldemo``) makes use of the ``ioctl`` system
|
||||||
call to trigger an ``LCDDEVIO_PUTAREA`` request to the higher-level device
|
call to trigger an ``LCDDEVIO_PUTAREA`` request to the higher-level device
|
||||||
driver to refresh the LCD screen with data as usual;
|
driver to refresh the LCD screen with data as usual;
|
||||||
|
|
||||||
|
LCD Header files
|
||||||
|
================
|
||||||
|
|
||||||
|
``include/nuttx/lcd/lcd.h``
|
||||||
|
|
||||||
|
Structures and APIs needed to work with LCD drivers are provided in
|
||||||
|
this header file. This header file also depends on some of the same
|
||||||
|
definitions used for the frame buffer driver as provided in
|
||||||
|
include/nuttx/video/fb.h.
|
||||||
|
|
||||||
|
``struct lcd_dev_s``
|
||||||
|
|
||||||
|
Each LCD device driver must implement an instance of struct lcd_dev_s.
|
||||||
|
That structure defines a call table with the following methods:
|
||||||
|
|
||||||
|
- Get information about the LCD video controller configuration and the
|
||||||
|
configuration of each LCD color plane.
|
||||||
|
|
||||||
|
.. code-block:: C
|
||||||
|
|
||||||
|
int (*getvideoinfo)(FAR struct lcd_dev_s *dev,
|
||||||
|
FAR struct fb_videoinfo_s *vinfo);
|
||||||
|
int (*getplaneinfo)(FAR struct lcd_dev_s *dev, unsigned int planeno,
|
||||||
|
FAR struct lcd_planeinfo_s *pinfo);
|
||||||
|
|
||||||
|
|
||||||
|
- The following are provided only if the video hardware supports RGB
|
||||||
|
color mapping:
|
||||||
|
|
||||||
|
.. code-block:: C
|
||||||
|
|
||||||
|
int (*getcmap)(FAR struct lcd_dev_s *dev,
|
||||||
|
FAR struct fb_cmap_s *cmap);
|
||||||
|
int (*putcmap)(FAR struct lcd_dev_s *dev,
|
||||||
|
FAR const struct fb_cmap_s *cmap);
|
||||||
|
|
||||||
|
|
||||||
|
- The following are provided only if the video hardware supports a
|
||||||
|
hardware cursor:
|
||||||
|
|
||||||
|
.. code-block:: C
|
||||||
|
|
||||||
|
int (*getcursor)(FAR struct lcd_dev_s *dev,
|
||||||
|
FAR struct fb_cursorattrib_s *attrib);
|
||||||
|
int (*setcursor)(FAR struct lcd_dev_s *dev,
|
||||||
|
FAR struct fb_setcursor_s *settings);
|
||||||
|
|
||||||
|
|
||||||
|
- Get the LCD panel power status (0: full off - CONFIG_LCD_MAXPOWER:
|
||||||
|
full on). On backlit LCDs, this setting may correspond to the
|
||||||
|
backlight setting:
|
||||||
|
|
||||||
|
.. code-block:: C
|
||||||
|
|
||||||
|
int (*getpower)(struct lcd_dev_s *dev);
|
||||||
|
|
||||||
|
|
||||||
|
- Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER:
|
||||||
|
full on). On backlit LCDs, this setting may correspond to the
|
||||||
|
backlight setting:
|
||||||
|
|
||||||
|
.. code-block:: C
|
||||||
|
|
||||||
|
int (*setpower)(struct lcd_dev_s *dev, int power);
|
||||||
|
|
||||||
|
|
||||||
|
- Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST):
|
||||||
|
|
||||||
|
.. code-block:: C
|
||||||
|
|
||||||
|
int (*getcontrast)(struct lcd_dev_s *dev);
|
||||||
|
|
||||||
|
|
||||||
|
- Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST):
|
||||||
|
|
||||||
|
.. code-block:: C
|
||||||
|
|
||||||
|
int (*setcontrast)(struct lcd_dev_s *dev, unsigned int contrast);
|
||||||
|
496
Documentation/components/drivers/special/sensors.rst
Normal file
496
Documentation/components/drivers/special/sensors.rst
Normal file
@ -0,0 +1,496 @@
|
|||||||
|
.. warning:: this list is incomplete. See drivers/sensors for ar full list of
|
||||||
|
supported sensors
|
||||||
|
|
||||||
|
==============
|
||||||
|
Sensor Drivers
|
||||||
|
==============
|
||||||
|
|
||||||
|
ADXL345
|
||||||
|
=======
|
||||||
|
|
||||||
|
Contributed by Alan Carvalho de Assis
|
||||||
|
|
||||||
|
The ADXL345 accelerometer can operate in I2C or SPI mode. To operate in I2C
|
||||||
|
mode just connect the CS pin to Vddi/o.
|
||||||
|
|
||||||
|
In order to operate in SPI mode CS need to use connected to microcontroller,
|
||||||
|
it cannot leave unconnected.
|
||||||
|
|
||||||
|
In SPI mode it works with clock polarity (CPOL) = 1 and clock phase (CPHA)
|
||||||
|
= 1.
|
||||||
|
|
||||||
|
ADXL372
|
||||||
|
=======
|
||||||
|
|
||||||
|
Contributed by Bob Feretich
|
||||||
|
|
||||||
|
The ADXL372 is a 200g tri-axis accelerometer that is capable of detecting
|
||||||
|
and recording shock impact impact events. Recording trigger
|
||||||
|
characteristics are programmed into the sensor via multiple threshold and
|
||||||
|
duration registers. The ADXL372 is a SPI only device that can transfer
|
||||||
|
data at 10 MHz. The data transfer performance of this part permits the
|
||||||
|
sensor to be sampled "on demand" rather than periodically sampled by a
|
||||||
|
worker task.
|
||||||
|
|
||||||
|
See the description of the "Common Sensor Register Interface" below for more
|
||||||
|
details. It also implements the "Sensor Cluster Driver Interface".
|
||||||
|
|
||||||
|
LSM330_SPI
|
||||||
|
==========
|
||||||
|
|
||||||
|
Contributed by Bob Feretich
|
||||||
|
|
||||||
|
The LSM330 consists of a multi-range tri-axis accelerometer and a
|
||||||
|
multi-range tri-axis gyroscope. The tri-axis accelerometer features two
|
||||||
|
state machines that can be firmware programmed for event detection. The
|
||||||
|
tri-axis gyroscope features threshold and duration registers for event
|
||||||
|
detection.
|
||||||
|
|
||||||
|
This driver supports the LSM330 in SPI mode. In this mode, the LSM330
|
||||||
|
that can transfer data at 10 MHz. The data transfer performance of
|
||||||
|
this part permits the sensor to be sampled "on demand" rather than
|
||||||
|
periodically sampled by a worker task. See the description of the "Common
|
||||||
|
Sensor Register Interface" below for more details. It also implements the
|
||||||
|
"Sensor Cluster Driver Interface".
|
||||||
|
|
||||||
|
MPL115A
|
||||||
|
=======
|
||||||
|
|
||||||
|
Contributed by Alan Carvalho de Assis
|
||||||
|
|
||||||
|
This driver has support only for MPL115A1 (SPI), but support to MPL115A2
|
||||||
|
(I2C) can be added easily.
|
||||||
|
|
||||||
|
Common Sensor Register Interface
|
||||||
|
================================
|
||||||
|
|
||||||
|
Contributed by Bob Feretich
|
||||||
|
|
||||||
|
Background and problem statement:
|
||||||
|
|
||||||
|
The capabilities and performance of modern sensors have grown tremendously.
|
||||||
|
Most sensors are now capable of some degree of autonomous behavior and
|
||||||
|
several permit the user to load firmware into them and perform as
|
||||||
|
nanocontrollers. Other sensors have very sophisticated built-in digital
|
||||||
|
filters that can be programmed with hundreds of parameters.
|
||||||
|
|
||||||
|
Currently most sensor drivers in the NuttX drivers/sensors
|
||||||
|
directory implement file_ops open(), close(), and read() functions.
|
||||||
|
The open() function initializes the sensor and places it in a mode where
|
||||||
|
it can transfer live data in a default configuration. The close() function
|
||||||
|
places the sensor in a low power shutdown mode. The read() function
|
||||||
|
returns the most recent data sample from the sensor's most used data
|
||||||
|
output registers. The write() function is rarely implemented and when it
|
||||||
|
is there is no consistency in its use. The lseek() and poll() functions
|
||||||
|
seem to be completely ignored. This results in the sensors being operated
|
||||||
|
in only their most primitive modes using a fixed "default configuration".
|
||||||
|
|
||||||
|
To work around this problem sensor drivers have implemented ioctl()
|
||||||
|
functions to perform configuration, program the sensor, and manage
|
||||||
|
autonomous activity. Ioctls provide a method where user programs can
|
||||||
|
tunnel through a high level driver to access and control device specific
|
||||||
|
features. The problem with using ioctls is that before the ioctl interface
|
||||||
|
can be used, the sensor driver must be opened; and the open() function
|
||||||
|
causes the driver to start performing these primitive actions, so before
|
||||||
|
ioctls can manage the drivers as desired, ioctls must first be used to
|
||||||
|
undo the generic actions caused by the open() function. Another major
|
||||||
|
issue is that there is no consistency from sensor to sensor on ioctl
|
||||||
|
definitions, not even for the most common sensor actions like writing a
|
||||||
|
sensor control register or reading a sensor status register.
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
|
||||||
|
The purpose of the "Common Sensor Register Interface" is to implement a
|
||||||
|
consistent and more useful definition of file_ops interface and to make the
|
||||||
|
file_ops open() function more flexible in establishing the initial
|
||||||
|
operational state of the sensor. Compatibility for user applications that
|
||||||
|
implement the current open(), close(), read() interface will be
|
||||||
|
maintained; and the much greater capabilities of modern sensors will
|
||||||
|
become accessible through this interface.
|
||||||
|
|
||||||
|
Scope:
|
||||||
|
|
||||||
|
Applicable to I2C and SPI attached sensors, and some serial port attached
|
||||||
|
sensors.
|
||||||
|
|
||||||
|
The file_ops interface definition:
|
||||||
|
|
||||||
|
open(): This function performs the below actions...
|
||||||
|
|
||||||
|
1) Reads the sensors ID register. If the sensor responds with an
|
||||||
|
unexpected value, then...
|
||||||
|
|
||||||
|
a) The driver's write() function is disabled.
|
||||||
|
b) The open function initializes the driver instance, so
|
||||||
|
that read() and lseek() operations may be performed to enable
|
||||||
|
problem diagnoses, but the sensor hardware is not initialized.
|
||||||
|
(No write operations are performed to the sensor.)
|
||||||
|
c) The errno global variable is set to positive ENODEV
|
||||||
|
("No such device").
|
||||||
|
d) The open() function returns successfully with a file_handle.
|
||||||
|
Note that the calling routine should clear errno before
|
||||||
|
calling open(). (The file_ops rules prevent drivers from
|
||||||
|
setting errno to zero.)
|
||||||
|
|
||||||
|
2) The other file_ops functions are enabled.
|
||||||
|
3) The driver's "current reg address" state variable is set to the
|
||||||
|
sensor's first sensor data output register. (This will make
|
||||||
|
calls to read() return live sensor data and maintain compatibility
|
||||||
|
with existing user programs.)
|
||||||
|
4) If the driver supports a default worker task and an interrupt
|
||||||
|
handler is specified by in the sensor configuration structure, then
|
||||||
|
the default worker task is bound to the default worker task.
|
||||||
|
5) The sensor configuration structure (that was provided to the driver
|
||||||
|
registration function) is examined to determine whether a custom
|
||||||
|
sensor configuration is specified. (The custom configuration is
|
||||||
|
basically an array of (device_reg_address, value) pairs that are
|
||||||
|
written to the sensor via "single register write" operations.
|
||||||
|
If a custom sensor configuration was specified, then that
|
||||||
|
configuration is written to the sensor, otherwise the "default
|
||||||
|
sensor configuration" is written to the sensor.
|
||||||
|
(A side effect of writing this data may result in interrupts
|
||||||
|
occurring and data being transferred to/from the worker task.)
|
||||||
|
6) The open() function returns successfully with a file_handle.
|
||||||
|
|
||||||
|
``close()``: This function stops sensor activity and places it in a low
|
||||||
|
power mode. The file_ops interface functions are disabled for this
|
||||||
|
instance of the sensor driver. (Except for open())
|
||||||
|
|
||||||
|
``read()``: The action of this function is dependent on whether a "default
|
||||||
|
worker task" is running and the value of the driver's "current reg
|
||||||
|
address" state variable.
|
||||||
|
|
||||||
|
If a "default worker task" is running,
|
||||||
|
|
||||||
|
AND the driver's "current reg address" is equal to the value of
|
||||||
|
the first sensor data output register,
|
||||||
|
AND the number of bytes to be read is less than or equal to the
|
||||||
|
number of bytes in a "default worker task" sample,
|
||||||
|
|
||||||
|
Then data is copied from the "default worker task's" sample memory to
|
||||||
|
the caller's provided buffer.
|
||||||
|
|
||||||
|
Otherwise, this function transfers data from sensor registers to the
|
||||||
|
data buffer provided by the caller. The first byte read is from the
|
||||||
|
sensor register address specified by the sensor's "current reg
|
||||||
|
address". The addresses of subsequent bytes to be read are context
|
||||||
|
sensitive. If more than bus transfer is needed to complete the read,
|
||||||
|
then a "multi-byte" (sometimes called "burst mode") data transfer
|
||||||
|
will be used to fill the buffer.
|
||||||
|
See the sensor's datasheet to determine the auto-increment
|
||||||
|
behavior of a "multi-byte" data transfers.
|
||||||
|
|
||||||
|
Note: That most sensors collect only a few bytes of data per sample.
|
||||||
|
Small data transfers occurring over a high speed bus (like SPI and some
|
||||||
|
high speed i2c and serial interfaces) are much more efficient when
|
||||||
|
collected directly from the sensor hardware than by using a worker task
|
||||||
|
as an intermediary.
|
||||||
|
|
||||||
|
``write()``: This function transfers data from the data buffer provided by
|
||||||
|
the caller to sensor registers. The first byte written is to the
|
||||||
|
sensor register address specified by the sensor's "current reg
|
||||||
|
address". The addresses of subsequent bytes to be read are context
|
||||||
|
sensitive. If more than bus transfer is needed to complete the write,
|
||||||
|
then a "multi-byte" (sometimes called "burst mode") data
|
||||||
|
transfer will be used to transfer data from the buffer.
|
||||||
|
|
||||||
|
See the sensor's datasheet to determine the auto-increment
|
||||||
|
behavior of a "multi-byte" data transfers.
|
||||||
|
|
||||||
|
Note: If write() function was disabled, then no writes will be performed
|
||||||
|
and the function will return 0 (characters transferred) and errno
|
||||||
|
is set to -EROFS ("read-only file system").
|
||||||
|
|
||||||
|
``lseek()``: This function sets the value of the sensor's "current reg address"
|
||||||
|
(seek_address). The open() function initializes the "current reg address"
|
||||||
|
to the first sensor data output register, so unless the user needs
|
||||||
|
to change the sensor configuration, lseek() does not need to be
|
||||||
|
called. Neither read() nor write() change the sensor's "current reg
|
||||||
|
address".
|
||||||
|
|
||||||
|
The definition of lseek is...::
|
||||||
|
|
||||||
|
off_t lseek(int fd, off_t offset, int whence);
|
||||||
|
|
||||||
|
For whence == SEEK_SET, the sensor's "current reg address" will be set
|
||||||
|
to offset.
|
||||||
|
|
||||||
|
For whence == SEEK_CUR, offset will be added to the sensor's "current
|
||||||
|
reg address".
|
||||||
|
|
||||||
|
For whence == SEEK_END, offset is ignored and the sensor's "current
|
||||||
|
reg address" is set to the first sensor data output register.
|
||||||
|
|
||||||
|
lseek() will return an error if the resulting "current reg address"
|
||||||
|
is invalid for the sensor.
|
||||||
|
|
||||||
|
``ioctl()``: Ioctls() may still be used and this interface make no attempt to
|
||||||
|
regulate them. But, it is expected that far fewer ioctls will be needed.
|
||||||
|
|
||||||
|
The above interface can be used to fully configure a sensor to the needs
|
||||||
|
of an application, including the ability to load firmware into sensor
|
||||||
|
state machines
|
||||||
|
|
||||||
|
Sensor Cluster Driver Interface
|
||||||
|
===============================
|
||||||
|
|
||||||
|
Contributed by Bob Feretich
|
||||||
|
|
||||||
|
Background and problem statement:
|
||||||
|
|
||||||
|
Most microcontrollers can support SPI bus transfers at 8 MHz or greater.
|
||||||
|
Most SPI attached sensors can support a 10 MHz SPI bus. Most tri-axis
|
||||||
|
accelerometers, tri-axis gyroscopes, or tri-axis magnetometers use only 6
|
||||||
|
bytes per sample. Many sensors use less than 6 bytes per sample. On an 8
|
||||||
|
MHz SPI bus it takes about 8 microseconds to transfer a 6 byte sample.
|
||||||
|
(This time includes a command byte, 6 data bytes, and chip select select
|
||||||
|
setup and hold.) So, for the below discussion keep in mind that the sensor
|
||||||
|
sample collection work we want to perform should ideally take 8 microseconds
|
||||||
|
per sample.
|
||||||
|
|
||||||
|
The drivers in the drivers/sensors directory support only the user space
|
||||||
|
file_ops interface (accessing drivers through the POSIX open/read/close
|
||||||
|
functions using a file descriptor). Also these drivers typically start
|
||||||
|
their own worker task to perform sensor data collection, even when their
|
||||||
|
sensors only transfer a few bytes of data per sample and those transfers
|
||||||
|
are being made over a high performance bus.
|
||||||
|
|
||||||
|
Using the current implementation...
|
||||||
|
|
||||||
|
1) A sensor "data ready" or timer interrupt occurs.
|
||||||
|
2) Context is saved and and the driver's interrupt handler is scheduled
|
||||||
|
to run.
|
||||||
|
3) The NuttX scheduler dispatches the driver's interrupt handler task.
|
||||||
|
4) The driver's interrupt handler task posts to a semaphore that the
|
||||||
|
driver's worker task is waiting on.
|
||||||
|
5) NuttX restores the context for the driver's worker task and starts it
|
||||||
|
running.
|
||||||
|
6) The driver's worker task starts the i/o to collect the sample.) (This is
|
||||||
|
where the 8 microseconds of real work gets performed.) And waits on a
|
||||||
|
SPI data transfer complete semaphore.
|
||||||
|
7) The NuttX saves the context of the driver's worker task, and the
|
||||||
|
scheduler dispatches some other task to run while we are waiting.
|
||||||
|
Note that this is a good thing. This task is probably performing some
|
||||||
|
other real work. We want this to happen during the data transfer.
|
||||||
|
8) The completion of the data transfer causes an interrupt. NuttX saves the
|
||||||
|
current context and restores the driver's worker task's context.
|
||||||
|
9) The driver's worker task goes to sleep waiting on the semaphore for the
|
||||||
|
next sensor "data ready" or timer interrupt.
|
||||||
|
10) The NuttX saves the context of the driver's worker task, and the
|
||||||
|
scheduler dispatches some other task to run while we are waiting.
|
||||||
|
|
||||||
|
Independently with the above...
|
||||||
|
|
||||||
|
a) The sensor application program performs a file_ops read() to collect a
|
||||||
|
sample.
|
||||||
|
b) The NuttX high level driver receives control, performs a thin layer of
|
||||||
|
housekeeping and calls the sensor driver's read function.
|
||||||
|
c) The sensor driver's read function copies the most recent sample from the
|
||||||
|
worker task's data area to the application's buffer and returns.
|
||||||
|
d) The NuttX high level driver receives control, performs a thin layer of
|
||||||
|
housekeeping and returns.
|
||||||
|
e) The application processes the sample.
|
||||||
|
|
||||||
|
Using a 216 MHz STM32F7 with no other activity occurring, we have timed the
|
||||||
|
above the elapsed time for the above to be on average 45 microseconds.
|
||||||
|
|
||||||
|
Most sensor applications process data from multiple sensors. (An 9-DoF IMU
|
||||||
|
is typically represented as three sensors (accelerometer, gyroscope, and
|
||||||
|
magnetometer). In this case there are three copies of 1-10 occurring in
|
||||||
|
parallel.
|
||||||
|
|
||||||
|
In applications where live data is being used, the context switch
|
||||||
|
thrashing and cache pollution of this approach cripples system
|
||||||
|
performance. In applications where sensor FIFO data is being used and
|
||||||
|
therefore a large amount of data is collected per iteration, the non "zero
|
||||||
|
copy" nature of the data collection becomes a performance issue.
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
|
||||||
|
The "Sensor Cluster Driver Interface" provides a standard mechanism for
|
||||||
|
an application to collect data from multiple sensor drivers in a much more
|
||||||
|
efficient manner. It significantly reduces the number of running tasks and
|
||||||
|
the context thrashing and cache pollution caused by them. It also permits
|
||||||
|
"zero copy" collection of sensor data.
|
||||||
|
|
||||||
|
The Sensor Cluster Driver Interface uses a single "worker task" to be shared
|
||||||
|
by an arbitrary number of drivers. This shared worker task is a kernel
|
||||||
|
task that is registered like a driver, supports a driver interface to
|
||||||
|
application programs, and collects data from multiple sensors (a cluster of
|
||||||
|
sensors), we refer to it a "Sensor Cluster Driver".
|
||||||
|
|
||||||
|
Its goal is to change the sequence of events detailed above to...
|
||||||
|
|
||||||
|
1) A sensor "data ready" or timer interrupt occurs.
|
||||||
|
2) Context is saved and and the cluster driver's interrupt handler is
|
||||||
|
scheduled to run.
|
||||||
|
3) The NuttX scheduler dispatches the cluster driver's interrupt handler
|
||||||
|
task.
|
||||||
|
4) The cluster driver's interrupt handler task posts to a semaphore that
|
||||||
|
the cluster driver's worker task is waiting on.
|
||||||
|
5) NuttX restores the context for the driver's worker task and starts it
|
||||||
|
running.
|
||||||
|
6) The cluster driver's worker task starts the i/o to collect the sample.
|
||||||
|
There are two choices here. Programmed I/O (PIO) or DMA. If PIO is
|
||||||
|
fastest for a small sample size, but it will lock up the processor for
|
||||||
|
the full duration of the transfer; it can only transfer from one
|
||||||
|
sensor at a time; and the worker task should manually yield control
|
||||||
|
occasionally to permit other tasks to run. DMA has higher start and
|
||||||
|
completion overhead, but it is much faster for long transfers, can
|
||||||
|
perform simultaneous transfers from sensors on different buses, and
|
||||||
|
automatically releases the processor while the transfer is occurring.
|
||||||
|
For this reason our drivers allows the worker task to choose between
|
||||||
|
PIO (driver_read()) and DMA (driver_exchange()), a common extension to
|
||||||
|
the sensor_cluster_operations_s structure. So either way after one or
|
||||||
|
more transfers we yield control and move to the next step. Note that
|
||||||
|
the data is being transferred directly into the buffer provided by the
|
||||||
|
application program; so no copy needs to be performed.
|
||||||
|
7) The NuttX saves the context of the cluster driver's worker task, and the
|
||||||
|
scheduler dispatches some other task to run while we are waiting.
|
||||||
|
Again note that this is a good thing. This task is probably performing
|
||||||
|
some other real work. We want this to happen during the data transfer.
|
||||||
|
8) The completion of the last of the previous data transfers causes an
|
||||||
|
interrupt. NuttX saves the current context and restores the cluster
|
||||||
|
driver's worker task's context. If there is more sensor data to
|
||||||
|
collect, then goto Step 6. Otherwise it posts to a semaphore that
|
||||||
|
will wake the application.
|
||||||
|
9) The driver's worker task goes to sleep waiting on the semaphore for the
|
||||||
|
next sensor "data ready" or timer interrupt.
|
||||||
|
10) The NuttX saves the context of the driver's worker task, and the
|
||||||
|
scheduler dispatches some other task to run while we are waiting.
|
||||||
|
|
||||||
|
Independently with the above...
|
||||||
|
|
||||||
|
a) The sensor application program performs a file_ops read() to collect a
|
||||||
|
sample.
|
||||||
|
b) The NuttX high level driver receives control, performs a thin layer of
|
||||||
|
housekeeping and calls the sensor driver's read function.
|
||||||
|
c) The sensor driver's read function copies the most recent sample from the
|
||||||
|
worker task's data area to the application's buffer and returns.
|
||||||
|
d) The NuttX high level driver receives control, performs a thin layer of
|
||||||
|
housekeeping and returns.
|
||||||
|
e) The application processes the sample.
|
||||||
|
|
||||||
|
So when collecting data from three sensors, this mechanism saved...
|
||||||
|
|
||||||
|
* the handling of 2 sensor "data ready" or timer interrupts (Steps 1 - 4).
|
||||||
|
* 2 occurrences of waking and scheduling of a worker task (Step 5).
|
||||||
|
* 2 context switches to other tasks (Step 9 & 10)
|
||||||
|
* if the three sensors were on separate buses, then 2 occurrences of
|
||||||
|
|
||||||
|
Steps 6 - 8 could have also been saved.
|
||||||
|
|
||||||
|
* An extra copy operation of the collected sensor data.
|
||||||
|
* The cache pollution caused by 2 competing worker tasks.
|
||||||
|
|
||||||
|
Definitions:
|
||||||
|
|
||||||
|
"Leaf Driver" - a kernel driver that implements the "Sensor Cluster Driver
|
||||||
|
Interface" so that it can be called by Cluster drivers.
|
||||||
|
|
||||||
|
"Cluster Driver" - a kernel driver that uses the "Sensor Cluster Driver
|
||||||
|
Interface" to call leaf drivers.
|
||||||
|
|
||||||
|
"Entry-Point Vector" - an array of function addresses to which a leaf driver
|
||||||
|
will permit calls by a Cluster Driver.
|
||||||
|
|
||||||
|
"Leaf Driver Instance Handle" - a pointer to an opaque Leaf Driver structure
|
||||||
|
that identifies an instance of the leaf driver. Leaf Drivers store this
|
||||||
|
handle in its configuration structure during registration.
|
||||||
|
|
||||||
|
Sensor Cluster Interface description:
|
||||||
|
|
||||||
|
* The definition of an entry-point vector. This is similar to the
|
||||||
|
entry-point vector that is provided to the file-ops high level driver.
|
||||||
|
This entry-point vector must include the sensor_cluster_operations_s
|
||||||
|
structure as its first member.
|
||||||
|
* The the definition of an driver entry-point vector member in the leaf
|
||||||
|
driver's configuration structure. The leaf driver registration function
|
||||||
|
must store the address of its entry-point vector in this field.
|
||||||
|
* The the definition of an instance handle member in the leaf drivers
|
||||||
|
configuration structure. The leaf driver registration function must store
|
||||||
|
a handle (opaque pointer) to the instance of the leaf driver being
|
||||||
|
registered in this field. Note that this should be the same handle that
|
||||||
|
the leaf driver supplies to NuttX to register itself. The cluster driver
|
||||||
|
will include this handle as a parameter in calls made to the leaf driver.
|
||||||
|
|
||||||
|
.. code-block:: C
|
||||||
|
|
||||||
|
struct sensor_cluster_operations_s
|
||||||
|
{
|
||||||
|
CODE int (*driver_open)(FAR void *instance_handle, int32_t arg);
|
||||||
|
CODE int (*driver_close)(FAR void *instance_handle, int32_t arg);
|
||||||
|
CODE ssize_t (*driver_read)(FAR void *instance_handle, FAR char *buffer,
|
||||||
|
size_t buflen);
|
||||||
|
CODE ssize_t (*driver_write)(FAR void *instance_handle,
|
||||||
|
FAR const char *buffer, size_t buflen);
|
||||||
|
CODE off_t (*driver_seek)(FAR void *instance_handle, off_t offset,
|
||||||
|
int whence);
|
||||||
|
CODE int (*driver_ioctl)(FAR void *instance_handle, int cmd,
|
||||||
|
unsigned long arg);
|
||||||
|
CODE int (*driver_suspend)(FAR void *instance_handle, int32_t arg);
|
||||||
|
CODE int (*driver_resume)(FAR void *instance_handle, int32_t arg);
|
||||||
|
};
|
||||||
|
|
||||||
|
Note that the sensor_cluster_operations_s strongly resembles the NuttX fs.h
|
||||||
|
file_operations structures. This permits the current file_operations
|
||||||
|
functions to become thin wrappers around these functions.
|
||||||
|
|
||||||
|
``driver_open()`` Same as the fs.h open() except that arg can be specify
|
||||||
|
permitting more flexibility in sensor configuration and initial operation.
|
||||||
|
when arg = 0 the function of driver_open() must be identical to open().
|
||||||
|
|
||||||
|
``driver_close()`` Same as the fs.h close() except that arg can be specify
|
||||||
|
permitting more flexibility in selecting a sensor low power state.
|
||||||
|
when arg = 0 the function of driver_close() must be identical to close().
|
||||||
|
|
||||||
|
``driver_read()`` Same as the fs.h read().
|
||||||
|
|
||||||
|
``driver_write()`` Same as the fs.h write(). Optional. Set to NULL if not
|
||||||
|
supported.
|
||||||
|
|
||||||
|
``driver_seek()`` Same as the fs.h seek(). Optional. Set to NULL if not
|
||||||
|
supported.
|
||||||
|
|
||||||
|
``driver_ioctl()`` Same as the fs.h ioctl(). Optional. Set to NULL if not
|
||||||
|
supported.
|
||||||
|
|
||||||
|
``driver_suspend()`` and ``driver_resume()`` Optional. Set to NULL if not
|
||||||
|
supported. It is common for sensor applications to conserve power and
|
||||||
|
send their microcontroller into a low power sleep state. It seems
|
||||||
|
appropriate to reserve these spots for future use. These driver entry
|
||||||
|
points exist in Linux and Windows. Since microcontrollers and sensors
|
||||||
|
get more capable every year, there should soon be a requirement for
|
||||||
|
these entry points. Discussion on how to standardize their use and
|
||||||
|
implementation should
|
||||||
|
be taken up independently from this driver document.
|
||||||
|
|
||||||
|
Note that all drivers are encouraged to extend their entry-point vectors
|
||||||
|
beyond this common segment. For example it may be beneficial for the
|
||||||
|
worker task to select between programmed i/o and DMA data transfer
|
||||||
|
routines. Unregulated extensions to the Entry-Point Vector should be
|
||||||
|
encouraged to maximize the benefits of a sensor's features.
|
||||||
|
|
||||||
|
Operation:
|
||||||
|
|
||||||
|
Board logic (configs directory) will register the cluster driver. The
|
||||||
|
cluster driver will register the leaf drivers that it will call.
|
||||||
|
This means that the cluster driver has access to the leaf driver's
|
||||||
|
configuration structures and can pass the Leaf Driver Instance Handle to
|
||||||
|
the leaf driver as a parameter in calls made via the Entry-Point Vector.
|
||||||
|
|
||||||
|
Either board logic or an application program may open() the cluster
|
||||||
|
driver. The cluster driver open() calls the open() function of the leaf
|
||||||
|
drivers. The cluster driver open() or read() function can launch the
|
||||||
|
shared worker task that collects the data.
|
||||||
|
|
||||||
|
The cluster driver close() function calls the close functions of the leaf
|
||||||
|
drivers.
|
||||||
|
|
||||||
|
ADT7320
|
||||||
|
=======
|
||||||
|
|
||||||
|
Contributed by Augusto Fraga Giachero
|
||||||
|
|
||||||
|
The ADT7320 is a SPI temperature sensor with a temperature range of
|
||||||
|
−40°C to +150°C.
|
70
Documentation/components/drivers/special/video.rst
Normal file
70
Documentation/components/drivers/special/video.rst
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
====================
|
||||||
|
Video Device Drivers
|
||||||
|
====================
|
||||||
|
|
||||||
|
|
||||||
|
max7456
|
||||||
|
-------
|
||||||
|
|
||||||
|
23 March 2019
|
||||||
|
Bill Gatliff <bgat@billgatliff.com>
|
||||||
|
|
||||||
|
The code in drivers/video/max7456.[ch] is a preliminary device driver for the MAX7456 analog
|
||||||
|
on-screen-display generator. This SPI slave chip is a popular feature in many
|
||||||
|
embedded devices due its low cost and power requirements. In particular, you
|
||||||
|
see it a lot on drone flight-management units.
|
||||||
|
|
||||||
|
I use the term "preliminary" because at present, only the most rudimentary
|
||||||
|
capabilities of the chip are supported:
|
||||||
|
|
||||||
|
* chip reset and startup
|
||||||
|
* read and write low-level chip control registers (DEBUG mode only)
|
||||||
|
* write CA (Character Address) data to the chip's framebuffer memory
|
||||||
|
|
||||||
|
Some key missing features are, in no particular order:
|
||||||
|
|
||||||
|
* VSYNC and HSYNC synchronization (prevents flicker)
|
||||||
|
* ability to update NVM (define custom character sets)
|
||||||
|
|
||||||
|
If you have a factory-fresh chip, then the datasheet shows you what the factory
|
||||||
|
character data set looks like. If you've used the chip in other scenarios,
|
||||||
|
i.e. with Betaflight or similar, then your chip will almost certainly have had
|
||||||
|
the factory character data replaced with something application-specific.
|
||||||
|
|
||||||
|
Either way, you'll probably want to update your character set before long. I
|
||||||
|
should probably get that working, unless you want to take a look at it
|
||||||
|
yoruself...
|
||||||
|
|
||||||
|
The max7456_register() function starts things rolling. The omnibusf4 target
|
||||||
|
device provides an example (there may be others by the time you read this).
|
||||||
|
|
||||||
|
In normal use, the driver creates a set of interfaces under /dev, i.e.::
|
||||||
|
|
||||||
|
/dev/osd0/fb
|
||||||
|
/dev/osd0/raw (*)
|
||||||
|
/dev/osd0/vsync (*)
|
||||||
|
|
||||||
|
* - not yet implemented
|
||||||
|
|
||||||
|
By writing character data to the "fb" interface, you'll see data appear on the
|
||||||
|
display. NOTE that the data you write is NOT, for example, ASCII text: it is
|
||||||
|
the addresses of the characters in the chip's onboard character map.
|
||||||
|
|
||||||
|
For example, if entry 42 in your onboard character map is a bitmap that looks
|
||||||
|
like "H", then when you write the ASCII "*" (decimal 42, hex 2a), you'll see
|
||||||
|
that "H" appear on your screen.
|
||||||
|
|
||||||
|
If you build the code with the DEBUG macro defined, you will see a bunch more interfaces::
|
||||||
|
|
||||||
|
/dev/osd0/VM0
|
||||||
|
/dev/osd0/VM1
|
||||||
|
/dev/osd/DMM
|
||||||
|
...
|
||||||
|
...
|
||||||
|
|
||||||
|
These are interfaces to the low-level chip registers, which can be read and/or
|
||||||
|
written to help you figure out what's going on inside the chip. They're
|
||||||
|
probably more useful for me than you, but there they are in case I'm wrong
|
||||||
|
about that.
|
||||||
|
|
||||||
|
b.g.
|
Loading…
x
Reference in New Issue
Block a user