minor changes and typos
This commit is contained in:
parent
814e4405dc
commit
85ad051e83
6 changed files with 289 additions and 243 deletions
|
|
@ -16,7 +16,7 @@ L3GD20H is a low-power **3-axis angular rate sensor** connected to **I2C** or **
|
|||
- 7 measuring rates from 12.5 Hz to 800 Hz with 4 bandwidths
|
||||
- 16 bit angular rate value data output
|
||||
- 8 bit temperature data output
|
||||
- 2 dedicated interrupt signals (axis movement wake up and data ready)
|
||||
- 2 dedicated interrupt signals for data and event interrupts
|
||||
- integrated high-pass filters with 3 modes and 10 different cut off frequencies
|
||||
- embedded temperature sensor
|
||||
- embedded 32 levels of 16 bit data output FIFO
|
||||
|
|
@ -141,7 +141,7 @@ The functions ```l3gd20h_get_float_data``` and ```l3gd20h_get_raw_data``` always
|
|||
### Filters
|
||||
|
||||
L3GD20H provides embedded low-pass as well as high-pass filtering capabilities to improve measurement results.
|
||||
It is possible to independently apply the filters on the output data and/or on the data used for selective axes movement / wake up interrupt generation (see below) separately. Please refer the [datasheet](http://www.st.com/resource/en/datasheet/l3gd20.pdf) or [application note](http://www.st.com/resource/en/application_note/dm00119036.pdf) for more details.
|
||||
It is possible to independently apply the filters on the output data and/or on the data used for event interrupt generation (selective axis movement and wake up, see below) separately. Please refer the [datasheet](http://www.st.com/resource/en/datasheet/l3gd20.pdf) or [application note](http://www.st.com/resource/en/application_note/dm00119036.pdf) for more details.
|
||||
|
||||
The filters applied to the output data are selected with function ```l3gd20h_select_output_filter```. Following selections are possible:
|
||||
|
||||
|
|
@ -152,7 +152,7 @@ l3gd20h_hpf_only | x | -
|
|||
l3gd20h_lpf2_only | - | x
|
||||
l3gd20h_hpf_and_lpf2 | x | x
|
||||
|
||||
These filters can also be applied to data used for selective axes movement / wake up interrupt generation. The filter mode is defined by member ```filter``` in the settings for interrupt configuration, see function ```l3gd20h_set_int1_config```.
|
||||
These filters can also be applied to data used for event interrupt generation (selective axis movement and wake up). The filter mode is defined by member ```filter``` in the settings of interrupt generator configuration, see function ```l3gd20h_set_int_event_config```.
|
||||
|
||||
While the cutoff frequency of the low pass filter (LPF2) is fixed and depends only on the output data rate (ODR), the mode and the cutoff frequency of the high pass filter can be configured using function ```l3gd20h_config_hpf```. Following HPF modes are available:
|
||||
|
||||
|
|
@ -177,7 +177,7 @@ l3gd20h_get_hpf_ref (sensor);
|
|||
...
|
||||
```
|
||||
|
||||
**Please note:** Since same filters are used for the output data as well as the data used for selective axes movement / wake up interrupt generation, the configuration of the filters always affects both data.
|
||||
**Please note:** Since same filters are used for the output data as well as the data used for event interrupt generation (selective axes movement / wake up), the configuration of the filters always affects both data.
|
||||
|
||||
|
||||
### FIFO
|
||||
|
|
@ -243,37 +243,37 @@ void user_task_periodic (void *pvParameters)
|
|||
|
||||
The L3GD20H allows to activate interrupts on two dedicated interrupt signals
|
||||
|
||||
- for data ready and FIFO interrupts (**```DRDY/INT2```**), and
|
||||
- for axes movement / wake up interrupts (**```INT1```**).
|
||||
- for data interrupts (data ready and FIFO status) on signal **```DRDY/INT2```**, and
|
||||
- for event interrupts (axis movement and wake up) on signal **```INT1```**.
|
||||
|
||||
#### Data ready and FIFO interrupts (```DRDY/INT2```)
|
||||
#### Data interrupts (data ready and FIFO status) on signal **```DRDY/INT2```**
|
||||
|
||||
Interrupts on signal ```DRDY/INT2``` can be generated by following sources:
|
||||
|
||||
Interrupt source | Driver symbol
|
||||
:-----------------|:-------------
|
||||
Output data become ready to read | l3gd20h_data_ready
|
||||
FIFO content exceeds the watermark level | l3gd20h_fifo_threshold
|
||||
FIFO is completely filled | l3gd20h_fifo_overrun
|
||||
FIFO becomes empty | l3gd20h_fifo_empty
|
||||
Output data become ready to read | l3gd20h_int_data_ready
|
||||
FIFO content exceeds the watermark level | l3gd20h_int_fifo_threshold
|
||||
FIFO is completely filled | l3gd20h_int_fifo_overrun
|
||||
FIFO becomes empty | l3gd20h_int_fifo_empty
|
||||
|
||||
Each of these interrupt sources can be enabled or disabled separately with function ```l3gd20h_enable_int2```. By default all interrupt sources are disabled.
|
||||
Each of these interrupt sources can be enabled or disabled separately with function ```l3gd20h_enable_int```. By default all interrupt sources are disabled.
|
||||
|
||||
```
|
||||
l3gd20h_enable_int2 (sensor, l3gd20h_data_ready, true);
|
||||
l3gd20h_enable_int (sensor, l3gd20h_int_data_ready, true);
|
||||
```
|
||||
|
||||
Whenever the interrupt signal ```DRDY/INT2``` is generated, function ```l3gd20h_get_int2_source``` can be used to determine the source of the interrupt signal. This function returns a data structure of type ```l3gd20h_int2_source_t``` that contains a boolean member for each source that can be tested for true.
|
||||
Whenever the interrupt signal ```DRDY/INT2``` is generated, function ```l3gd20h_get_int_data_source``` can be used to determine the source of the interrupt signal. This function returns a data structure of type ```l3gd20h_int_data_source_t``` that contains a boolean member for each source that can be tested for true.
|
||||
|
||||
```
|
||||
void int2_handler ()
|
||||
{
|
||||
l3gd20h_int2_source_t source;
|
||||
l3gd20h_int_data_source_t source;
|
||||
|
||||
// get interrupt source of INT2
|
||||
l3gd20h_get_int2_source (sensor, &source);
|
||||
// get the interrupt source of INT2
|
||||
l3gd20h_get_int_data_source (sensor, &source);
|
||||
|
||||
// if data ready interrupt, get the results and do something with them
|
||||
// in case of data ready interrupt, get the results and do something with them
|
||||
if (source.data_ready)
|
||||
{
|
||||
l3gd20h_get_float_data (sensor, &data)
|
||||
|
|
@ -284,7 +284,7 @@ void int2_handler ()
|
|||
}
|
||||
```
|
||||
|
||||
#### Axes movement / wake up interrupts (**```INT1```**)
|
||||
#### Event interrupts (Axes movement and wake up) on signal **```INT1```**
|
||||
|
||||
This interrupt signal allows to recognize independent rotations of the x, y and z axes. For this purpose, a separate threshold can be defined for each axis. If activated, the angular rate of each axis is compared with its threshold to check whether it is below or above the threshold. The results of all activated comparisons are combined OR or AND to generate the interrupt signal.
|
||||
|
||||
|
|
@ -294,39 +294,40 @@ The configuration of the thresholds, the activated comparisons and selected AND/
|
|||
|
||||
- **Axis movement wake up (WU)** means that the angular rate of any axis is above its threshold (OR).
|
||||
|
||||
To configure the axes movements and wake up interrupts, the function ```l3gd20h_set_int1_config``` has to be used with a parameter of structured data type ```l3gd20h_int1_config_t``` which contains the configuration. For example, selective axis movement recognition (SA) for the z-axis could be configured as following:
|
||||
To configure event interrupts, the function ```l3gd20h_set_int_event_config``` has to be used with a parameter of structured data type ```l3gd20h_int_event_config_t``` which contains the configuration. For example, selective axis movement recognition (SA) for the z-axis could be configured as following:
|
||||
|
||||
```
|
||||
l3gd20h_int1_config_t int1_config;
|
||||
l3gd20h_int_event_config_t int_cfg;
|
||||
|
||||
// thresholds
|
||||
int1_config.x_threshold = 100;
|
||||
int1_config.y_threshold = 100;
|
||||
int1_config.z_threshold = 1000;
|
||||
int_cfg.x_threshold = 100;
|
||||
int_cfg.y_threshold = 100;
|
||||
int_cfg.z_threshold = 1000;
|
||||
|
||||
// x axis below threshold
|
||||
int1_config.x_low_enabled = false;
|
||||
int1_config.x_high_enabled = true;
|
||||
int_cfg.x_low_enabled = false;
|
||||
int_cfg.x_high_enabled = true;
|
||||
|
||||
// y axis below threshold
|
||||
int1_config.y_low_enabled = true;
|
||||
int1_config.y_high_enabled = false;
|
||||
int_cfg.y_low_enabled = true;
|
||||
int_cfg.y_high_enabled = false;
|
||||
|
||||
// z axis below threshold
|
||||
int1_config.z_low_enabled = false;
|
||||
int1_config.z_high_enabled = true;
|
||||
int_cfg.z_low_enabled = false;
|
||||
int_cfg.z_high_enabled = true;
|
||||
|
||||
// AND combination of all conditions
|
||||
int1_config.and_or = true;
|
||||
int_cfg.and_or = true;
|
||||
|
||||
// further parameters
|
||||
int1_config.filter = l3gd20h_hpf_only;
|
||||
int1_config.latch = true;
|
||||
int1_config.duration = 0;
|
||||
int1_config.wait = false;
|
||||
int_cfg.filter = l3gd20h_hpf_only;
|
||||
int_cfg.latch = true;
|
||||
int_cfg.duration = 0;
|
||||
int_cfg.wait = false;
|
||||
|
||||
// set configuration
|
||||
l3gd20h_set_int1_config (sensor, &int1_config);
|
||||
// set the configuration and enable the interrupt
|
||||
l3gd20h_set_int_cfg (sensor, &int_cfg);
|
||||
l3gd20h_enable_int (sensor, l3gd20h_int_event, true);
|
||||
```
|
||||
|
||||
Furthermore, with this data structure it is also configured
|
||||
|
|
@ -341,10 +342,10 @@ As with data ready and FIFO interrupts, function ```l3gd20h_get_int1_source``` c
|
|||
```
|
||||
void int1_handler ()
|
||||
{
|
||||
l3gd20h_int1_source_t source;
|
||||
l3gd20h_int_event_source_t source;
|
||||
|
||||
// get interrupt source of INT1
|
||||
l3gd20h_get_int1_source (sensor, &source);
|
||||
// get the source of INT1 reset INT1 signal
|
||||
l3gd20h_get_int_event_source (sensor, &source);
|
||||
|
||||
// if all conditions where true interrupt
|
||||
if (source.active)
|
||||
|
|
@ -360,30 +361,31 @@ void int1_handler ()
|
|||
**Please note** Activating all threshold comparisons and the OR combination is the most flexible way, functions like selective axis movement can then be realized combining the different interrupt sources. Following example realizes also the selective axis movement recognition (SA) for the z-axis.
|
||||
|
||||
```
|
||||
l3gd20h_int1_config_t int1_config;
|
||||
l3gd20h_int_event_config_t int_cfg;
|
||||
|
||||
// thresholds
|
||||
int1_config.x_threshold = 100;
|
||||
int1_config.y_threshold = 100;
|
||||
int1_config.z_threshold = 100;
|
||||
int_cfg.x_threshold = 100;
|
||||
int_cfg.y_threshold = 100;
|
||||
int_cfg.z_threshold = 100;
|
||||
|
||||
// x axis
|
||||
int1_config.x_low_enabled = true;
|
||||
int1_config.x_high_enabled = true;
|
||||
int_cfg.x_low_enabled = true;
|
||||
int_cfg.x_high_enabled = true;
|
||||
|
||||
// y axis
|
||||
int1_config.y_low_enabled = true;
|
||||
int1_config.y_high_enabled = true;
|
||||
int_cfg.y_low_enabled = true;
|
||||
int_cfg.y_high_enabled = true;
|
||||
|
||||
// z axis
|
||||
int1_config.z_low_enabled = true;
|
||||
int1_config.z_high_enabled = true;
|
||||
int_cfg.z_low_enabled = true;
|
||||
int_cfg.z_high_enabled = true;
|
||||
|
||||
// OR combination of all conditions
|
||||
int1_config.and_or = false;
|
||||
int_cfg.and_or = false;
|
||||
...
|
||||
// set configuration
|
||||
l3gd20h_set_int1_config (sensor, &int1_config);
|
||||
// set the configuration and enable the interrupt
|
||||
l3gd20h_set_int_cfg (sensor, &int_cfg);
|
||||
l3gd20h_enable_int (sensor, l3gd20h_int_event, true);
|
||||
```
|
||||
|
||||
```
|
||||
|
|
@ -391,9 +393,10 @@ void int1_handler ()
|
|||
{
|
||||
l3gd20h_int1_source_t source;
|
||||
|
||||
// get interrupt source of INT1
|
||||
// get the interrupt source of INT1
|
||||
l3gd20h_get_int1_source (sensor, &source);
|
||||
|
||||
// if all conditions where true interrupt
|
||||
if (source.y_low && source.y_low && source.z_high)
|
||||
{
|
||||
// selective axis movement of z-axis
|
||||
|
|
@ -590,7 +593,7 @@ The user task simply tests periodically with a higher rate than the output data
|
|||
A different approach is to use one of the **interrupts** INT1 or INT2.
|
||||
|
||||
- **```DRDY/INT2```** is triggered when new data become available or the FIFO queue status changes.
|
||||
- **```INT1```** is triggered when configured axes movements are recognized.
|
||||
- **```INT1```** is triggered when configured axis movements are recognized.
|
||||
|
||||
In both cases, the user has to implement an interrupt handler that either fetches the data directly or triggers a task, that is waiting to fetch the data.
|
||||
|
||||
|
|
@ -669,14 +672,46 @@ l3gd20h_set_mode (sensor, l3gd20h_normal_odr_12_5, 3, true, true, true);
|
|||
## Full Example
|
||||
|
||||
```
|
||||
/* -- use following constants to define the example mode ----------- */
|
||||
/**
|
||||
* Simple example with one sensor connected to I2C or SPI. It demonstrates the
|
||||
* different approaches to fetch the data. Either one of the interrupt signals
|
||||
* for axes movement wake up *INT1* and data ready interrupt *INT2* is used
|
||||
* or the new data are fetched periodically.
|
||||
*
|
||||
* Harware configuration:
|
||||
*
|
||||
* I2C
|
||||
*
|
||||
* +-----------------+ +----------+
|
||||
* | ESP8266 / ESP32 | | L3GD20H |
|
||||
* | | | |
|
||||
* | GPIO 14 (SCL) ----> SCL |
|
||||
* | GPIO 13 (SDA) <---> SDA |
|
||||
* | GPIO 5 <---- INT1 |
|
||||
* | GPIO 4 <---- DRDY/INT2|
|
||||
* +-----------------+ +----------+
|
||||
*
|
||||
* SPI
|
||||
*
|
||||
* +---------------+ +----------+ +---------------+ +----------+
|
||||
* | ESP8266 | | L3GD20H | | ESP32 | | L3GD20H |
|
||||
* | | | | | | | |
|
||||
* | GPIO 14 (SCK) ----> SCK | | GPIO 16 (SCK) ----> SCK |
|
||||
* | GPIO 13 (MOSI)----> SDI | | GPIO 17 (MOSI)----> SDI |
|
||||
* | GPIO 12 (MISO)<---- SDO | | GPIO 18 (MISO)<---- SDO |
|
||||
* | GPIO 2 (CS) ----> CS | | GPIO 19 (CS) ----> CS |
|
||||
* | GPIO 5 <---- INT1 | | GPIO 5 <---- INT1 |
|
||||
* | GPIO 4 <---- DRDY/INT2| | GPIO 4 <---- DRDY/INT2|
|
||||
* +---------------+ +---------+ +---------------+ +----------+
|
||||
*/
|
||||
|
||||
// use following constants to define the example mode
|
||||
// #define SPI_USED // if defined SPI is used, otherwise I2C
|
||||
// #define INT1_USED // axes movement / wake up interrupts
|
||||
// #define INT2_USED // data ready and FIFO status interrupts
|
||||
// #define INT_EVENT // event interrupts used (axes movement and wake up)
|
||||
// #define INT_DATA // data interrupts used (data ready and FIFO status)
|
||||
// #define FIFO_MODE // multiple sample read mode
|
||||
|
||||
#if defined(INT1_USED) || defined(INT2_USED)
|
||||
#if defined(INT_EVENT) || defined(INT_DATA)
|
||||
#define INT_USED
|
||||
#endif
|
||||
|
||||
|
|
@ -688,10 +723,10 @@ l3gd20h_set_mode (sensor, l3gd20h_normal_odr_12_5, 3, true, true, true);
|
|||
|
||||
#ifdef ESP_PLATFORM // ESP32 (ESP-IDF)
|
||||
|
||||
// user task stack depth for ESP32
|
||||
// user task stack depth
|
||||
#define TASK_STACK_DEPTH 2048
|
||||
|
||||
// SPI interface definitions for ESP32
|
||||
// define SPI interface for L3GD20H sensors
|
||||
#define SPI_BUS HSPI_HOST
|
||||
#define SPI_SCK_GPIO 16
|
||||
#define SPI_MOSI_GPIO 17
|
||||
|
|
@ -700,10 +735,10 @@ l3gd20h_set_mode (sensor, l3gd20h_normal_odr_12_5, 3, true, true, true);
|
|||
|
||||
#else // ESP8266 (esp-open-rtos)
|
||||
|
||||
// user task stack depth for ESP8266
|
||||
// user task stack depth
|
||||
#define TASK_STACK_DEPTH 256
|
||||
|
||||
// SPI interface definitions for ESP8266
|
||||
// define SPI interface for L3GD20H sensors
|
||||
#define SPI_BUS 1
|
||||
#define SPI_SCK_GPIO 14
|
||||
#define SPI_MOSI_GPIO 13
|
||||
|
|
@ -712,13 +747,13 @@ l3gd20h_set_mode (sensor, l3gd20h_normal_odr_12_5, 3, true, true, true);
|
|||
|
||||
#endif // ESP_PLATFORM
|
||||
|
||||
// I2C interface defintions for ESP32 and ESP8266
|
||||
// define I2C interfaces for L3GD20H sensors
|
||||
#define I2C_BUS 0
|
||||
#define I2C_SCL_PIN 14
|
||||
#define I2C_SDA_PIN 13
|
||||
#define I2C_FREQ I2C_FREQ_100K
|
||||
|
||||
// interrupt GPIOs defintions for ESP8266 and ESP32
|
||||
// define GPIOs for interrupt
|
||||
#define INT1_PIN 5
|
||||
#define INT2_PIN 4
|
||||
|
||||
|
|
@ -787,21 +822,21 @@ void user_task_interrupt (void *pvParameters)
|
|||
{
|
||||
if (gpio_num == INT1_PIN)
|
||||
{
|
||||
l3gd20h_int1_source_t source;
|
||||
l3gd20h_int_event_source_t source;
|
||||
|
||||
// get the source of the interrupt and reset INT1 signal
|
||||
l3gd20h_get_int1_source (sensor, &source);
|
||||
// get the source of INT1 reset INT1 signal
|
||||
l3gd20h_get_int_event_source (sensor, &source);
|
||||
|
||||
// if data ready interrupt, get the results and do something with them
|
||||
// in case of data ready interrupt, get the results and do something with them
|
||||
if (source.active)
|
||||
read_data ();
|
||||
}
|
||||
else if (gpio_num == INT2_PIN)
|
||||
{
|
||||
l3gd20h_int2_source_t source;
|
||||
l3gd20h_int_data_source_t source;
|
||||
|
||||
// get the source of the interrupt
|
||||
l3gd20h_get_int2_source (sensor, &source);
|
||||
// get the source of INT2
|
||||
l3gd20h_get_int_data_source (sensor, &source);
|
||||
|
||||
// if data ready interrupt, get the results and do something with them
|
||||
read_data();
|
||||
|
|
@ -903,40 +938,42 @@ void user_init(void)
|
|||
// set polarity of INT signals if necessary
|
||||
// l3gd20h_config_int_signals (dev, l3gd20h_high_active, l3gd20h_push_pull);
|
||||
|
||||
#ifdef INT1_USED
|
||||
// enable event interrupts
|
||||
l3gd20h_int1_config_t int1_config;
|
||||
#ifdef INT_EVENT
|
||||
// enable event interrupts (axis movement and wake up)
|
||||
l3gd20h_int_event_config_t int_cfg;
|
||||
|
||||
l3gd20h_get_int1_config (sensor, &int1_config);
|
||||
l3gd20h_get_int_event_config (sensor, &int_cfg);
|
||||
|
||||
int1_config.x_high_enabled = true;
|
||||
int1_config.y_high_enabled = true;
|
||||
int1_config.z_high_enabled = true;
|
||||
int1_config.x_low_enabled = false;
|
||||
int1_config.y_low_enabled = false;
|
||||
int1_config.z_low_enabled = false;
|
||||
int1_config.x_threshold = 1000;
|
||||
int1_config.y_threshold = 1000;
|
||||
int1_config.z_threshold = 1000;
|
||||
int_cfg.x_high_enabled = true;
|
||||
int_cfg.y_high_enabled = true;
|
||||
int_cfg.z_high_enabled = true;
|
||||
int_cfg.x_low_enabled = false;
|
||||
int_cfg.y_low_enabled = false;
|
||||
int_cfg.z_low_enabled = false;
|
||||
int_cfg.x_threshold = 1000;
|
||||
int_cfg.y_threshold = 1000;
|
||||
int_cfg.z_threshold = 1000;
|
||||
|
||||
int1_config.filter = l3gd20h_hpf_only;
|
||||
int1_config.and_or = false;
|
||||
int1_config.duration = 0;
|
||||
int1_config.latch = true;
|
||||
int_cfg.filter = l3gd20h_hpf_only;
|
||||
int_cfg.and_or = false;
|
||||
int_cfg.duration = 0;
|
||||
int_cfg.latch = true;
|
||||
|
||||
l3gd20h_set_int1_config (sensor, &int1_config);
|
||||
#endif // INT1_USED
|
||||
l3gd20h_set_int_event_config (sensor, &int_cfg);
|
||||
l3gd20h_enable_int (sensor, l3gd20h_int_event, true);
|
||||
|
||||
#ifdef INT2_USED
|
||||
#endif // INT_EVENT
|
||||
|
||||
#ifdef INT_DATA
|
||||
// enable data ready (DRDY) and FIFO interrupt signal *INT2*
|
||||
// NOTE: DRDY and FIFO interrupts must not be enabled at the same time
|
||||
#ifdef FIFO_MODE
|
||||
l3gd20h_enable_int2 (sensor, l3gd20h_fifo_overrun, true);
|
||||
l3gd20h_enable_int2 (sensor, l3gd20h_fifo_threshold, true);
|
||||
l3gd20h_enable_int (sensor, l3gd20h_int_fifo_overrun, true);
|
||||
l3gd20h_enable_int (sensor, l3gd20h_int_fifo_threshold, true);
|
||||
#else
|
||||
l3gd20h_enable_int2 (sensor, l3gd20h_data_ready, true);
|
||||
l3gd20h_enable_int (sensor, l3gd20h_int_data_ready, true);
|
||||
#endif
|
||||
#endif // INT2_USED
|
||||
#endif // INT_DATA
|
||||
|
||||
#ifdef FIFO_MODE
|
||||
// clear FIFO and activate FIFO mode if needed
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue