初始版本

This commit is contained in:
xiaozhengsheng
2025-08-19 09:49:41 +08:00
parent 10f1ddf1c1
commit 6df0f7d96e
2974 changed files with 1712873 additions and 54 deletions

View File

@@ -0,0 +1,358 @@
/**
* Copyright (c) 2009 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <stdbool.h>
#include <stdint.h>
#include "adns2080.h"
#include "sdio.h"
/*lint ++flb "Enter library region" */
#define ADNS2080_PRODUCT_ID (0x2AU) /*!< ADNS2080 product id */
#define ADNS2080_RESET_NUMBER (0x5AU) /*!< ADNS2080 reset code */
/* ADNS2080 register addresses */
#define REG_PROD_ID (0x00U) /*!< Product ID. Default value : 0x2A */
#define REG_REV_ID (0x01U) /*!< Revision ID. Default value : 0x00 */
#define REG_MOTION_ST (0x02U) /*!< Motion Status. Default value : 0x00 */
#define REG_DELTA_X (0x03U) /*!< Lower byte of Delta_X. Default value : 0x00 */
#define REG_DELTA_Y (0x04U) /*!< Lower byte of Delta_Y. Default value : 0x00 */
#define REG_SQUAL (0x05U) /*!< Squal Quality. Default value : 0x00 */
#define REG_SHUT_HI (0x06U) /*!< Shutter Open Time (Upper 8-bit). Default value : 0x00 */
#define REG_SHUT_LO (0x07U) /*!< Shutter Open Time (Lower 8-bit). Default value : 0x64 */
#define REG_PIX_MAX (0x08U) /*!< Maximum Pixel Value. Default value : 0xD0 */
#define REG_PIX_ACCUM (0x09U) /*!< Average Pixel Value. Default value : 0x80 */
#define REG_PIX_MIN (0x0AU) /*!< Minimum Pixel Value. Default value : 0x00 */
#define REG_PIX_GRAB (0x0BU) /*!< Pixel Grabber. Default value : 0x00 */
#define REG_DELTA_XY_HIGH (0x0CU) /*!< Upper 4 bits of Delta X and Y displacement. Default value : 0x00 */
#define REG_MOUSE_CTRL (0x0DU) /*!< Mouse Control. Default value : 0x01 */
#define REG_RUN_DOWNSHIFT (0x0EU) /*!< Run to Rest1 Time. Default value : 0x08 */
#define REG_REST1_PERIOD (0x0FU) /*!< Rest1 Period. Default value : 0x01 */
#define REG_REST1_DOWNSHIFT (0x10U) /*!< Rest1 to Rest2 Time. Default value : 0x1f */
#define REG_REST2_PERIOD (0x11U) /*!< Rest2 Period. Default value : 0x09 */
#define REG_REST2_DOWNSHIFT (0x12U) /*!< Rest2 to Rest3 Time. Default value : 0x2f */
#define REG_REST3_PERIOD (0x13U) /*!< Rest3 Period. Default value : 0x31 */
#define REG_PERFORMANCE (0x22U) /*!< Performance. Default value : 0x00 */
#define REG_RESET (0x3aU) /*!< Reset. Default value : 0x00 */
#define REG_NOT_REV_ID (0x3fU) /*!< Inverted Revision ID. Default value : 0xff */
#define REG_LED_CTRL (0x40U) /*!< LED Control. Default value : 0x00 */
#define REG_MOTION_CTRL (0x41U) /*!< Motion Control. Default value : 0x40 */
#define REG_BURST_READ_FIRST (0x42U) /*!< Burst Read Starting Register. Default value : 0x03 */
#define REG_BURST_READ_LAST (0x44U) /*!< Burst Read Ending Register. Default value : 0x09 */
#define REG_REST_MODE_CONFIG (0x45U) /*!< Rest Mode Confi guration. Default value : 0x00 */
#define REG_MOTION_BURST (0x63U) /*!< Burst Read. Default value : 0x00 */
/* ADNS2080 register bits */
#define REG_MOUSE_CTRL_POWERDOWN (0x02U) /*!< Mouse control register powerdown bit */
#define REG_MOTION_CTRL_MOT_A (0x80U) /*!< Motion control register polarity bit */
#define REG_MOTION_CTRL_MOT_S (0x40U) /*!< Motion control register edge sensitivity bit */
#define REG_MOUSE_CTRL_RES_EN (0x40U) /*!< Mouse control register resolution enable bit */
#define REG_MOUSE_CTRL_BIT_REPORTING (0x80U) /*!< Mouse control register "number of motion bits" bit*/
void adns2080_movement_read(int16_t * deltaX, int16_t * deltaY)
{
uint8_t delta_x; /*!< Stores REG_DELTA_X contents */
uint8_t delta_y; /*!< Stores REG_DELTA_Y contents */
uint8_t delta_xy_high; /*!< Stores REG_DELTA_XY contents which contains upper 4 bits for both delta_x and delta_y when 12 bit mode is used */
uint8_t delta_x_high; /*!< Stores delta_x 4 MSB bits */
uint8_t delta_y_high; /*!< Stores delta_y 4 MSB bits */
uint16_t u16_deltaX; /*!< This is used to buffer the result and will be cast later to int16_t */
uint16_t u16_deltaY; /*!< This is used to buffer the result and will be cast later to int16_t */
delta_x = sdio_read_byte(REG_DELTA_X);
delta_y = sdio_read_byte(REG_DELTA_Y);
if (adns2080_motion_bits_read() == ADNS2080_MOTION_BITS_12)
{
// In 12 bit mode the upper 4 bits are stored in a separate register
// where first 4 upper bits are for delta_x and lower 4 bits for delta_y.
delta_xy_high = sdio_read_byte(REG_DELTA_XY_HIGH);
delta_x_high = ((delta_xy_high & 0xF0) >> 4);
delta_y_high = (delta_xy_high & 0x0F);
// Check if MSB is 1. If it is, this is a negative number and we have
// to fill the upper unused bits with 1s.
if (delta_x_high & 0x08)
{
u16_deltaX = 0xF000;
}
else
{
u16_deltaX = 0x0000;
}
// Check if MSB is 1. If it is, this is a negative number and we have
// to fill the upper unused bits with 1s.
if (delta_y_high & 0x08)
{
u16_deltaY = 0xF000;
}
else
{
u16_deltaY = 0x0000;
}
u16_deltaX |= (delta_x_high << 4) | delta_x;
u16_deltaY |= (delta_y_high << 4) | delta_y;
}
else // Only 8 bits is used for motion data
{
// Check if MSB is 1. If it is, this is a negative number and we have
// to fill the upper unused bits with 1s.
if (delta_x & 0x80)
{
u16_deltaX = 0xFF00;
}
else
{
u16_deltaX = 0x0000;
}
// Check if MSB is 1. If it is, this is a negative number and we have
// to fill the upper unused bits with 1s.
if (delta_y & 0x80)
{
u16_deltaY = 0xFF00;
}
else
{
u16_deltaY = 0x0000;
}
u16_deltaX |= delta_x;
u16_deltaY |= delta_y;
}
*deltaX = (int16_t)u16_deltaX;
*deltaY = (int16_t)u16_deltaY;
}
adns2080_motion_bits_t adns2080_motion_bits_read(void)
{
/* Read the most significant bit */
return (adns2080_motion_bits_t)((sdio_read_byte(REG_MOUSE_CTRL) >> 7) & 0x01);
}
bool adns2080_is_motion_detected(void)
{
return ((sdio_read_byte(REG_MOTION_ST) & 0x80) != 0);
}
uint8_t adns2080_product_id_read(void)
{
return sdio_read_byte(REG_PROD_ID);
}
uint8_t adns2080_revision_id_read(void)
{
return sdio_read_byte(REG_REV_ID);
}
adns2080_status_t adns2080_init(void)
{
sdio_init();
adns2080_reset();
if (adns2080_product_id_read() != ADNS2080_PRODUCT_ID)
{
return ADNS2080_CHIP_NOT_DETECTED;
}
sdio_write_byte(REG_BURST_READ_FIRST, REG_DELTA_X);
sdio_write_byte(REG_BURST_READ_LAST, REG_DELTA_Y);
return ADNS2080_OK;
}
void adns2080_reset(void)
{
sdio_write_byte(REG_RESET, ADNS2080_RESET_NUMBER);
}
void adns2080_powerdown(void)
{
sdio_write_byte(REG_MOUSE_CTRL, REG_MOUSE_CTRL_POWERDOWN);
}
void adns2080_wakeup(void)
{
adns2080_reset();
}
adns2080_status_t adns2080_motion_interrupt_set(motion_output_polarity_t polarity, motion_output_sensitivity_t sensitivity)
{
uint8_t databyte = 0;
adns2080_status_t status = ADNS2080_OK;
switch (polarity)
{
case ADNS2080_MOTION_OUTPUT_POLARITY_LOW:
databyte = 0; // Clear REG_MOTION_CTRL_MOT_A bit
break;
case ADNS2080_MOTION_OUTPUT_POLARITY_HIGH:
databyte = REG_MOTION_CTRL_MOT_A;
break;
default:
status = ADNS2080_INVALID_PARAMETER;
break;
}
switch (sensitivity)
{
case ADNS2080_MOTION_OUTPUT_SENSITIVITY_LEVEL:
databyte &= ~(REG_MOTION_CTRL_MOT_S);
break;
case ADNS2080_MOTION_OUTPUT_SENSITIVITY_EDGE:
databyte |= (REG_MOTION_CTRL_MOT_S);
break;
default:
status = ADNS2080_INVALID_PARAMETER;
break;
}
if (status == ADNS2080_OK)
{
sdio_write_byte(REG_MOTION_CTRL, databyte);
}
return status;
}
adns2080_status_t adns2080_resolution_set(adns2080_resolution_t resolution)
{
uint8_t databyte = sdio_read_byte(REG_MOUSE_CTRL);
adns2080_status_t status = ADNS2080_OK;
// Enable resolution settings on REG_MOUSE_CTRL [4:2]
databyte |= (REG_MOUSE_CTRL_RES_EN);
switch (resolution)
{
case ADNS2080_RESOLUTION_250DPI:
case ADNS2080_RESOLUTION_500DPI:
case ADNS2080_RESOLUTION_1000DPI:
case ADNS2080_RESOLUTION_1250DPI:
case ADNS2080_RESOLUTION_1500DPI:
case ADNS2080_RESOLUTION_1750DPI:
case ADNS2080_RESOLUTION_2000DPI:
// Clear resolution bits [4:2]
databyte &= ~(0x1C); // 0b00011100;
// Set resolution bits
databyte |= (uint8_t)((uint8_t)resolution << 2);
break;
default:
status = ADNS2080_INVALID_PARAMETER;
break;
}
if (status == ADNS2080_OK)
{
sdio_write_byte(REG_MOUSE_CTRL, databyte);
}
return status;
}
adns2080_status_t adns2080_motion_bits_set(adns2080_motion_bits_t motion_bits)
{
uint8_t databyte = sdio_read_byte(REG_MOUSE_CTRL);
adns2080_status_t status = ADNS2080_OK;
switch (motion_bits)
{
case ADNS2080_MOTION_BITS_8:
databyte &= ~(REG_MOUSE_CTRL_BIT_REPORTING);
break;
case ADNS2080_MOTION_BITS_12:
databyte |= (REG_MOUSE_CTRL_BIT_REPORTING);
break;
default:
status = ADNS2080_INVALID_PARAMETER;
break;
}
if (status == ADNS2080_OK)
{
sdio_write_byte(REG_MOUSE_CTRL, databyte);
}
return status;
}
void adns2080_rest_periods_set(uint8_t rest1_period, uint8_t rest2_period, uint8_t rest3_period)
{
adns2080_mode_t current_mode = adns2080_force_mode_read();
adns2080_force_mode_set(ADNS2080_MODE_RUN1);
sdio_write_byte(REG_REST1_PERIOD, rest1_period);
sdio_write_byte(REG_REST2_PERIOD, rest2_period);
sdio_write_byte(REG_REST3_PERIOD, rest3_period);
adns2080_force_mode_set(current_mode);
}
void adns2080_downshift_times_set(uint8_t run_to_rest1_mode_time, uint8_t rest1_to_rest2_mode_time, uint8_t rest2_to_rest3_mode_time)
{
adns2080_mode_t current_mode = adns2080_force_mode_read();
adns2080_force_mode_set(ADNS2080_MODE_RUN1);
sdio_write_byte(REG_RUN_DOWNSHIFT, run_to_rest1_mode_time);
sdio_write_byte(REG_REST1_DOWNSHIFT, rest1_to_rest2_mode_time);
sdio_write_byte(REG_REST2_DOWNSHIFT, rest2_to_rest3_mode_time);
adns2080_force_mode_set(current_mode);
}
adns2080_mode_t adns2080_force_mode_read(void)
{
return (adns2080_mode_t)((sdio_read_byte(REG_PERFORMANCE) >> 4) & 0x07);
}
void adns2080_force_mode_set(adns2080_mode_t mode)
{
sdio_write_byte(REG_PERFORMANCE, (uint8_t)((uint8_t)mode << 4));
}
/*lint --flb "Leave library region" */

View File

@@ -0,0 +1,317 @@
/**
* Copyright (c) 2009 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef ADNS2080_H
#define ADNS2080_H
/*lint ++flb "Enter library region" */
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @file
* @brief ADNS2080 mouse sensor driver
*
* @defgroup nrf_drivers_adns2080 ADNS2080 driver
* @{
* @ingroup ext_drivers
* @brief ADNS2080 mouse sensor driver.
*/
/**
* Describes return values for @ref adns2080_init.
*/
typedef enum
{
ADNS2080_OK, /*!< Operation was succesful */
ADNS2080_SERIAL_COMM_FAILURE, /*!< Serial communication failed */
ADNS2080_CHIP_NOT_DETECTED, /*!< Product/Revision ID was not what was expected */
ADNS2080_INVALID_PARAMETER /*!< Given parameters were not valid */
} adns2080_status_t;
/**
* ADNS2080 motion output pin polarity values.
*/
typedef enum
{
ADNS2080_MOTION_OUTPUT_POLARITY_LOW = 0, /*!< Motion output polarity active low */
ADNS2080_MOTION_OUTPUT_POLARITY_HIGH = 1 /*!< Motion output polarity active high */
} motion_output_polarity_t;
/**
* Motion output pin configuration.
*/
typedef enum
{
ADNS2080_MOTION_OUTPUT_SENSITIVITY_LEVEL = 0, /*!< Motion output pin will be driven low/high (depending on the polarity setting) as long as there is motion data in DELTA registers */
ADNS2080_MOTION_OUTPUT_SENSITIVITY_EDGE = 1 /*!< Motion output pin will be driven low/high (depending on the polarity setting) for 380 ns when motion is detected during rest modes */
} motion_output_sensitivity_t;
/**
* Mouse sensor resolution values.
*/
typedef enum
{
ADNS2080_RESOLUTION_250DPI = 1, /*!< 250 dpi resolution */
ADNS2080_RESOLUTION_500DPI = 2, /*!< 500 dpi resolution */
ADNS2080_RESOLUTION_1000DPI = 0, /*!< 1000 dpi resolution */
ADNS2080_RESOLUTION_1250DPI = 3, /*!< 1250 dpi resolution */
ADNS2080_RESOLUTION_1500DPI = 4, /*!< 1500 dpi resolution */
ADNS2080_RESOLUTION_1750DPI = 5, /*!< 1750 dpi resolution */
ADNS2080_RESOLUTION_2000DPI = 6 /*!< 2000 dpi resolution */
} adns2080_resolution_t;
/**
* Mouse sensor forced mode options.
*/
typedef enum
{
ADNS2080_MODE_NORMAL = 0, /*!< Normal operation mode */
ADNS2080_MODE_REST1 = 1, /*!< Rest1 operation mode */
ADNS2080_MODE_REST2 = 2, /*!< Rest2 operation mode */
ADNS2080_MODE_REST3 = 3, /*!< Rest3 operation mode */
ADNS2080_MODE_RUN1 = 4, /*!< Run1 operation mode */
ADNS2080_MODE_RUN2 = 5, /*!< Run2 operation mode */
ADNS2080_MODE_IDLE = 6 /*!< Idle operation mode */
} adns2080_mode_t;
/**
* Mouse sensor motion reporting bits.
*/
typedef enum
{
ADNS2080_MOTION_BITS_8 = 0, /*!< Motion reporting uses 8 bits */
ADNS2080_MOTION_BITS_12 = 1 /*!< Motion reporting uses 12 bits */
} adns2080_motion_bits_t;
/**
* @brief Function for initializing the mouse sensor chip.
*
* Valid mouse sensor information will be available 50 milliseconds after this
* function finishes.
*
* @return
* @retval ADNS2080_OK Mouse sensor was initialized succesfully.
* @retval ADNS2080_SERIAL_COMM_FAILURE Serial communications failure.
* @retval ADNS2080_CHIP_NOT_DETECTED Could not find revision 0 ADNS2080 chip.
*/
adns2080_status_t adns2080_init(void);
/**
* @brief Function for resetting the mouse sensor chip.
*
* Valid mouse sensor information will be available 50 milliseconds after this
* function finishes.
* All register settings will be lost and need to be reloaded.
*
*/
void adns2080_reset(void);
/**
* @brief Function for reading mouse sensor product ID.
*
* Chip is expected to be initialized before calling this function.
* Returned product ID should always be 0x2A.
*
* @return Product ID.
*/
uint8_t adns2080_product_id_read(void);
/**
* @brief Function for reading mouse sensor revision ID.
*
* Chip is expected to be initialized before calling this function.
*
* @return Product ID.
*/
uint8_t adns2080_revision_id_read(void); // also note there is "not rev id" register
/**
* @brief Function for powering down the mouse sensor.
*
* Chip is expected to be initialized before calling this function.
* Serial port should not be accessed during the power down. To exit the power
* down mode, @ref adns2080_wakeup must be called.
*
*/
void adns2080_powerdown(void);
/**
* @brief Function for waking up the mouse sensor.
*
* After wakeup, all mouse sensor settings must be reloaded. Valid mouse sensor
* information will be available 55 milliseconds after this function finishes.
*/
void adns2080_wakeup(void);
/**
* @brief Function for configuring the MOTION interrupt output pin.
*
* When motion is detected by the mouse sensor, the chip has a MOTION pin
* indicating there is motion data in DELTA_X and DELTA_Y registers. This
* function configures the polarity and sensitivity of that pin.
*
* Chip is expected to be initialized before calling this function.
*
* @param polarity MOTION output pin is either active LOW (default) or active HIGH
* @param sensitivity Level or Edge (default) sensitive
* @return
* @retval ADNS2080_OK Operation succeeded.
* @retval ADNS2080_INVALID_PARAMETER One of the parameters was not within valid range.
*/
adns2080_status_t adns2080_motion_interrupt_set(motion_output_polarity_t polarity, motion_output_sensitivity_t sensitivity);
/**
* @brief Function for setting mouse sensor resolution.
*
* Chip is expected to be initialized before calling this function.
*
* @param resolution Desired resolution.
* @return
* @retval ADNS2080_OK Operation succeeded.
* @retval ADNS2080_INVALID_PARAMETER One of the parameters was not within valid range.
*/
adns2080_status_t adns2080_resolution_set(adns2080_resolution_t resolution);
/**
* @brief Function for setting number of bits used for mouse sensor motion reporting.
*
* Chip is expected to be initialized before calling this function.
*
* @param motion_bits Desired number of bits.
* @return
* @retval ADNS2080_OK Operation succeeded.
* @retval ADNS2080_INVALID_PARAMETER One of the parameters was not within valid range.
*/
adns2080_status_t adns2080_motion_bits_set(adns2080_motion_bits_t motion_bits);
/**
* @brief Function for reading number of bits used for mouse sensor motion reporting.
*
* Chip is expected to be initialized before calling this function.
*
* @return motion_bits Number of bits.
*/
adns2080_motion_bits_t adns2080_motion_bits_read(void);
/**
* @brief Function for reading X- and Y-axis movement (in counts) since last report.
*
* Absolute value is determined by resolution.
* Chip is expected to be initialized before calling this function.
*
* @param p_delta_x Location to store X-axis movement
* @param p_delta_y Location to store Y-axis movement
*/
void adns2080_movement_read(int16_t *p_delta_x, int16_t *p_delta_y);
/**
* @brief Function for checking if motion has been detected since last call.
*
* Chip is expected to be initialized before calling this function.
*
* @return
* @retval true, if movement has been detected
* @retval false, if no movement has been detected
*/
bool adns2080_is_motion_detected(void);
/**
* @brief Function for setting mouse sensor Rest1, Rest2 and Rest3 mode motion detection time period.
*
* Allowed range for the periods is 0x01 to 0xFD.
* Resulting period is derived from the following equation :
* Period = (Rest period + 1) * 10 milliseconds
* Chip is expected to be initialized before calling this function.
*
* @param rest1_period Rest1 period
* @param rest2_period Rest2 period
* @param rest3_period Rest3 period
*/
void adns2080_rest_periods_set(uint8_t rest1_period, uint8_t rest2_period, uint8_t rest3_period);
/**
* @brief Function for setting mouse sensor mode downshift time periods.
*
* Allowed range for run_to_rest1_mode_time period is 0x00 to 0xFF.
* Allowed range for rest1_to_rest2_mode_time period is 0x01 to 0xFF.
* Allowed range for rest2_to_rest3_mode_time period is 0x01 to 0xFF.
*
* Chip is expected to be initialized before calling this function.
*
* @param run_to_rest1_mode_time Run mode to Rest1 mode downshift time period (Time = run_to_rest1_mode_time * 8 * 4)
* @param rest1_to_rest2_mode_time Rest1 mode to Rest2 mode downshift time period (Time = rest1_to_rest2_mode_time * rest1_period * 16)
* @param rest2_to_rest3_mode_time Rest2 mode to Rest3 mode downshift time period (Time = rest2_to_rest3_mode_time * rest2_period * 128)
*/
void adns2080_downshift_times_set(uint8_t run_to_rest1_mode_time, uint8_t rest1_to_rest2_mode_time, uint8_t rest2_to_rest3_mode_time);
/**
* @brief Function for forcing mouse sensor to a certain operating mode.
*
* Chip is expected to be initialized before calling this function.
* Normal operation will not continue until this function is called with ADNS2080_MODE_NORMAL parameter.
*
* @param mode Mode to force the sensor to.
*/
void adns2080_force_mode_set(adns2080_mode_t mode);
/**
* @brief Function for reading the current forced operating mode.
*
* Chip is expected to be initialized before calling this function.
*
* @return Mode the sensor is forced to.
*/
adns2080_mode_t adns2080_force_mode_read(void);
/**
*@}
**/
/*lint --flb "Leave library region" */
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,203 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "bh1745.h"
#define BH1745_SENSOR_WRITE(p_instance, msg) \
nrf_twi_sensor_write(p_instance->p_sensor_data, \
p_instance->sensor_addr, \
msg, \
ARRAY_SIZE(msg), \
true)
ret_code_t bh1745_init(bh1745_instance_t * p_instance)
{
ASSERT(p_instance != NULL);
if (p_instance->p_sensor_data->p_twi_mngr->p_queue->size < BH1745_MIN_QUEUE_SIZE)
{
return NRF_ERROR_INVALID_LENGTH;
}
static const uint8_t msg1[] = {
BH1745_REG_MODE_CONTROL1,
0x00,
0x00,
0x00
};
ret_code_t err = BH1745_SENSOR_WRITE(p_instance, msg1);
if (err != NRF_SUCCESS)
{
return err;
}
static const uint8_t msg2[] = {
BH1745_REG_INTERRUPT,
0x00,
0x01,
0xFF,
0xFF,
0x00,
0x00
};
return BH1745_SENSOR_WRITE(p_instance, msg2);
}
ret_code_t bh1745_sw_reset(bh1745_instance_t * p_instance)
{
ASSERT(p_instance != NULL);
static const uint8_t send_msg[] = {
BH1745_REG_SYSTEM_CONTROL,
BH1745_SW_RESET_MASK
};
return BH1745_SENSOR_WRITE(p_instance, send_msg);
}
ret_code_t bh1745_int_reset(bh1745_instance_t * p_instance)
{
ASSERT(p_instance != NULL);
static const uint8_t send_msg[] = {
BH1745_REG_SYSTEM_CONTROL,
BH1745_INT_RESET_MASK
};
return BH1745_SENSOR_WRITE(p_instance, send_msg);
}
ret_code_t bh1745_meas_cfg(bh1745_instance_t * p_instance,
bh1745_meas_time_t meas_time,
bool enable,
bh1745_gain_t gain)
{
ASSERT(p_instance != NULL);
if (meas_time > BH1745_MEAS_TIME_5120MS)
{
meas_time = BH1745_MEAS_TIME_5120MS;
}
if (gain > BH1745_GAIN_16X)
{
gain = BH1745_GAIN_16X;
}
uint8_t send_msg[] = {
BH1745_REG_MODE_CONTROL1,
0,
0,
0x02
};
NRF_TWI_SENSOR_REG_SET(send_msg[1], BH1745_MEAS_TIME_MASK, BH1745_MEAS_TIME_POS, meas_time);
NRF_TWI_SENSOR_REG_SET(send_msg[2], BH1745_RGBC_EN_MASK, BH1745_RGBC_EN_POS, enable);
NRF_TWI_SENSOR_REG_SET(send_msg[2], BH1745_ADC_GAIN_MASK, BH1745_ADC_GAIN_POS, gain);
return BH1745_SENSOR_WRITE(p_instance, send_msg);
}
ret_code_t bh1745_data_read(bh1745_instance_t * p_instance,
bh1745_data_callback_t user_callback,
bh1745_data_t * p_data)
{
ASSERT(p_instance != NULL);
ASSERT(p_data != NULL);
ret_code_t err_code;
err_code = nrf_twi_sensor_reg_read(p_instance->p_sensor_data,
p_instance->sensor_addr,
BH1745_REG_MODE_CONTROL2,
NULL,
&p_data->valid,
1);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
err_code = nrf_twi_sensor_reg_read(p_instance->p_sensor_data,
p_instance->sensor_addr,
BH1745_REG_RED_DATA_LSB,
(nrf_twi_sensor_reg_cb_t) user_callback,
(uint8_t *) &p_data->red,
BH1745_DATA_REG_NUM);
return err_code;
}
ret_code_t bh1745_int_cfg(bh1745_instance_t * p_instance,
bool latch,
bh1745_int_source_t source,
bool enable,
bh1745_persistence_t persistance)
{
ASSERT(p_instance != NULL);
uint8_t int_reg = 0;
NRF_TWI_SENSOR_REG_SET(int_reg, BH1745_INT_ENABLE_MASK, BH1745_INT_ENABLE_POS, enable);
NRF_TWI_SENSOR_REG_SET(int_reg, BH1745_INT_SOURCE_MASK, BH1745_INT_SOURCE_POS, source);
NRF_TWI_SENSOR_REG_SET(int_reg, BH1745_INT_LATCH_MASK, BH1745_INT_LATCH_POS, latch);
uint8_t send_msg[] = {
BH1745_REG_INTERRUPT,
int_reg,
persistance
};
return BH1745_SENSOR_WRITE(p_instance, send_msg);
}
ret_code_t bh1745_high_thr_set(bh1745_instance_t * p_instance,
uint16_t threshold)
{
ASSERT(p_instance != NULL);
uint8_t send_msg[] = {
BH1745_REG_TH_LSB,
LSB_16(threshold),
MSB_16(threshold)
};
return BH1745_SENSOR_WRITE(p_instance, send_msg);
}
ret_code_t bh1745_low_thr_set(bh1745_instance_t * p_instance,
uint16_t threshold)
{
ASSERT(p_instance != NULL);
uint8_t send_msg[] = {
BH1745_REG_TL_LSB,
LSB_16(threshold),
MSB_16(threshold)
};
return BH1745_SENSOR_WRITE(p_instance, send_msg);
}

View File

@@ -0,0 +1,359 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef BH1745_H
#define BH1745_H
#include "nrf_twi_sensor.h"
#include "bh1745_internal.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Possible sensor addresses.
*/
#define BH1745_BASE_ADDRESS_LOW 0x38U
#define BH1745_BASE_ADDRESS_HIGH 0x39U
// Minimum nrf_twi_sensor message buffer size and nrf_twi_mngr queue length.
#define BH1745_MIN_QUEUE_SIZE 5
/**
* @brief Sensor driver usage.
*
* Sensor instance has to be defined first in global context using @ref BH1745_INSTANCE DEF.
* After that it has to be initialized using @ref bh1745_init.
* At this point sensor instance is ready and all other functions can be used.
*
* Configuration functions schedule TWI operation using @ref nrf_twi_sensor module.
* After calling function, setting will be automatically send to sensor when TWI bus is free.
*
* There are designated functions to read status sensor registers e.g. @ref bh1745_sys_ctrl_read
* As parameters they receive function to be called after register is read, and pointer where
* register value should be stored. From that value specific parameters can be extracted
* using @ref NRF_TWI_SENSOR_REG_VAL_GET macro.
* Example:
* uint8_t part_id = NRF_TWI_SENSOR_REG_VAL_GET(sys_ctrl_reg,
* BH1745_PART_ID_MASK,
* BH1745_PART_ID_POS);
*
* Other functions are self-explanatory or have description on their usage.
*/
/**
* @brief Measurement time.
*/
typedef enum
{
BH1745_MEAS_TIME_160MS,
BH1745_MEAS_TIME_320MS,
BH1745_MEAS_TIME_640MS,
BH1745_MEAS_TIME_1280MS,
BH1745_MEAS_TIME_2560MS,
BH1745_MEAS_TIME_5120MS
} bh1745_meas_time_t;
/**
* @brief RGBC (red, green, blue, clear) gain setting.
*/
typedef enum
{
BH1745_GAIN_1X,
BH1745_GAIN_2X,
BH1745_GAIN_16X
} bh1745_gain_t;
/**
* @brief Persistence settings.
*/
typedef enum
{
BH1745_TOGGLE_EACH_MEASURE,
BH1745_UPDATE_EACH_MEASURE,
BH1745_UPDATE_EVERY_FOURTH,
BH1745_UPDATE_EVERY_EIGHTH
} bh1745_persistence_t;
/**
* @brief Interrupt source settings.
*/
typedef enum
{
BH1745_RED_CHANNEL,
BH1745_GREEN_CHANNEL,
BH1745_BLUE_CHANNEL,
BH1745_CLEAR_CHANNEL
} bh1745_int_source_t;
/**
* @brief Measurement result.
*/
typedef struct
{
uint16_t red; //!< Raw red color value.
uint16_t green; //!< Raw green color value.
uint16_t blue; //!< Raw blue color value.
uint16_t clear; //!< Raw clear color pass value.
uint8_t valid; //!< Mode control 2 register value, used for checking data validity.
} bh1745_data_t;
/**
* @brief RGBC data callback prototype.
*
* @param result Result of operation (NRF_SUCCESS on success,
* otherwise a relevant error code).
* @param[in] p_user_data Pointer to color data structure.
*/
typedef void (* bh1745_data_callback_t)(ret_code_t result, bh1745_data_t * p_user_data);
/**
* @brief Macro that creates sensor instance.
*
* @param[in] _bh1745_inst_name Sensor instance name.
* @param[in] _p_twi_sensor Pointer to common TWI sensor instance. @ref NRF_TWI_SENSOR_DEF
* @param[in] _sensor_address Sensor base address.
*/
#define BH1745_INSTANCE_DEF(_bh1745_inst_name, _p_twi_sensor, _sensor_address) \
BH1745_INTERNAL_INSTANCE_DEF(_bh1745_inst_name, _p_twi_sensor, _sensor_address)
/**
* @brief Function for initializing the BH1745 sensor instance.
*
* TWI manager queue length has to be at least BH1745_MIN_QUEUE_SIZE.
*
* @param[in] p_instance Pointer to the sensor instance.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t bh1745_init(bh1745_instance_t * p_instance);
/**
* @brief Function for resetting the BH1745 registers.
*
* @param[in] p_instance Pointer to the sensor instance.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t bh1745_sw_reset(bh1745_instance_t * p_instance);
/**
* @brief Function for resetting the interrupt.
*
* @param[in] p_instance Pointer to the sensor instance.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t bh1745_int_reset(bh1745_instance_t * p_instance);
/**
* @brief Function for setting measurement configuration.
*
* @param[in] p_instance Pointer to the sensor instance.
* @param[in] meas_time Measurement time.
* @param[in] enable Enable RGBC measurements.
* @param[in] gain Measurement gain.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t bh1745_meas_cfg(bh1745_instance_t * p_instance,
bh1745_meas_time_t meas_time,
bool enable,
bh1745_gain_t gain);
/**
* @brief Function for setting interrupt configuration.
*
* @param p_instance Pointer to sensor instance.
* @param latch INT pin latch.
* @arg false INT pin is latched until INTERRUPT register is read or initialized.
* @arg true INT pin is updated after each measurement.
* @param source Interrupt source.
* @param enable Enable INT pin.
* @param persistence Set persistence.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t bh1745_int_cfg(bh1745_instance_t * p_instance,
bool latch,
bh1745_int_source_t source,
bool enable,
bh1745_persistence_t persistance);
/**
* @brief Function for setting high interrupt threshold.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] threshold Threshold value.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t bh1745_high_thr_set(bh1745_instance_t * p_instance,
uint16_t threshold);
/**
* @brief Function for setting low interrupt threshold.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] threshold Threshold value.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t bh1745_low_thr_set(bh1745_instance_t * p_instance,
uint16_t threshold);
/**
* @brief Function for getting the BH1745 data.
*
* @param[in] p_instance Pointer to the sensor instance.
* @param[in] user_callback Callback function created by user.
* @param[out] p_data The measurement results.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
ret_code_t bh1745_data_read(bh1745_instance_t * p_instance,
bh1745_data_callback_t user_callback,
bh1745_data_t * p_data);
/**
* @brief Function for reading system control register.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] user_cb Function to be called after register is read.
* @param[out] reg_val Register value, single uint8_t.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
__STATIC_INLINE ret_code_t bh1745_sys_ctrl_read(bh1745_instance_t * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * reg_val);
/**
* @brief Function for reading interrupt register.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] user_cb Function to be called after register is read.
* @param[out] reg_val Register value, single uint8_t.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
__STATIC_INLINE ret_code_t bh1745_interrupt_read(bh1745_instance_t * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * reg_val);
/**
* @brief Function for reading manufacturer id register.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] user_cb Function to be called after register is read.
* @param[out] reg_val Register value, single uint8_t.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
__STATIC_INLINE ret_code_t bh1745_manu_id_read(bh1745_instance_t * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * reg_val);
/**
* @brief Function for checking if RGBC data has been updated after last configuration change.
*
* This function should be used in data callback.
*
* @param[in] p_instance Pointer to the sensor instance.
*
* @return True if data is valid.
*/
__STATIC_INLINE bool bh1745_is_data_valid(bh1745_data_t * p_data);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE ret_code_t bh1745_sys_ctrl_read(bh1745_instance_t * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * reg_val)
{
ASSERT(p_instance != NULL);
return nrf_twi_sensor_reg_read(p_instance->p_sensor_data,
p_instance->sensor_addr,
BH1745_REG_SYSTEM_CONTROL,
user_cb,
reg_val,
1);
}
__STATIC_INLINE ret_code_t bh1745_interrupt_read(bh1745_instance_t * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * reg_val)
{
ASSERT(p_instance != NULL);
return nrf_twi_sensor_reg_read(p_instance->p_sensor_data,
p_instance->sensor_addr,
BH1745_REG_INTERRUPT,
user_cb,
reg_val,
1);
}
__STATIC_INLINE ret_code_t bh1745_manu_id_read(bh1745_instance_t * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * reg_val)
{
ASSERT(p_instance != NULL);
return nrf_twi_sensor_reg_read(p_instance->p_sensor_data,
p_instance->sensor_addr,
BH1745_REG_MANUFACTURER_ID,
user_cb,
reg_val,
1);
}
__STATIC_INLINE bool bh1745_is_data_valid(bh1745_data_t * p_data)
{
return NRF_TWI_SENSOR_REG_VAL_GET(p_data->valid,
BH1745_VALID_MASK,
BH1745_VALID_POS);
}
#endif //SUPPRESS_INLINE_IMPLEMENTATION
#ifdef __cplusplus
}
#endif
#endif // BH1745_H

View File

@@ -0,0 +1,180 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef BH1745_INTERNAL_H
#define BH1745_INTERNAL_H
#include "nrf_twi_sensor.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Possible sensor addresses.
*/
#define BH1745_BASE_ADDRESS_LOW 0x38U
#define BH1745_BASE_ADDRESS_HIGH 0x39U
#define BH1745_MIN_QUEUE_SIZE 5
/**
* @brief Sensor registers.
*/
#define BH1745_REG_SYSTEM_CONTROL 0x40
#define BH1745_REG_MODE_CONTROL1 0x41
#define BH1745_REG_MODE_CONTROL2 0x42
#define BH1745_REG_RED_DATA_LSB 0x50
#define BH1745_REG_DINT_DATA_LSB 0x58
#define BH1745_REG_INTERRUPT 0x60
#define BH1745_REG_PERSISTENCE 0x61
#define BH1745_REG_TH_LSB 0x62
#define BH1745_REG_TL_LSB 0x64
#define BH1745_REG_MANUFACTURER_ID 0x92
#define BH1745_DATA_REG_NUM 8
#define BH1745_MANU_ID 0xE0
#define BH1745_PART_ID 0x0B
/**
* @brief System Control register bitmasks.
*/
// Default value for system control register.
#define BH1745_DEF_SYSTEM_CONTROL 0x0B
// Bitmasks for sw reset.
#define BH1745_SW_RESET_POS 7
#define BH1745_SW_RESET_MASK (1 << BH1745_SW_RESET_POS)
// Bitmasks for int reset.
#define BH1745_INT_RESET_POS 6
#define BH1745_INT_RESET_MASK (1 << BH1745_INT_RESET_POS)
// Bitmasks for part id.
#define BH1745_PART_ID_POS 0
#define BH1745_PART_ID_MASK (0x3F << BH1745_PART_ID_POS)
/**
* @brief Mode Control 1 register bitmasks.
*/
// Bitmasks for meas time.
#define BH1745_MEAS_TIME_POS 0
#define BH1745_MEAS_TIME_MASK (0x07 << BH1745_MEAS_TIME_POS)
/**
* @brief Mode Control 2 register bitmasks.
*/
// Bitmasks for valid.
#define BH1745_VALID_POS 7
#define BH1745_VALID_MASK (1 << BH1745_VALID_POS)
// Bitmasks for rgbc en.
#define BH1745_RGBC_EN_POS 4
#define BH1745_RGBC_EN_MASK (1 << BH1745_RGBC_EN_POS)
// Bitmasks for adc gain.
#define BH1745_ADC_GAIN_POS 0
#define BH1745_ADC_GAIN_MASK (3 << BH1745_ADC_GAIN_POS)
/**
* @brief Interrupt register bitmasks.
*/
// Bitmasks for int status.
#define BH1745_INT_STATUS_POS 7
#define BH1745_INT_STATUS_MASK (1 << BH1745_INT_STATUS_POS)
// Bitmasks for int latch.
#define BH1745_INT_LATCH_POS 4
#define BH1745_INT_LATCH_MASK (1 << BH1745_INT_LATCH_POS)
// Bitmasks for int source.
#define BH1745_INT_SOURCE_POS 2
#define BH1745_INT_SOURCE_MASK (3 << BH1745_INT_SOURCE_POS)
// Bitmasks for int enable.
#define BH1745_INT_ENABLE_POS 0
#define BH1745_INT_ENABLE_MASK (1 << BH1745_INT_ENABLE_POS)
/**
* @brief Persistence register bitmasks.
*/
// Default value for persistence register.
#define BH1745_DEF_PERSISTENCE 0x01
// Bitmasks for persistence.
#define BH1745_PERSISTENCE_POS 0
#define BH1745_PERSISTENCE_MASK (3 << BH1745_PERSISTENCE_POS)
// Default value for high threshold registers.
#define BH1745_DEF_TH 0xFFFF
/**
* @brief Sensor instance information.
*/
typedef struct
{
nrf_twi_sensor_t * const p_sensor_data;
uint8_t const sensor_addr;
} bh1745_instance_t;
#define BH1745_INTERNAL_INSTANCE_DEF(_bh1745_inst_name, _p_twi_sensor, _sensor_address) \
static bh1745_instance_t _bh1745_inst_name = \
{ \
.p_sensor_data = _p_twi_sensor, \
.sensor_addr = _sensor_address \
}
#ifdef __cplusplus
}
#endif
#endif // BH1745_INTERNAL_H

View File

@@ -0,0 +1,225 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "ccs811.h"
#define SWAP_16(arg) ((arg) = (MSB_16(arg) | (LSB_16(arg) << 8)))
ret_code_t ccs811_init(ccs811_instance_t const * p_instance)
{
ASSERT(p_instance != NULL);
if (p_instance->p_sensor_data->p_twi_mngr->p_queue->size < CCS811_MIN_QUEUE_SIZE)
{
return NRF_ERROR_INVALID_LENGTH;
}
static uint8_t const send_msg[] = {
CCS811_REG_APP_START
};
ret_code_t err = nrf_twi_sensor_write(p_instance->p_sensor_data,
p_instance->sensor_addr,
send_msg,
ARRAY_SIZE(send_msg),
true);
err = ccs811_drive_mode_set(p_instance, CCS811_MODE_0, false, false);
if (err != NRF_SUCCESS)
{
return err;
}
err = ccs811_env_set(p_instance, CCS811_DEFAULT_TEMPERATURE, 0, CCS811_DEFAULT_HUMIDITY, 0);
if (err != NRF_SUCCESS)
{
return err;
}
return ccs811_thr_cfg(p_instance,
CCS811_DEFAULT_LOW_THR,
CCS811_DEFAULT_HIGH_THR,
CCS811_DEFAULT_HYSTERESIS);
}
ret_code_t ccs811_drive_mode_set(ccs811_instance_t const * p_instance,
ccs811_drive_mode_t mode,
bool drdy_en,
bool thr_en)
{
ASSERT(p_instance != NULL);
uint8_t reg = 0;
NRF_TWI_SENSOR_REG_SET(reg, CCS811_DRIVE_MODE_MASK, CCS811_DRIVE_MODE_POS, mode);
NRF_TWI_SENSOR_REG_SET(reg, CCS811_DATA_READY_MASK, CCS811_DATA_READY_POS, drdy_en);
NRF_TWI_SENSOR_REG_SET(reg, CCS811_THRESH_MASK, CCS811_THRESH_POS, thr_en);
uint8_t send_msg[] = {
CCS811_REG_MEAS_MODE,
reg
};
return nrf_twi_sensor_write(p_instance->p_sensor_data,
p_instance->sensor_addr,
send_msg,
ARRAY_SIZE(send_msg),
true);
}
ret_code_t ccs811_alg_data_read(ccs811_instance_t const * p_instance,
ccs811_data_callback_t user_cb,
ccs811_alg_data_t * p_alg_data,
ccs811_last_data_byte_t last)
{
ASSERT(p_instance != NULL);
ASSERT(p_alg_data != NULL);
return nrf_twi_sensor_reg_read(p_instance->p_sensor_data,
p_instance->sensor_addr,
CCS811_REG_ALG_RESULT_DATA,
(nrf_twi_sensor_reg_cb_t) user_cb,
(uint8_t *) p_alg_data,
last);
}
void ccs811_alg_data_process(ccs811_alg_data_t * p_alg_data)
{
ASSERT(p_alg_data != NULL);
SWAP_16(p_alg_data->eco2);
SWAP_16(p_alg_data->tvoc);
SWAP_16(p_alg_data->raw);
}
ret_code_t ccs811_env_set(ccs811_instance_t const * p_instance,
int8_t temp_value,
uint16_t temp_fraction,
uint8_t hum_percent,
uint16_t hum_fraction)
{
ASSERT(p_instance != NULL);
temp_value += CCS811_TEMPERATURE_OFFSET;
if(temp_value < 0)
{
temp_value = 0;
}
uint16_t env_temp = ( *((uint16_t *) &temp_value) << CCS811_ENV_TEMP_VALUE_POS)
| (temp_fraction & CCS811_ENV_TEMP_FRACTION_MASK);
uint16_t env_hum = ( *((uint16_t *) &hum_percent) << CCS811_ENV_HUM_PERCENT_POS)
| (hum_fraction & CCS811_ENV_HUM_FRACTION_MASK);
uint8_t send_msg[] = {
CCS811_REG_ENV_DATA,
MSB_16(env_temp),
LSB_16(env_temp),
MSB_16(env_hum),
LSB_16(env_hum)
};
return nrf_twi_sensor_write(p_instance->p_sensor_data,
p_instance->sensor_addr,
send_msg,
ARRAY_SIZE(send_msg),
true);
}
ret_code_t ccs811_thr_cfg(ccs811_instance_t const * p_instance,
uint16_t l_to_m,
uint16_t m_to_h,
uint8_t hysteresis)
{
ASSERT(p_instance != NULL);
uint8_t send_msg[] = {
CCS811_REG_THRESHOLDS,
MSB_16(l_to_m),
LSB_16(l_to_m),
MSB_16(m_to_h),
LSB_16(m_to_h),
hysteresis
};
return nrf_twi_sensor_write(p_instance->p_sensor_data,
p_instance->sensor_addr,
send_msg,
ARRAY_SIZE(send_msg),
true);
}
ret_code_t ccs811_baseline_read(ccs811_instance_t const * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint16_t * p_baseline)
{
ASSERT(p_instance != NULL);
ASSERT(p_baseline != NULL);
return nrf_twi_sensor_reg_read(p_instance->p_sensor_data,
p_instance->sensor_addr,
CCS811_REG_BASELINE,
user_cb,
(uint8_t *) p_baseline,
2);
}
ret_code_t ccs811_baseline_set(ccs811_instance_t const * p_instance, uint16_t baseline)
{
ASSERT(p_instance != NULL);
uint8_t * p_base = (uint8_t *) &baseline;
uint8_t send_msg[] = {
CCS811_REG_BASELINE,
p_base[0],
p_base[1]
};
return nrf_twi_sensor_write(p_instance->p_sensor_data,
p_instance->sensor_addr,
send_msg,
ARRAY_SIZE(send_msg),
true);
}
ret_code_t ccs811_sw_reset(ccs811_instance_t const * p_instance)
{
ASSERT(p_instance != NULL);
static uint8_t const send_msg[] = {
CCS811_REG_SW_RESET,
CCS811_SW_RESET_BYTE0,
CCS811_SW_RESET_BYTE1,
CCS811_SW_RESET_BYTE2,
CCS811_SW_RESET_BYTE3
};
return nrf_twi_sensor_write(p_instance->p_sensor_data,
p_instance->sensor_addr,
send_msg,
ARRAY_SIZE(send_msg),
true);
}

View File

@@ -0,0 +1,297 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef CCS811_H
#define CCS811_H
#include "nrf_twi_sensor.h"
#include "ccs811_internal.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Possible sensor addresses.
*/
#define CCS811_BASE_ADDRESS_LOW 0x5AU
#define CCS811_BASE_ADDRESS_HIGH 0x5BU
// Minimum nrf_twi_sensor message buffer size and nrf_twi_mngr queue length.
#define CCS811_MIN_QUEUE_SIZE 6
// Hardware ID register value
#define CCS811_HARDWARE_ID 0x81
/**
* @brief Sensor driver usage.
*
* Sensor instance has to be defined first in global context using @ref CCS811_INSTANCE_DEF.
* After that it has to be initialized using @ref ccs811_init.
* At this point sensor instance is ready and all other functions can be used.
*
* Configuration functions schedule TWI operation using @ref nrf_twi_sensor module.
* After calling function, setting will be automatically send to sensor when TWI bus is free.
*
* There are designated functions to read status sensor registers e.g. @ref ccs811_status_read
* As parameters they receive function to be called after register is read, and pointer where
* register value should be stored. From that value specific parameters can be extracted
* using @ref NRF_TWI_SENSOR_REG_VAL_GET macro.
* Example:
* bool drdy = NRF_TWI_SENSOR_REG_VAL_GET(status, CCS811_DATA_READY_MASK, CCS811_DATA_READY_POS);
*
* Other functions are self-explanatory or have description on their usage.
*/
/**
* @brief Drive mode setting.
*/
typedef enum
{
CCS811_MODE_0,//!< CCS811_MODE_0 - Idle
CCS811_MODE_1,//!< CCS811_MODE_1 - Constant power, measure every second.
CCS811_MODE_2,//!< CCS811_MODE_2 - Pulse heating mode, measure every 10 seconds.
CCS811_MODE_3,//!< CCS811_MODE_3 - Low power pulse heating mode, measure every 60 seconds.
CCS811_MODE_4 //!< CCS811_MODE_4 - Constant power, measure every 250ms, only raw data.
} ccs811_drive_mode_t;
/**
* @brief Last byte read from algorithm data.
*
* Used with @ref ccs811_alg_data_read function, defines to which byte data should be read.
*/
typedef enum
{
CCS811_LAST_ECO2 = 2,
CCS811_LAST_TVOC = 4,
CCS811_LAST_STATUS,
CCS811_LAST_ERROR_ID,
CCS811_LAST_RAW = 8
} ccs811_last_data_byte_t;
/**
* @brief Structure for holding algorithm data.
*/
typedef struct
{
uint16_t eco2; //!< eC02 value in ppm.
uint16_t tvoc; //!< TVOC value in ppb.
uint8_t status; //!< Status register data.
uint8_t error_id; //!< Error register data.
uint16_t raw; //!< Raw data.
} ccs811_alg_data_t;
/**
* @brief Data callback prototype.
*
* @param[in] result Return code from TWI manager and underlying drivers.
* @param[in] p_data Pointer to sensor data.
*/
typedef void (* ccs811_data_callback_t)(ret_code_t result, ccs811_alg_data_t * p_data);
/**
* @brief Macro that creates sensor instance.
*
* @param[in] _ccs811_inst_name Sensor instance name.
* @param[in] _p_twi_sensor Pointer to common TWI sensor instance.
* @param[in] _sensor_address Sensor base address.
*/
#define CCS811_INSTANCE_DEF(_ccs811_inst_name, _p_twi_sensor, _sensor_address) \
CCS811_INTERNAL_INSTANCE_DEF(_ccs811_inst_name, _p_twi_sensor, _sensor_address)
/**
* @brief Function initializing ccs811 sensor
*
* TWI manager queue length has to be at least CCS811_MIN_QUEUE_SIZE
*
* @param[in] p_instance Pointer to sensor instance created by macro
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t ccs811_init(ccs811_instance_t const * p_instance);
/**
* @brief Function for setting drive mode.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] mode Drive mode.
* @param[in] drdy_en Enable data ready pin.
* @param[in] thr_en Enable threshold.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t ccs811_drive_mode_set(ccs811_instance_t const * p_instance,
ccs811_drive_mode_t mode,
bool drdy_en,
bool thr_en);
/**
* @brief Function for reading sensor data.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] user_cb Function to be called after data read.
* @param[out] p_alg_data Pointer to structure holding sensor algorithm data.
* @param[in] last Last byte to read.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
ret_code_t ccs811_alg_data_read(ccs811_instance_t const * p_instance,
ccs811_data_callback_t user_cb,
ccs811_alg_data_t * p_alg_data,
ccs811_last_data_byte_t last);
/**
* @brief Function for processing algorithm data
*
* @param[in/out] p_alg_data Pointer to read data to be processed.
*/
void ccs811_alg_data_process(ccs811_alg_data_t * p_alg_data);
/**
* @brief Function for setting environment temperature.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] temp_value Temperature value (-25 to 100 degree celsius).
* @param[in] temp_fraction Temperature fraction.
* @param[in] hum_percent Humidity percent.
* @param[in] hum_fraction Humidity fraction.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t ccs811_env_set(ccs811_instance_t const * p_instance,
int8_t temp_value,
uint16_t temp_fraction,
uint8_t hum_percent,
uint16_t hum_fraction);
/**
* @brief Function for threshold configuration
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] l_to_m Low to medium threshold.
* @param[in] m_to_h Medium to high threshold.
* @param[in] hysteresis Hysteresis.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t ccs811_thr_cfg(ccs811_instance_t const * p_instance,
uint16_t l_to_m,
uint16_t m_to_h,
uint8_t hysteresis);
/**
* @brief Function for reading baseline.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] user_cb Function to be called after baseline read.
* @param[out] baseline Baseline value, single uint16_t.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
ret_code_t ccs811_baseline_read(ccs811_instance_t const * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint16_t * p_baseline);
/**
* @brief Function for setting baseline.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] baseline Baseline value.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t ccs811_baseline_set(ccs811_instance_t const * p_instance,
uint16_t baseline);
/**
* @brief Function commencing software reset.
*
* @param[in] p_instance Pointer to sensor instance.
*
* @note To use sensor after reset, it has to be initialized again using @ref ccs811_init function.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t ccs811_sw_reset(ccs811_instance_t const * p_instance);
/**
* @brief Function for reading status register.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] user_cb Function to be called after register is read.
* @param[out] p_reg_val Pointer to register value, single uint8_t.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
__STATIC_INLINE ret_code_t ccs811_status_read(ccs811_instance_t const * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * p_reg_val);
/**
* @brief Function for reading hardware id register.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] user_cb Function to be called after register is read.
* @param[out] p_reg_val Pointer to register value, single uint8_t.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
__STATIC_INLINE ret_code_t ccs811_hw_id_read(ccs811_instance_t const * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * p_reg_val);
/**
* @brief Function for reading error id register.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] user_cb Function to be called after register is read.
* @param[out] p_reg_val Pointer to register value, single uint8_t.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
__STATIC_INLINE ret_code_t ccs811_error_read(ccs811_instance_t const * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * p_reg_val);
#ifdef __cplusplus
}
#endif
#endif // CCS811_H

View File

@@ -0,0 +1,259 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef CCS811_INTERNAL_H
#define CCS811_INTERNAL_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief CCS811 sensor registers.
*/
#define CCS811_REG_STATUS 0x00
#define CCS811_REG_MEAS_MODE 0x01
#define CCS811_REG_ALG_RESULT_DATA 0x02
#define CCS811_REG_RAW_DATA 0x03
#define CCS811_REG_ENV_DATA 0x05
#define CCS811_REG_NTC 0x06
#define CCS811_REG_THRESHOLDS 0x10
#define CCS811_REG_BASELINE 0x11
#define CCS811_REG_HW_ID 0x20
#define CCS811_REG_HW_VER 0x21
#define CCS811_REG_FW_BOOT_VER 0x23
#define CCS811_REG_FW_APP_VER 0x24
#define CCS811_REG_ERROR_ID 0xE0
#define CCS811_REG_SW_RESET 0xFF
#define CCS811_REG_APP_START 0xF4
/**
* @brief CCS811 Default configuration values.
*/
#define CCS811_DEFAULT_HUMIDITY 50
#define CCS811_DEFAULT_TEMPERATURE 25
#define CCS811_DEFAULT_LOW_THR 1500
#define CCS811_DEFAULT_HIGH_THR 2500
#define CCS811_DEFAULT_HYSTERESIS 50
/**
* @brief CCS811 Environment temperature offset.
*/
#define CCS811_TEMPERATURE_OFFSET 25
/**
* @brief Status register bitmasks.
*/
// Bitmasks for FW_MODE.
#define CCS811_FW_MODE_POS 7
#define CCS811_FW_MODE_MASK (1 << CCS811_FW_MODE_POS)
// Bitmasks for APP_VALID.
#define CCS811_APP_VALID_POS 4
#define CCS811_APP_VALID_MASK (1 << CCS811_APP_VALID_POS)
// Bitmasks for DATA_READY.
#define CCS811_DATA_READY_POS 3
#define CCS811_DATA_READY_MASK (1 << CCS811_DATA_READY_POS)
// Bitmasks for ERROR.
#define CCS811_ERROR_POS 0
#define CCS811_ERROR_MASK (1 << CCS811_ERROR_POS)
/**
* @brief Meas mode register bitmasks.
*/
// Register validity mask.
#define CCS811_MEAS_MODE_VALID_MASK 0x83U
// Bitmasks for DRIVE_MODE.
#define CCS811_DRIVE_MODE_POS 4
#define CCS811_DRIVE_MODE_MASK (7 << CCS811_DRIVE_MODE_POS)
// Bitmasks for INTERRUPT.
#define CCS811_INTERRUPT_POS 3
#define CCS811_INTERRUPT_MASK (1 << CCS811_INTERRUPT_MASK)
// Bitmasks for THRESH.
#define CCS811_THRESH_POS 2
#define CCS811_THRESH_MASK (1 << CCS811_THRESH_POS)
/**
* @brief Algorithm results data bytes.
*/
#define CCS811_ALG_RESULT_BYTE_NUM 8
#define CCS811_ALG_ECO2_H_BYTE 0
#define CCS811_ALG_ECO2_L_BYTE 1
#define CCS811_ALG_TVOC_H_BYTE 2
#define CCS811_ALG_TVOC_L_BYTE 3
#define CCS811_ALG_STATUS_BYTE 4
#define CCS811_ALG_ERROR_BYTE 5
#define CCS811_ALG_RAW_DATA1_BYTE 6
#define CCS811_ALG_RAW_DATA2_BYTE 7
/**
* @brief Environment data register.
*/
#define CCS811_ENV_HUMIDITY_H_BYTE 0
// Humidity percent position.
#define CCS811_ENV_HUM_PERCENT_POS 9
// Bitmasks for humidity fraction.
#define CCS811_ENV_HUM_FRACTION_MASK (0x01FF)
// Temperature value position.
#define CCS811_ENV_TEMP_VALUE_POS 9
// Bitmasks for temperature fraction.
#define CCS811_ENV_TEMP_FRACTION_MASK (0x01FF)
/**
* @brief Error register.
*/
// Bitmasks for HEATER_SUPPLY
#define CCS811_ERROR_HEATER_SUPPLY_POS 5
#define CCS811_ERROR_HEATER_SUPPLY_MASK (1 << CCS811_ERROR_HEATER_SUPPLY_POS)
// Bitmasks for HEATER_FAULT
#define CCS811_ERROR_HEATER_FAULT_POS 4
#define CCS811_ERROR_HEATER_FAULT_MASK (1 << CCS811_ERROR_HEATER_FAULT_POS)
// Bitmasks for MAX_RESISTANCE
#define CCS811_ERROR_MAX_RESISTANCE_POS 3
#define CCS811_ERROR_MAX_RESISTANCE_MASK (1 << CCS811_ERROR_MAX_RESISTANCE_POS)
// Bitmasks for MEASMODE_INVALID
#define CCS811_ERROR_MEAS_MODE_POS 2
#define CCS811_ERROR_MEAS_MODE_MASK (1 CCS811_ERROR_MEAS_MODE_POS)
// Bitmasks for READ_REG
#define CCS811_ERROR_READ_REG_POS 1
#define CCS811_ERROR_READ_REG_MASK (1 << CCS811_ERROR_READ_REG_POS)
// Bitmasks for WRITE_REG
#define CCS811_ERROR_WRITE_REG_POS 0
#define CCS811_ERROR_WRITE_REG_MASK (1 << CCS811_ERROR_WRITE_REG_POS)
/**
* @brief Software reset register.
*/
#define CCS811_SW_RESET_BYTE0 0x11
#define CCS811_SW_RESET_BYTE1 0xE5
#define CCS811_SW_RESET_BYTE2 0x72
#define CCS811_SW_RESET_BYTE3 0x8A
/**
* @brief Structure holding sensor instance
*/
typedef struct
{
nrf_twi_sensor_t * const p_sensor_data;
uint8_t const sensor_addr;
} ccs811_instance_t;
/**
* @brief Macro that creates sensor instance.
*/
#define CCS811_INTERNAL_INSTANCE_DEF(_ccs811_inst_name, _p_twi_sensor, _sensor_address) \
static ccs811_instance_t _ccs811_inst_name = \
{ \
.p_sensor_data = _p_twi_sensor, \
.sensor_addr = _sensor_address, \
}
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE ret_code_t ccs811_status_read(ccs811_instance_t const * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * p_reg_val)
{
ASSERT(p_instance != NULL);
ASSERT(p_reg_val != NULL);
return nrf_twi_sensor_reg_read(p_instance->p_sensor_data,
p_instance->sensor_addr,
CCS811_REG_STATUS,
user_cb,
p_reg_val,
1);
}
__STATIC_INLINE ret_code_t ccs811_hw_id_read(ccs811_instance_t const * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * p_reg_val)
{
ASSERT(p_instance != NULL);
ASSERT(p_reg_val != NULL);
return nrf_twi_sensor_reg_read(p_instance->p_sensor_data,
p_instance->sensor_addr,
CCS811_REG_HW_ID,
user_cb,
p_reg_val,
1);
}
__STATIC_INLINE ret_code_t ccs811_error_read(ccs811_instance_t const * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * p_reg_val)
{
ASSERT(p_instance != NULL);
ASSERT(p_reg_val != NULL);
return nrf_twi_sensor_reg_read(p_instance->p_sensor_data,
p_instance->sensor_addr,
CCS811_REG_ERROR_ID,
user_cb,
p_reg_val,
1);
}
#endif //SUPPRESS_INLINE_IMPLEMENTATION
#ifdef __cplusplus
}
#endif
#endif // CCS811_INTERNAL_H

View File

@@ -0,0 +1,474 @@
/**
* Copyright (c) 2009 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <stdint.h>
#include <stdbool.h>
#include "cherry8x16.h"
#include "nrf.h"
#define CHERRY8x16_NUM_OF_COLUMNS 16 // !< Number of columns in the keyboard matrix
#define CHERRY8x16_NUM_OF_ROWS 8 // !< Number of rows in the keyboard matrix
#define MODIFIER_HID_START 0xE0
#define MODIFIER_HID_END 0xE7
static uint8_t m_currently_pressed_keys[CHERRY8x16_MAX_NUM_OF_PRESSED_KEYS]; //!< Array holding currently pressed keys. Filled up from index 0. Values are
static uint8_t m_transmitted_keys[CHERRY8x16_MAX_NUM_OF_PRESSED_KEYS]; //!< Array holding the keys that have already been transmitted.
static uint8_t m_num_of_currently_pressed_keys; //!< Number of keys in m_currently_pressed_keys
static uint8_t m_number_of_transmitted_keys; //!< Number of keys in m_transmitted_keys
static uint8_t m_key_packet[KEY_PACKET_SIZE]; //!< Stores last created key packet. One byte is used for modifier keys, one for OEMs. Key values are USB HID keycodes.
static const uint8_t volatile * m_row_port; //!< Pointer to location where row IO can be read
static uint16_t volatile * m_column_port; //!< Pointer to location where column IO can be written
static const uint8_t * matrix_lookup; //!< Pointer to the key lookup matrix in use
/** Table containing the mapping between the key matrix and the HID Usage codes for each key. */
static const uint8_t default_matrix_lookup[CHERRY8x16_NUM_OF_COLUMNS * CHERRY8x16_NUM_OF_ROWS] =
{
0xE7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xE1, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xE2, 0xE5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x29, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x3F, 0x40,
0x1E, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x24, 0x25,
0x4F, 0x43, 0x47, 0x53, 0x46, 0x48, 0x42, 0x41,
0x51, 0x2D, 0x2E, 0x2A, 0x00, 0x4A, 0x27, 0x26,
0x52, 0x13, 0x2F, 0x30, 0x00, 0x4B, 0x12, 0x0C,
0x50, 0x33, 0x34, 0x32, 0x28, 0x4E, 0x0F, 0x0E,
0x2C, 0x38, 0x4C, 0x49, 0x65, 0x4D, 0x37, 0x36,
0x35, 0x05, 0x19, 0x06, 0x1B, 0x1D, 0x11, 0x10,
0x39, 0x0A, 0x09, 0x07, 0x16, 0x04, 0x0B, 0x0D,
0x2B, 0x17, 0x15, 0x08, 0x1A, 0x14, 0x1C, 0x18
};
static bool cherry8x16_have_keys_changed(const uint8_t * state_now,
uint8_t number_of_now_pressed_keys,
const uint8_t * state_before,
uint8_t number_of_before_pressed_keys);
static bool cherry8x16_keymatrix_read(uint8_t * pressed_keys, uint8_t * number_of_pressed_keys);
static void cherry8x16_keypacket_addkey(uint8_t key);
static void cherry8x16_keypacket_create(uint8_t * key_packet, uint8_t key_packet_size);
static void cherry8x16_remap_fn_keys(uint8_t * keys, uint8_t number_of_keys);
static uint8_t cherry8x16_row_read(void);
cherry8x16_status_t cherry8x16_init(const uint8_t volatile * row_port,
uint16_t * column_port,
const uint8_t * key_lookup_matrix)
{
cherry8x16_status_t status = CHERRY8x16_OK;
if (row_port == 0 || column_port == 0)
{
status = CHERRY8x16_INVALID_PARAMETER;
}
else
{
m_row_port = row_port;
m_column_port = column_port;
*m_column_port = 0x0000;
if (*m_row_port != 0x00)
{
status = CHERRY8x16_NOT_DETECTED;
}
else
{
m_num_of_currently_pressed_keys = 0;
m_number_of_transmitted_keys = 0;
for (uint_fast8_t i = CHERRY8x16_MAX_NUM_OF_PRESSED_KEYS; i--;)
{
m_currently_pressed_keys[i] = 0;
m_transmitted_keys[i] = 0;
}
}
if (key_lookup_matrix == CHERRY8x16_DEFAULT_KEY_LOOKUP_MATRIX)
{
matrix_lookup = default_matrix_lookup;
}
else
{
matrix_lookup = key_lookup_matrix;
}
}
return status;
}
bool cherry8x16_new_packet(const uint8_t ** p_key_packet, uint8_t * p_key_packet_size)
{
bool new_packet_prepared;
// Save currently pressed keys
for (uint_fast8_t i = CHERRY8x16_MAX_NUM_OF_PRESSED_KEYS; i--; )
{
m_transmitted_keys[i] = m_currently_pressed_keys[i];
}
m_number_of_transmitted_keys = m_num_of_currently_pressed_keys;
// Create a new packet if key states have changed and there are no keys blocking each other (ghosting/phantom keys)
if (cherry8x16_keymatrix_read(m_currently_pressed_keys, &m_num_of_currently_pressed_keys))
{
if (cherry8x16_have_keys_changed(m_currently_pressed_keys, m_num_of_currently_pressed_keys,
m_transmitted_keys, m_number_of_transmitted_keys))
{
cherry8x16_keypacket_create(&m_key_packet[0], KEY_PACKET_SIZE);
*p_key_packet = &m_key_packet[0];
*p_key_packet_size = KEY_PACKET_SIZE;
new_packet_prepared = true;
}
else
{
// The same keys are still pressed, no need to create a new packet
new_packet_prepared = false;
}
}
else
{
// Ghosting detected. Don't create a packet.
new_packet_prepared = false;
}
return new_packet_prepared;
}
/**
* @brief Function for reading and returning keyboard matrix row state.
*
* @return uint8_t Row state
*/
static uint8_t cherry8x16_row_read(void)
{
return *m_row_port;
}
/**
* @brief Function for reading the keyboard matrix state and stores the pressed keys to an array.
*
* This function resolves keys from the matrix and finds their corresponding HID usage codes
* If there are any ghost key conditions the packet will be discarded
* @param pressed_keys Array holding pressed keys. Must be at least CHERRY8x16_MAX_NUM_OF_PRESSED_KEYS in size.
* @param number_of_pressed_keys Pointer to variable where number of pressed keys will be stored.
* @return
* @retval true If no keys were blocking each other.
* @retval false If some keys were blocking each other o rno key is pressed.
*/
static bool cherry8x16_keymatrix_read(uint8_t * pressed_keys, uint8_t * number_of_pressed_keys)
{
uint_fast8_t row_state[CHERRY8x16_NUM_OF_COLUMNS];
uint_fast8_t blocking_mask = 0;
*number_of_pressed_keys = 0;
for (uint_fast8_t column = CHERRY8x16_NUM_OF_COLUMNS; column--;)
{
// drive column under test
*m_column_port = (uint16_t)(1UL << column);
row_state[column] = cherry8x16_row_read();
// Check if any keys are pressed
if (row_state[column] != 0)
{
uint_fast8_t detected_keypresses_on_column = 0;
// Loop through rows, check for active rows and add pressed keys to the array
for (uint_fast8_t row = CHERRY8x16_NUM_OF_ROWS; row--;)
{
if (row_state[column] & (1U << row))
{
if (*number_of_pressed_keys < CHERRY8x16_MAX_NUM_OF_PRESSED_KEYS)
{
*pressed_keys = matrix_lookup[column * CHERRY8x16_NUM_OF_ROWS + row];
pressed_keys++;
(*number_of_pressed_keys)++;
}
detected_keypresses_on_column++;
}
}
if (detected_keypresses_on_column > 1)
{
if (blocking_mask & row_state[column])
{
// Cannot determine reliably all pressed keys, two or more keys are blocking each other.
return false;
}
}
blocking_mask |= row_state[column];
}
}
return true;
}
/**
* @brief Function for remapping the keypad, F11 and F12 keys in case when Fn key is pressed.
*
* @param keys Array holding pressed keys.
* @param number_of_keys Number of elements if 'keys' array.
*/
static void cherry8x16_remap_fn_keys(uint8_t * keys, uint8_t number_of_keys)
{
/*lint -e845 -save // A zero has been given as right argument to operator '<<'" */
/*lint -e778 -save // Constant expression evaluates to zero */
#define MODIFIER_LEFT_CONTROL_HID 0xE0
#define MODIFER_RIGHT_CONTROL_HID 0xE4
// Check if Fn key is pressed along with any other modifier key (only usage now is Fn + Left_Ctrl = Right Ctrl)
// So we modify the modifier byte if Fn + Left_Ctrl is pressed, HID for left_Ctrl = 0xE0
if ( keys[0] & (1UL << (MODIFIER_LEFT_CONTROL_HID - MODIFIER_HID_START)) )
{
keys[0] &= ~(1UL << (MODIFIER_LEFT_CONTROL_HID - MODIFIER_HID_START));
keys[0] |= (1UL << (MODIFER_RIGHT_CONTROL_HID - MODIFIER_HID_START));
}
/*lint -restore */
/*lint -restore */
for (uint_fast8_t i = 2; i < number_of_keys; i++)
{
switch (keys[i])
{
case 0x10: // 'M'
keys[i] = 0x62; // Keypad 0
break;
case 0x37: // '>'
keys[i] = 0x63; // Keypad .
break;
case 0x38: // '/'
keys[i] = 0x54; // Keypad /
break;
case 0x0D: // 'J'
keys[i] = 0x59; // Keypad 1
break;
case 0x0E: // 'K'
keys[i] = 0x5A; // Keypad 2
break;
case 0x0F: // 'L'
keys[i] = 0x5B; // Keypad 3
break;
case 0x33: // ''
keys[i] = 0x57; // Keypad +
break;
case 0x28: // 'Enter'
keys[i] = 0x58; // Keypad enter
break;
case 0x18: // 'U'
keys[i] = 0x5C; // Keypad 4
break;
case 0x0C: // 'I'
keys[i] = 0x5D; // Keypad 5
break;
case 0x12: // 'O'
keys[i] = 0x5E; // Keypad 6
break;
case 0x13: // 'P'
keys[i] = 0x56; // Keypad -
break;
case 0x24: // '7'
keys[i] = 0x5F; // Keypad 7
break;
case 0x25: // '8'
keys[i] = 0x60; // Keypad 8
break;
case 0x26: // '9'
keys[i] = 0x61; // Keypad 9
break;
case 0x27: // '0'
keys[i] = 0x55; // Keypad *
break;
case 0x3A: // 'F1'
keys[i] = 0x44; // 'F11'
break;
case 0x3B: // 'F2'
keys[i] = 0x45; // 'F12'
break;
default:
break;
}
}
}
/**
* @brief Function for determining whether the keyboard matrix state has changed compared to the state before.
*
* @param state_now List of pressed keys in current state
* @param number_of_now_pressed_keys Number of pressed keys in current state
* @param state_before List of pressed keys in previous state
* @param number_of_before_pressed_keys Number of pressed keys in previous state
* @return
* @retval true If keyboard matrix is different compared to state before.
* @retval false If keyboard matrix is the same compared to state before.
*/
static bool cherry8x16_have_keys_changed(const uint8_t * state_now,
uint8_t number_of_now_pressed_keys,
const uint8_t * state_before,
uint8_t number_of_before_pressed_keys)
{
if (number_of_now_pressed_keys != number_of_before_pressed_keys)
{
return true;
}
else
{
for (uint_fast8_t i = number_of_now_pressed_keys; i--;)
{
if (state_now[i] != state_before[i])
{
return true;
}
}
}
return false;
}
/**
* @brief Function for adding a key to the key packet.
*
* If key is found to be in the packet, it will not be added twice.
* Attempts to add more keys than the buffer capacity allows will be silently ignored.
*
* @param key Key to add
*/
static void cherry8x16_keypacket_addkey(uint8_t key)
{
for (uint_fast8_t i = KEY_PACKET_KEY_INDEX; i < KEY_PACKET_SIZE; i++)
{
if (m_key_packet[i] == key)
{
return;
}
}
for (uint_fast8_t i = KEY_PACKET_KEY_INDEX; i < KEY_PACKET_SIZE; i++)
{
if (m_key_packet[i] == KEY_PACKET_NO_KEY)
{
m_key_packet[i] = key;
return;
}
}
}
/**
* @brief Function for creating a new key packet.
*
* This function uses @ref m_currently_pressed_keys to determine pressed keys.
* Priority is given to those keys that were found in the previous packet.
* All modifier keys can be found in all packets.
* If Fn key is detected to be pressed, some keys are remapped to different functions.
*
* @param key_packet Pointer to location where packet contents will be put
* @param key_packet_size Key packet size in bytes
*/
static void cherry8x16_keypacket_create(uint8_t * key_packet, uint8_t key_packet_size)
{
// Clear key_packet contents
for (uint_fast8_t i = KEY_PACKET_KEY_INDEX; i < key_packet_size; i++)
{
key_packet[i] = KEY_PACKET_NO_KEY;
}
key_packet[KEY_PACKET_MODIFIER_KEY_INDEX] = 0;
key_packet[KEY_PACKET_RESERVED_INDEX] = 0;
// Give priority to keys that were already pressed when we transmitted them the last time.
for (uint_fast8_t i = 0; i < m_number_of_transmitted_keys; i++)
{
for (uint_fast8_t j = 0; j < m_num_of_currently_pressed_keys; j++)
{
if (m_transmitted_keys[i] == m_currently_pressed_keys[j])
{
cherry8x16_keypacket_addkey(m_currently_pressed_keys[j]);
break;
}
}
}
bool fn_key_is_set = false;
// Detect if Fn is pressed, detect modifier keys, and add rest of the keys to the packet
for (uint_fast8_t i = 0; i < m_num_of_currently_pressed_keys; i++)
{
if (m_currently_pressed_keys[i] == 0xFF) // Pressing Fn key changes function of certain keys and it must handled by the firmware
{
fn_key_is_set = true;
}
// Modifier HID usage codes are from 0xE0 to 0xE7
else if (m_currently_pressed_keys[i] >= MODIFIER_HID_START && m_currently_pressed_keys[i] <= MODIFIER_HID_END) // Detect and set modifier keys
{
key_packet[KEY_PACKET_MODIFIER_KEY_INDEX] |= (uint8_t)(1U << (m_currently_pressed_keys[i] - MODIFIER_HID_START));
}
else if (m_currently_pressed_keys[i] != 0)
{
cherry8x16_keypacket_addkey(m_currently_pressed_keys[i]);
}
}
if (fn_key_is_set)
{
cherry8x16_remap_fn_keys(&key_packet[0], KEY_PACKET_MAX_KEYS);
}
}

View File

@@ -0,0 +1,119 @@
/**
* Copyright (c) 2009 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef CHERRY8x16_H
#define CHERRY8x16_H
/*lint ++flb "Enter library region" */
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @file
* @brief Cherry 8x16 keyboard matrix driver
*
*
* @defgroup nrf_drivers_cherry8x16 Cherry 8x16 keyboard matrix driver
* @{
* @ingroup ext_drivers
* @brief Cherry 8x16 keyboard matrix driver.
*/
#define CHERRY8x16_MAX_NUM_OF_PRESSED_KEYS 6 //!< Maximum number of pressed keys kept in buffers
#define CHERRY8x16_DEFAULT_KEY_LOOKUP_MATRIX (const uint8_t*)0 //!< If passed to @ref cherry8x16_init, default lookup matrix will be used
#define KEY_PACKET_MODIFIER_KEY_INDEX (0) //!< Index in the key packet where modifier keys such as ALT and Control are stored
#define KEY_PACKET_RESERVED_INDEX (1) //!< Index in the key packet where OEMs can store information
#define KEY_PACKET_KEY_INDEX (2) //!< Start index in the key packet where pressed keys are stored
#define KEY_PACKET_MAX_KEYS (6) //!< Maximum number of keys that can be stored into the key packet
#define KEY_PACKET_SIZE (KEY_PACKET_KEY_INDEX + KEY_PACKET_MAX_KEYS) //!< Total size of the key packet in bytes
#define KEY_PACKET_NO_KEY (0) //!< Value to be stored to key index to indicate no key is pressed
/**
* Describes return values for:
* @ref cherry8x16_init
*/
typedef enum
{
CHERRY8x16_OK, /*!< Operation was succesful. */
CHERRY8x16_NOT_DETECTED, /*!< Product/Revision ID was not what was expected */
CHERRY8x16_INVALID_PARAMETER /*!< Given parameters were not valid */
} cherry8x16_status_t;
/**
* @brief Function for initializing the driver.
*
* @note Before calling this function, setup row_port as IO inputs with pulldowns enabled and column_port as IO outputs.
*
* @param row_port Pointer to GPIO port address that is used as key matrix row input.
* @param column_port Pointer to GPIO port address that is used as key matrix column output.
* @param key_lookup_matrix If NULL, use a default key lookup matrix. Otherwise pointer to a 128 (8x16) element array containing HID keycodes.
* @return
* @retval CHERRY8X16_OK Peripheral was initialized succesfully.
* @retval CHERRY8X16_NOT_DETECTED Could not detect the peripheral.
*/
cherry8x16_status_t cherry8x16_init(const uint8_t volatile * row_port, uint16_t * column_port, const uint8_t * key_lookup_matrix);
/**
* @brief Function for creating a new key packet if new data is available and key ghosting is not detected.
*
* @param p_key_packet Array that will hold the created key packet. Previously created packet will be discarded.
* @param p_key_packet_size Key packet size in bytes.
* @return
* @retval true If new packet was created.
* @retval false If packet was not created.
*/
bool cherry8x16_new_packet(const uint8_t ** p_key_packet, uint8_t *p_key_packet_size);
/**
*@}
**/
/*lint --flb "Leave library region" */
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,154 @@
/**
* Copyright (c) 2012 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "ds1624.h"
#include "twi_master.h"
#include "nrf_delay.h"
/*lint ++flb "Enter library region" */
#define DS1634_BASE_ADDRESS 0x90 //!< 4 MSBs of the DS1624 TWI address
#define DS1624_ONESHOT_MODE 0x01 //!< Bit in configuration register for 1-shot mode
#define DS1624_CONVERSION_DONE 0x80 //!< Bit in configuration register to indicate completed temperature conversion
static uint8_t m_device_address; //!< Device address in bits [7:1]
const uint8_t command_access_memory = 0x17; //!< Reads or writes to 256-byte EEPROM memory
const uint8_t command_access_config = 0xAC; //!< Reads or writes configuration data to configuration register
const uint8_t command_read_temp = 0xAA; //!< Reads last converted temperature value from temperature register
const uint8_t command_start_convert_temp = 0xEE; //!< Initiates temperature conversion.
const uint8_t command_stop_convert_temp = 0x22; //!< Halts temperature conversion.
/**
* @brief Function for reading the current configuration of the sensor.
*
* @return uint8_t Zero if communication with the sensor failed. Contents (always non-zero) of configuration register (@ref DS1624_ONESHOT_MODE and @ref DS1624_CONVERSION_DONE) if communication succeeded.
*/
static uint8_t ds1624_config_read(void)
{
uint8_t config = 0;
// Write: command protocol
if (twi_master_transfer(m_device_address, (uint8_t*)&command_access_config, 1, TWI_DONT_ISSUE_STOP))
{
if (twi_master_transfer(m_device_address | TWI_READ_BIT, &config, 1, TWI_ISSUE_STOP)) // Read: current configuration
{
// Read succeeded, configuration stored to variable "config"
}
else
{
// Read failed
config = 0;
}
}
return config;
}
bool ds1624_init(uint8_t device_address)
{
bool transfer_succeeded = true;
m_device_address = DS1634_BASE_ADDRESS + (uint8_t)(device_address << 1);
uint8_t config = ds1624_config_read();
if (config != 0)
{
// Configure DS1624 for 1SHOT mode if not done so already.
if (!(config & DS1624_ONESHOT_MODE))
{
uint8_t data_buffer[2];
data_buffer[0] = command_access_config;
data_buffer[1] = DS1624_ONESHOT_MODE;
transfer_succeeded &= twi_master_transfer(m_device_address, data_buffer, 2, TWI_ISSUE_STOP);
}
}
else
{
transfer_succeeded = false;
}
return transfer_succeeded;
}
bool ds1624_start_temp_conversion(void)
{
return twi_master_transfer(m_device_address, (uint8_t*)&command_start_convert_temp, 1, TWI_ISSUE_STOP);
}
bool ds1624_is_temp_conversion_done(void)
{
uint8_t config = ds1624_config_read();
if (config & DS1624_CONVERSION_DONE)
{
return true;
}
else
{
return false;
}
}
bool ds1624_temp_read(int8_t * temperature_in_celcius, int8_t * temperature_fraction)
{
bool transfer_succeeded = false;
// Write: Begin read temperature command
if (twi_master_transfer(m_device_address, (uint8_t*)&command_read_temp, 1, TWI_DONT_ISSUE_STOP))
{
uint8_t data_buffer[2];
// Read: 2 temperature bytes to data_buffer
if (twi_master_transfer(m_device_address | TWI_READ_BIT, data_buffer, 2, TWI_ISSUE_STOP))
{
*temperature_in_celcius = (int8_t)data_buffer[0];
*temperature_fraction = (int8_t)data_buffer[1];
transfer_succeeded = true;
}
}
return transfer_succeeded;
}
/*lint --flb "Leave library region" */

View File

@@ -0,0 +1,113 @@
/**
* Copyright (c) 2009 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef DS1624_H
#define DS1624_H
/*lint ++flb "Enter library region" */
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @file
* @brief DS1624 digital temperature sensor driver.
*
*
* @defgroup nrf_drivers_ds1624 DS1624 digital temperature sensor driver
* @{
* @ingroup ext_drivers
* @brief DS1624 digital temperature sensor driver.
*/
/**
* @brief Function for initializing DS1624 temperature sensor to 1-shot mode.
*
* @note Before calling this function, you must initialize twi_master first.
*
* @param device_address Bits [2:0] for the device address. All other bits must be zero.
* @return
* @retval true If communication succeeded with the device.
* @retval false If communication failed with the device.
*/
bool ds1624_init(uint8_t device_address);
/**
* @brief Function for reading temperature from the sensor.
*
* @param temperature_in_celcius Memory location to store temperature in full celcius degrees.
* @param temperature_fraction Memory location to store temperature's fraction part in 0.03125 celcius degree increments.
* @return
* @retval true Temperature was successfully read
* @retval false Temperature reading failed or conversion was not yet complete
*/
bool ds1624_temp_read(int8_t *temperature_in_celcius, int8_t *temperature_fraction);
/**
* @brief Function for starting temperature conversion. Valid data will be available 400 - 1000 milliseconds after exiting this function.
*
* @return
* @retval true Temperature conversion started.
* @retval false Temperature converion failed to start.
*/
bool ds1624_start_temp_conversion(void);
/**
* @brief Function for checking if temperature conversion is done.
*
* @return
* @retval true Temperature conversion done.
* @retval false Temperature converion still in progress.
*/
bool ds1624_is_temp_conversion_done(void);
/**
*@}
**/
/*lint --flb "Leave library region" */
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,255 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "hts221.h"
#include <string.h>
#define HTS221_WRITE(p_instance, msg) \
nrf_twi_sensor_write(p_instance->p_sensor_data, \
p_instance->sensor_addr, \
msg, \
ARRAY_SIZE(msg), \
true)
static void hts221_init_cb(ret_code_t result, void * p_register_data)
{
hts221_calib_t * calib_info = (hts221_calib_t *) p_register_data;
uint8_t calib_raw[HTS221_REG_CALIBRATION_NUM];
memcpy(calib_raw, calib_info, HTS221_REG_CALIBRATION_NUM);
calib_info->H0_rH_x2 = calib_raw[0];
calib_info->H1_rH_x2 = calib_raw[1];
calib_info->T0_degC_x8 = (uint16_t)calib_raw[2]
+ ((uint16_t)(calib_raw[5] & 0x03) << 8);
calib_info->T1_degC_x8 = (uint16_t)calib_raw[3]
+ ((uint16_t)((calib_raw[5] >> 2) & 0x03) << 8);
calib_info->H0_T0_OUT = (int16_t)calib_raw[6] + ((int16_t)calib_raw[7] << 8);
calib_info->H1_T0_OUT = (int16_t)calib_raw[10] + ((int16_t)calib_raw[11] << 8);
calib_info->T0_OUT = (int16_t)calib_raw[12] + ((int16_t)calib_raw[13] << 8);
calib_info->T1_OUT = (int16_t)calib_raw[14] + ((int16_t)calib_raw[15] << 8);
}
ret_code_t hts221_init(hts221_instance_t * p_instance)
{
ASSERT(p_instance != NULL);
if (p_instance->p_sensor_data->p_twi_mngr->p_queue->size < HTS221_MIN_QUEUE_SIZE)
{
return NRF_ERROR_INVALID_LENGTH;
}
p_instance->ctrl_reg1 = 0;
uint8_t send_msg[] = {
HTS221_REG_AV_CONF,
HTS221_DEF_AV_CONF,
0,
0,
0
};
ret_code_t err = HTS221_WRITE(p_instance, send_msg);
if (err != NRF_SUCCESS)
{
return err;
}
return nrf_twi_sensor_reg_read(p_instance->p_sensor_data,
p_instance->sensor_addr,
HTS221_REG_CALIBRATION | HTS221_INCR_REG_MASK,
hts221_init_cb,
(uint8_t *) &p_instance->calib_info,
HTS221_REG_CALIBRATION_NUM);
}
ret_code_t hts221_avg_cfg(hts221_instance_t * p_instance,
hts221_temp_avg_samples_t temp_avg,
hts221_hum_avg_samples_t hum_avg)
{
ASSERT(p_instance != NULL);
uint8_t reg_val = 0;
NRF_TWI_SENSOR_REG_SET(reg_val, HTS221_AVGT_MASK, HTS221_AVGT_POS, temp_avg);
NRF_TWI_SENSOR_REG_SET(reg_val, HTS221_AVGH_MASK, HTS221_AVGH_POS, hum_avg);
uint8_t send_msg[] = {
HTS221_REG_AV_CONF,
reg_val
};
return HTS221_WRITE(p_instance, send_msg);
}
ret_code_t hts221_data_rate_cfg(hts221_instance_t * p_instance, hts221_odr_t odr)
{
ASSERT(p_instance != NULL);
NRF_TWI_SENSOR_REG_SET(p_instance->ctrl_reg1, HTS221_ODR_MASK, HTS221_ODR_POS, odr);
uint8_t send_msg[] = {
HTS221_REG_CTRL_REG1,
p_instance->ctrl_reg1
};
return HTS221_WRITE(p_instance, send_msg);
}
ret_code_t hts221_pd_enable(hts221_instance_t * p_instance, bool enable)
{
ASSERT(p_instance != NULL);
NRF_TWI_SENSOR_REG_SET(p_instance->ctrl_reg1, HTS221_PD_MASK, HTS221_PD_POS, enable);
uint8_t send_msg[] = {
HTS221_REG_CTRL_REG1,
p_instance->ctrl_reg1
};
return HTS221_WRITE(p_instance, send_msg);
}
ret_code_t hts221_boot(hts221_instance_t * p_instance)
{
ASSERT(p_instance != NULL);
uint8_t reg_val = p_instance->ctrl_reg2;
NRF_TWI_SENSOR_REG_SET(reg_val, HTS221_BOOT_MASK, HTS221_BOOT_POS, 1);
uint8_t send_msg[] = {
HTS221_REG_CTRL_REG2,
reg_val
};
return HTS221_WRITE(p_instance, send_msg);
}
ret_code_t hts221_heater_enable(hts221_instance_t * p_instance, bool enable)
{
ASSERT(p_instance != NULL);
NRF_TWI_SENSOR_REG_SET(p_instance->ctrl_reg2, HTS221_HEATER_MASK, HTS221_HEATER_POS, enable);
uint8_t send_msg[] = {
HTS221_REG_CTRL_REG2,
p_instance->ctrl_reg2
};
return HTS221_WRITE(p_instance, send_msg);
}
ret_code_t hts221_oneshot(hts221_instance_t * p_instance)
{
ASSERT(p_instance != NULL);
uint8_t reg_val = p_instance->ctrl_reg2;
NRF_TWI_SENSOR_REG_SET(reg_val, HTS221_ONE_SHOT_MASK, HTS221_ONE_SHOT_POS, true);
uint8_t send_msg[] = {
HTS221_REG_CTRL_REG2,
reg_val
};
return HTS221_WRITE(p_instance, send_msg);
}
ret_code_t hts221_drdy_pin_cfg(hts221_instance_t * p_instance,
bool active_low,
bool operation,
bool drdy_enable)
{
ASSERT(p_instance != NULL);
uint8_t reg_val = 0;
NRF_TWI_SENSOR_REG_SET(reg_val, HTS221_DRDY_H_L_MASK, HTS221_DRDY_H_L_POS, active_low);
NRF_TWI_SENSOR_REG_SET(reg_val, HTS221_PP_OD_MASK, HTS221_PP_OD_POS, operation);
NRF_TWI_SENSOR_REG_SET(reg_val, HTS221_DRDY_EN_MASK, HTS221_DRDY_EN_POS, drdy_enable);
uint8_t send_msg[] = {
HTS221_REG_CTRL_REG3,
reg_val
};
return HTS221_WRITE(p_instance, send_msg);
}
ret_code_t hts221_temp_read(hts221_instance_t * p_instance,
hts221_data_callback_t user_callback,
int16_t * p_temp)
{
ASSERT(p_instance != NULL);
return nrf_twi_sensor_reg_read(p_instance->p_sensor_data,
p_instance->sensor_addr,
HTS221_REG_TEMP_OUT_L | HTS221_INCR_REG_MASK,
(nrf_twi_sensor_reg_cb_t) user_callback,
(uint8_t *) p_temp,
2);
}
int16_t hts221_temp_process(hts221_instance_t * p_instance, int16_t raw_temp)
{
ASSERT(p_instance != NULL);
int32_t y;
int32_t x0 = p_instance->calib_info.T0_OUT;
int32_t x1 = p_instance->calib_info.T1_OUT;
int32_t y0 = p_instance->calib_info.T0_degC_x8;
int32_t y1 = p_instance->calib_info.T1_degC_x8;
y = ((y0 * (x1 - raw_temp)) + (y1 * (raw_temp - x0))) / (x1 - x0);
return y;
}
ret_code_t hts221_hum_read(hts221_instance_t * p_instance,
hts221_data_callback_t user_callback,
int16_t * p_hum)
{
ASSERT(p_instance != NULL);
return nrf_twi_sensor_reg_read(p_instance->p_sensor_data,
p_instance->sensor_addr,
HTS221_REG_HUM_OUT_L | HTS221_INCR_REG_MASK,
(nrf_twi_sensor_reg_cb_t) user_callback,
(uint8_t *) p_hum,
2);
}
int16_t hts221_hum_process(hts221_instance_t * p_instance, int16_t raw_hum)
{
ASSERT(p_instance != NULL);
int32_t y;
int32_t x0 = p_instance->calib_info.H0_T0_OUT;
int32_t x1 = p_instance->calib_info.H1_T0_OUT;
int32_t y0 = p_instance->calib_info.H0_rH_x2;
int32_t y1 = p_instance->calib_info.H1_rH_x2;
y = ((y0 * (x1 - raw_hum)) + (y1 * (raw_hum - x0))) / (x1 - x0);
return y;
}

View File

@@ -0,0 +1,309 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef HTS221_H
#define HTS221_H
#include "nrf_twi_sensor.h"
#include "hts221_internal.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Possible sensor addresses.
*/
#define HTS221_BASE_ADDRESS 0x5FU
// Who am I default value.
#define HTS221_WHO_AM_I 0xBC
// Minimal TWI Manager queue size needed for sensor.
#define HTS221_MIN_QUEUE_SIZE 4
/**
* @brief Sensor driver usage.
*
* Sensor instance has to be defined first in global context using @ref HTS221_INSTANCE_DEF.
* After that it has to be initialized using @ref hts221_init.
* At this point sensor instance is ready and all other functions can be used.
*
* Configuration functions schedule TWI operation using @ref nrf_twi_sensor module.
* After calling function, setting will be automatically send to sensor when TWI bus is free.
*
* There are designated functions to read status sensor registers e.g. @ref hts221_status_read
* As parameters they receive function to be called after register is read, and pointer where
* register value should be stored. From that value specific parameters can be extracted
* using @ref NRF_TWI_SENSOR_REG_VAL_GET macro.
* Example:
* uint8_t h_da = NRF_TWI_SENSOR_REG_VAL_GET(status, HTS221_H_DA_MASK, HTS221_H_DA_POS);
*
* Other functions are self-explanatory or have description on their usage.
*/
/**
* @brief Temperature average setting.
*/
typedef enum
{
HTS221_TEMP_SAMPLES_2,
HTS221_TEMP_SAMPLES_4,
HTS221_TEMP_SAMPLES_8,
HTS221_TEMP_SAMPLES_16,
HTS221_TEMP_SAMPLES_32,
HTS221_TEMP_SAMPLES_64,
HTS221_TEMP_SAMPLES_128,
HTS221_TEMP_SAMPLES_256
} hts221_temp_avg_samples_t;
/**
* @brief Humidity average setting.
*/
typedef enum
{
HTS221_HUMIDITY_SAMPLES_4,
HTS221_HUMIDITY_SAMPLES_8,
HTS221_HUMIDITY_SAMPLES_16,
HTS221_HUMIDITY_SAMPLES_32,
HTS221_HUMIDITY_SAMPLES_64,
HTS221_HUMIDITY_SAMPLES_128,
HTS221_HUMIDITY_SAMPLES_256,
HTS221_HUMIDITY_SAMPLES_512
} hts221_hum_avg_samples_t;
/**
* @brief Output data rate settings.
*/
typedef enum
{
HTS221_ODR_ONESHOT,
HTS221_ODR_1HZ,
HTS221_ODR_7HZ,
HTS221_ODR_12_5HZ,
} hts221_odr_t;
/**
* @brief Data callback prototype.
*
* @param[in] result Return error code from TWI manager and underlying drivers.
* @param[in] p_data Pointer to sensor data.
*/
typedef void (* hts221_data_callback_t)(ret_code_t result, int16_t * p_data);
/**
* @brief Macro creating hts221 sensor instance.
*
* @param[in] _hts221_inst_name Sensor instance name.
* @param[in] _p_twi_sensor Pointer to common TWI sensor instance. @ref NRF_TWI_SENSOR_DEF
* @param[in] _sensor_address Sensor base address.
*/
#define HTS221_INSTANCE_DEF(_hts221_inst_name, _p_twi_sensor, _sensor_address) \
HTS221_INTERNAL_INSTANCE_DEF(_hts221_inst_name, _p_twi_sensor, _sensor_address)
/**
* @brief Function initializing hts221 sensor
*
* Writes configuration from sensor instance into sensor.
*
* @param[in] p_instance Pointer to sensor instance created by macro
*
* @note TWI manager queue size has to be at least
* HTS221_MIN_QUEUE_SIZE element long.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t hts221_init(hts221_instance_t * p_instance);
/**
* @brief Function for setting average configuration.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] temp_avg Number of temperature average samples.
* @param[in] hum_avg Number of humidity average samples.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t hts221_avg_cfg(hts221_instance_t * p_instance,
hts221_temp_avg_samples_t temp_avg,
hts221_hum_avg_samples_t hum_avg);
/**
* @brief Function for setting power down mode
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] enable True if device is powered, false if power down.
*
* @note Changes made by this function don't take effect before @ref hts221_cfg_commit
*/
ret_code_t hts221_pd_enable(hts221_instance_t * p_instance, bool enable);
/**
* @brief Function for rebooting sensor.
*
* @param[in] p_instance Pointer to sensor instance.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t hts221_boot(hts221_instance_t * p_instance);
/**
* @brief Function for setting heater.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] enable True if heater is on.
*
* @note Changes made by this function don't take effect before @ref hts221_cfg_commit
*/
ret_code_t hts221_heater_enable(hts221_instance_t * p_instance, bool enable);
/**
* @brief Function for setting one shot mode
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] enable True if one shot mode is on.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t hts221_oneshot(hts221_instance_t * p_instance);
/**
* @brief Function for setting sensor_data ready output signal.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] active_low True if active low, false if active high.
* @param[in] open_drain True if open drain, false if push-pull.
* @param[in] drdy_enable True if pin is enabled.
*
* @note Changes made by this function don't take effect before @ref hts221_cfg_commit
*/
ret_code_t hts221_drdy_pin_cfg(hts221_instance_t * p_instance,
bool active_low,
bool operation,
bool drdy_enable);
/**
* @brief Function for setting output data rate.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] odr Desired output data rate.
*
* @note Changes made by this function don't take effect before @ref hts221_cfg_commit
*/
ret_code_t hts221_data_rate_cfg(hts221_instance_t * p_instance, hts221_odr_t odr);
/**
* @brief Function for reading sensors temperature.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] user_callback Function to be called when sensor data is gathered.
* @param[out] p_temp Pointer for raw temperature value, single int16_t.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
ret_code_t hts221_temp_read(hts221_instance_t * p_instance,
hts221_data_callback_t user_callback,
int16_t * p_temp);
/**
* @brief Function for calculating temperature based on sensors calibration data.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] raw_temp Raw temperature in.
*
* @return Temperature * 8
*/
int16_t hts221_temp_process(hts221_instance_t * p_instance, int16_t raw_temp);
/**
* @brief Function for reading sensors humidity.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] user_callback Function to be called when data is gathered.
* @param[out] p_hum Pointer for raw humidity value, single int16_t.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
ret_code_t hts221_hum_read(hts221_instance_t * p_instance,
hts221_data_callback_t user_callback,
int16_t * p_hum);
/**
* @brief Function for calculating humidity based on sensors calibration data.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] raw_hum Raw humidity in.
*
* @return Humidity * 2
*/
int16_t hts221_hum_process(hts221_instance_t * p_instance, int16_t raw_hum);
/**
* @brief Function for reading WHO_AM_I register.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] user_cb Function to be called after register is read.
* @param[out] reg_val Register value, single uint8_t.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
__STATIC_INLINE ret_code_t hts221_who_am_i_read(hts221_instance_t * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * reg_val);
/**
* @brief Function for reading status register.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] user_cb Function to be called after register is read.
* @param[out] reg_val Register value, single uint8_t.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
__STATIC_INLINE ret_code_t hts221_status_read(hts221_instance_t * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * reg_val);
#ifdef __cplusplus
}
#endif
#endif // HTS221_H

View File

@@ -0,0 +1,235 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef HTS221_INTERNAL_H
#define HTS221_INTERNAL_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief HTS221 sensor registers.
*/
#define HTS221_REG_WHO_AM_I 0x0F
#define HTS221_REG_AV_CONF 0x10
#define HTS221_REG_CTRL_REG1 0x20
#define HTS221_REG_CTRL_REG2 0x21
#define HTS221_REG_CTRL_REG3 0x22
#define HTS221_REG_STATUS_REG 0x27
#define HTS221_REG_HUM_OUT_L 0x28
#define HTS221_REG_HUM_OUT_H 0x29
#define HTS221_REG_TEMP_OUT_L 0x2A
#define HTS221_REG_TEMP_OUT_H 0x2B
// Calibration registers
#define HTS221_REG_CALIBRATION 0x30
#define HTS221_REG_CALIBRATION_NUM 16
#define HTS221_REG_CTRL_NUM 3
// For auto incrementing address, msb in register address must be set to 1.
#define HTS221_INCR_REG_MASK 0x80
/**
* @brief AV_CONF register bitmasks.
*/
#define HTS221_DEF_AV_CONF 0x1B
// Register validity bitmask.
#define HTS221_AV_CONF_VALID_MASK 0xC0
// Bitmasks for AVGT.
#define HTS221_AVGT_POS 3
#define HTS221_AVGT_MASK (7 << HTS221_AVGT_POS)
// Bitmasks for AVGH.
#define HTS221_AVGH_POS 0
#define HTS221_AVGH_MASK (7 << HTS221_AVGH_POS)
/**
* @brief Control register 1 bitmasks.
*/
// Register validity bitmask.
#define HTS221_CTRL1_VALID_MASK 0x78
// Bitmasks for PD.
#define HTS221_PD_POS 7
#define HTS221_PD_MASK (1 << HTS221_PD_POS)
// Bitmasks for BDU.
#define HTS221_BDU_POS 2
#define HTS221_BDU_MASK (1 << HTS221_BDU_POS)
// Bitmasks for ODR.
#define HTS221_ODR_POS 0
#define HTS221_ODR_MASK (3 << HTS221_ODR_POS)
/**
* @brief Control register 2 bitmasks.
*/
// Register validity bitmask.
#define HTS221_CTRL2_VALID_MASK 0x7C
// Bitmasks for BOOT.
#define HTS221_BOOT_POS 7
#define HTS221_BOOT_MASK (1 << HTS221_BOOT_POS)
// Bitmasks for Heater.
#define HTS221_HEATER_POS 1
#define HTS221_HEATER_MASK (1 << HTS221_HEATER_POS)
// Bitmasks for ONE_SHOT.
#define HTS221_ONE_SHOT_POS 0
#define HTS221_ONE_SHOT_MASK (1 << HTS221_ONE_SHOT_POS)
/**
* @brief Control register 3 bitmasks.
*/
// Register validity bitmask.
#define HTS221_CTRL3_VALID_MASK 0x3B
// Bitmasks for DRDY_H_L.
#define HTS221_DRDY_H_L_POS 7
#define HTS221_DRDY_H_L_MASK (1 << HTS221_DRDY_H_L_POS)
// Bitmasks for PP_OD
#define HTS221_PP_OD_POS 6
#define HTS221_PP_OD_MASK (1 << HTS221_PP_OD_POS)
// Bitmasks for DRDY_EN.
#define HTS221_DRDY_EN_POS 2
#define HTS221_DRDY_EN_MASK (1 << HTS221_DRDY_EN_POS)
/**
* @brief Status register bitmasks.
*/
// Bitmasks for H_DA.
#define HTS221_H_DA_POS 1
#define HTS221_H_DA_MASK (1 << HTS221_H_DA_POS)
// Bitmasks for T_DA
#define HTS221_T_DA_POS 0
#define HTS221_T_DA_MASK (1 << HTS221_T_DA_POS)
/**
* @brief Structure holding calibration information.
*/
typedef struct
{
uint8_t H0_rH_x2;
uint8_t H1_rH_x2;
uint16_t T0_degC_x8;
uint16_t T1_degC_x8;
int16_t H0_T0_OUT;
int16_t H1_T0_OUT;
int16_t T0_OUT;
int16_t T1_OUT;
uint16_t padding; //<- Additional memory needed to store all calibration registers.
} hts221_calib_t;
/**
* @brief Structure holding sensor instance
*/
typedef struct
{
nrf_twi_sensor_t * const p_sensor_data;
uint8_t const sensor_addr;
hts221_calib_t calib_info;
uint8_t ctrl_reg1;
uint8_t ctrl_reg2;
} hts221_instance_t;
/**
* @brief Macro creating hts221 sensor instance.
*/
#define HTS221_INTERNAL_INSTANCE_DEF(_hts221_inst_name, _p_twi_sensor, _sensor_address) \
static hts221_instance_t _hts221_inst_name = \
{ \
.p_sensor_data = _p_twi_sensor, \
.sensor_addr = _sensor_address, \
}
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE ret_code_t hts221_who_am_i_read(hts221_instance_t * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * reg_val)
{
ASSERT(p_instance != NULL);
return nrf_twi_sensor_reg_read(p_instance->p_sensor_data,
p_instance->sensor_addr,
HTS221_REG_WHO_AM_I,
user_cb,
reg_val,
1);
}
__STATIC_INLINE ret_code_t hts221_status_read(hts221_instance_t * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * reg_val)
{
ASSERT(p_instance != NULL);
return nrf_twi_sensor_reg_read(p_instance->p_sensor_data,
p_instance->sensor_addr,
HTS221_REG_STATUS_REG,
user_cb,
reg_val,
1);
}
#endif //SUPPRESS_INLINE_IMPLEMENTATION
#ifdef __cplusplus
}
#endif
#endif // HTS221_INTERNAL_H

View File

@@ -0,0 +1,401 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(ILI9341)
#include "nrf_lcd.h"
#include "nrf_drv_spi.h"
#include "nrf_delay.h"
#include "nrf_gpio.h"
#include "boards.h"
// Set of commands described in ILI9341 datasheet.
#define ILI9341_NOP 0x00
#define ILI9341_SWRESET 0x01
#define ILI9341_RDDID 0x04
#define ILI9341_RDDST 0x09
#define ILI9341_SLPIN 0x10
#define ILI9341_SLPOUT 0x11
#define ILI9341_PTLON 0x12
#define ILI9341_NORON 0x13
#define ILI9341_RDMODE 0x0A
#define ILI9341_RDMADCTL 0x0B
#define ILI9341_RDPIXFMT 0x0C
#define ILI9341_RDIMGFMT 0x0D
#define ILI9341_RDSELFDIAG 0x0F
#define ILI9341_INVOFF 0x20
#define ILI9341_INVON 0x21
#define ILI9341_GAMMASET 0x26
#define ILI9341_DISPOFF 0x28
#define ILI9341_DISPON 0x29
#define ILI9341_CASET 0x2A
#define ILI9341_PASET 0x2B
#define ILI9341_RAMWR 0x2C
#define ILI9341_RAMRD 0x2E
#define ILI9341_PTLAR 0x30
#define ILI9341_MADCTL 0x36
#define ILI9341_PIXFMT 0x3A
#define ILI9341_FRMCTR1 0xB1
#define ILI9341_FRMCTR2 0xB2
#define ILI9341_FRMCTR3 0xB3
#define ILI9341_INVCTR 0xB4
#define ILI9341_DFUNCTR 0xB6
#define ILI9341_PWCTR1 0xC0
#define ILI9341_PWCTR2 0xC1
#define ILI9341_PWCTR3 0xC2
#define ILI9341_PWCTR4 0xC3
#define ILI9341_PWCTR5 0xC4
#define ILI9341_VMCTR1 0xC5
#define ILI9341_VMCTR2 0xC7
#define ILI9341_PWCTRSEQ 0xCB
#define ILI9341_PWCTRA 0xCD
#define ILI9341_PWCTRB 0xCF
#define ILI9341_RDID1 0xDA
#define ILI9341_RDID2 0xDB
#define ILI9341_RDID3 0xDC
#define ILI9341_RDID4 0xDD
#define ILI9341_GMCTRP1 0xE0
#define ILI9341_GMCTRN1 0xE1
#define ILI9341_DGMCTR1 0xE2
#define ILI9341_DGMCTR2 0xE3
#define ILI9341_TIMCTRA 0xE8
#define ILI9341_TIMCTRB 0xEA
#define ILI9341_ENGMCTR 0xF2
#define ILI9341_INCTR 0xF6
#define ILI9341_PUMP 0xF7
#define ILI9341_MADCTL_MY 0x80
#define ILI9341_MADCTL_MX 0x40
#define ILI9341_MADCTL_MV 0x20
#define ILI9341_MADCTL_ML 0x10
#define ILI9341_MADCTL_RGB 0x00
#define ILI9341_MADCTL_BGR 0x08
#define ILI9341_MADCTL_MH 0x04
static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(ILI9341_SPI_INSTANCE);
static inline void spi_write(const void * data, size_t size)
{
APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, data, size, NULL, 0));
}
static inline void write_command(uint8_t c)
{
nrf_gpio_pin_clear(ILI9341_DC_PIN);
spi_write(&c, sizeof(c));
}
static inline void write_data(uint8_t c)
{
nrf_gpio_pin_set(ILI9341_DC_PIN);
spi_write(&c, sizeof(c));
}
static void set_addr_window(uint16_t x_0, uint16_t y_0, uint16_t x_1, uint16_t y_1)
{
ASSERT(x_0 <= x_1);
ASSERT(y_0 <= y_1);
write_command(ILI9341_CASET);
write_data(x_0 >> 8);
write_data(x_0);
write_data(x_1 >> 8);
write_data(x_1);
write_command(ILI9341_PASET);
write_data(y_0 >> 8);
write_data(y_0);
write_data(y_1 >> 8);
write_data(y_1);
write_command(ILI9341_RAMWR);
}
static void command_list(void)
{
write_command(ILI9341_SWRESET);
nrf_delay_ms(120);
write_command(ILI9341_DISPOFF);
nrf_delay_ms(120);
write_command(ILI9341_PWCTRB);
write_data(0x00);
write_data(0XC1);
write_data(0X30);
write_command(ILI9341_TIMCTRA);
write_data(0x85);
write_data(0x00);
write_data(0x78);
write_command(ILI9341_PWCTRSEQ);
write_data(0x39);
write_data(0x2C);
write_data(0x00);
write_data(0x34);
write_data(0x02);
write_command(ILI9341_PUMP);
write_data(0x20);
write_command(ILI9341_TIMCTRB);
write_data(0x00);
write_data(0x00);
write_command(ILI9341_PWCTR1);
write_data(0x23);
write_command(ILI9341_PWCTR2);
write_data(0x10);
write_command(ILI9341_VMCTR1);
write_data(0x3e);
write_data(0x28);
write_command(ILI9341_VMCTR2);
write_data(0x86);
write_command(ILI9341_MADCTL);
write_data(0x48);
write_command(ILI9341_PIXFMT);
write_data(0x55);
write_command(ILI9341_FRMCTR1);
write_data(0x00);
write_data(0x18);
write_command(ILI9341_DFUNCTR);
write_data(0x08);
write_data(0x82);
write_data(0x27);
write_command(ILI9341_ENGMCTR);
write_data(0x00);
write_command(ILI9341_GAMMASET);
write_data(0x01);
write_command(ILI9341_GMCTRP1);
write_data(0x0F);
write_data(0x31);
write_data(0x2B);
write_data(0x0C);
write_data(0x0E);
write_data(0x08);
write_data(0x4E);
write_data(0xF1);
write_data(0x37);
write_data(0x07);
write_data(0x10);
write_data(0x03);
write_data(0x0E);
write_data(0x09);
write_data(0x00);
write_command(ILI9341_GMCTRN1);
write_data(0x00);
write_data(0x0E);
write_data(0x14);
write_data(0x03);
write_data(0x11);
write_data(0x07);
write_data(0x31);
write_data(0xC1);
write_data(0x48);
write_data(0x08);
write_data(0x0F);
write_data(0x0C);
write_data(0x31);
write_data(0x36);
write_data(0x0F);
write_command(ILI9341_SLPOUT);
nrf_delay_ms(120);
write_command(ILI9341_DISPON);
}
static ret_code_t hardware_init(void)
{
ret_code_t err_code;
nrf_gpio_cfg_output(ILI9341_DC_PIN);
nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
spi_config.sck_pin = ILI9341_SCK_PIN;
spi_config.miso_pin = ILI9341_MISO_PIN;
spi_config.mosi_pin = ILI9341_MOSI_PIN;
spi_config.ss_pin = ILI9341_SS_PIN;
err_code = nrf_drv_spi_init(&spi, &spi_config, NULL, NULL);
return err_code;
}
static ret_code_t ili9341_init(void)
{
ret_code_t err_code;
err_code = hardware_init();
if (err_code != NRF_SUCCESS)
{
return err_code;
}
command_list();
return err_code;
}
static void ili9341_uninit(void)
{
nrf_drv_spi_uninit(&spi);
}
static void ili9341_pixel_draw(uint16_t x, uint16_t y, uint32_t color)
{
set_addr_window(x, y, x, y);
const uint8_t data[2] = {color >> 8, color};
nrf_gpio_pin_set(ILI9341_DC_PIN);
spi_write(data, sizeof(data));
nrf_gpio_pin_clear(ILI9341_DC_PIN);
}
static void ili9341_rect_draw(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t color)
{
set_addr_window(x, y, x + width - 1, y + height - 1);
const uint8_t data[2] = {color >> 8, color};
nrf_gpio_pin_set(ILI9341_DC_PIN);
// Duff's device algorithm for optimizing loop.
uint32_t i = (height * width + 7) / 8;
/*lint -save -e525 -e616 -e646 */
switch ((height * width) % 8) {
case 0:
do {
spi_write(data, sizeof(data));
case 7:
spi_write(data, sizeof(data));
case 6:
spi_write(data, sizeof(data));
case 5:
spi_write(data, sizeof(data));
case 4:
spi_write(data, sizeof(data));
case 3:
spi_write(data, sizeof(data));
case 2:
spi_write(data, sizeof(data));
case 1:
spi_write(data, sizeof(data));
} while (--i > 0);
default:
break;
}
/*lint -restore */
nrf_gpio_pin_clear(ILI9341_DC_PIN);
}
static void ili9341_dummy_display(void)
{
/* No implementation needed. */
}
static void ili9341_rotation_set(nrf_lcd_rotation_t rotation)
{
write_command(ILI9341_MADCTL);
switch (rotation) {
case NRF_LCD_ROTATE_0:
write_data(ILI9341_MADCTL_MX | ILI9341_MADCTL_BGR);
break;
case NRF_LCD_ROTATE_90:
write_data(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR);
break;
case NRF_LCD_ROTATE_180:
write_data(ILI9341_MADCTL_MY | ILI9341_MADCTL_BGR);
break;
case NRF_LCD_ROTATE_270:
write_data(ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR);
break;
default:
break;
}
}
static void ili9341_display_invert(bool invert)
{
write_command(invert ? ILI9341_INVON : ILI9341_INVOFF);
}
static lcd_cb_t ili9341_cb = {
.height = ILI9341_HEIGHT,
.width = ILI9341_WIDTH
};
const nrf_lcd_t nrf_lcd_ili9341 = {
.lcd_init = ili9341_init,
.lcd_uninit = ili9341_uninit,
.lcd_pixel_draw = ili9341_pixel_draw,
.lcd_rect_draw = ili9341_rect_draw,
.lcd_display = ili9341_dummy_display,
.lcd_rotation_set = ili9341_rotation_set,
.lcd_display_invert = ili9341_display_invert,
.p_lcd_cb = &ili9341_cb
};
#endif // NRF_MODULE_ENABLED(ILI9341)

View File

@@ -0,0 +1,173 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "lis2dh12.h"
#define RETURN_IF_ERR(err) \
if (err != NRF_SUCCESS) \
{ \
return err; \
}
ret_code_t lis2dh12_init(lis2dh12_instance_t * p_inst)
{
ASSERT(p_inst != NULL);
memset(&p_inst->temp_cfg, 0, &p_inst->act_dur - &p_inst->temp_cfg);
p_inst->ctrl0 = LIS2DH12_CTRL_REG0_VALID_SET;
p_inst->ctrl1 = 0x07;
p_inst->ctrl4 = 0x80;
return lis2dh12_cfg_commit(p_inst);
}
ret_code_t lis2dh12_cfg_commit(lis2dh12_instance_t * p_inst)
{
ASSERT(p_inst != NULL);
ret_code_t err;
p_inst->ctrl0 &= ~LIS2DH12_CTRL_REG0_VALID_MASK;
p_inst->ctrl0 |= LIS2DH12_CTRL_REG0_VALID_SET;
uint8_t ctrl_msg[] = {
LIS2DH12_REG_CTRL_REG0 | LIS2DH12_AUTO_INCR_MASK,
p_inst->ctrl0,
p_inst->temp_cfg,
p_inst->ctrl1,
p_inst->ctrl2,
p_inst->ctrl3,
p_inst->ctrl4,
p_inst->ctrl5,
p_inst->ctrl6,
p_inst->reference
};
err = nrf_twi_sensor_write(p_inst->p_sensor_data,
p_inst->sensor_addr,
ctrl_msg,
ARRAY_SIZE(ctrl_msg),
true);
RETURN_IF_ERR(err);
uint8_t fifo_msg[] = {
LIS2DH12_REG_FIFO_CTRL | LIS2DH12_AUTO_INCR_MASK,
p_inst->fifo_ctrl,
0,
p_inst->int1_cfg,
0,
p_inst->int1_ths,
p_inst->int1_dur,
p_inst->int2_cfg,
0,
p_inst->int2_ths,
p_inst->int2_dur,
p_inst->click_cfg
};
err = nrf_twi_sensor_write(p_inst->p_sensor_data,
p_inst->sensor_addr,
fifo_msg,
ARRAY_SIZE(fifo_msg),
true);
RETURN_IF_ERR(err);
uint8_t time_msg[] = {
LIS2DH12_REG_CLICK_THS | LIS2DH12_AUTO_INCR_MASK,
p_inst->click_ths,
p_inst->time_lim,
p_inst->latency,
p_inst->time_win,
p_inst->act_ths,
p_inst->act_dur
};
err = nrf_twi_sensor_write(p_inst->p_sensor_data,
p_inst->sensor_addr,
time_msg,
ARRAY_SIZE(time_msg),
true);
return err;
}
ret_code_t lis2dh12_data_read(lis2dh12_instance_t * p_inst,
lis2dh12_data_cb_t user_cb,
lis2dh12_data_t * p_data,
uint8_t samples)
{
ASSERT(p_inst != NULL);
return nrf_twi_sensor_reg_read(p_inst->p_sensor_data,
p_inst->sensor_addr,
LIS2DH12_REG_OUT_X_L | LIS2DH12_AUTO_INCR_MASK,
(nrf_twi_sensor_reg_cb_t) user_cb,
(uint8_t *) p_data,
samples * LIS2DH12_BYTES_PER_SAMPLE);
}
ret_code_t lis2dh12_temp_enable(lis2dh12_instance_t * p_inst, bool temp_en)
{
ASSERT(p_inst != NULL);
if (temp_en == true)
{
NRF_TWI_SENSOR_REG_SET(p_inst->temp_cfg, LIS2DH12_TEMP_EN_MASK, LIS2DH12_TEMP_EN_POS, 3);
}
else
{
NRF_TWI_SENSOR_REG_SET(p_inst->temp_cfg, LIS2DH12_TEMP_EN_MASK, LIS2DH12_TEMP_EN_POS, 0);
}
uint8_t send_msg[] = {
LIS2DH12_REG_TEMP_CFG_REG,
p_inst->temp_cfg
};
return nrf_twi_sensor_write(p_inst->p_sensor_data,
p_inst->sensor_addr,
send_msg,
ARRAY_SIZE(send_msg),
true);
}
ret_code_t lis2dh12_temp_read(lis2dh12_instance_t * p_inst,
lis2dh12_temp_cb_t user_cb,
int16_t * p_temp)
{
ASSERT(p_inst != NULL);
return nrf_twi_sensor_reg_read(p_inst->p_sensor_data,
p_inst->sensor_addr,
LIS2DH12_REG_OUT_TEMP_L | LIS2DH12_AUTO_INCR_MASK,
(nrf_twi_sensor_reg_cb_t) user_cb,
(uint8_t *) p_temp,
LIS2DH12_BYTES_PER_TEMP);
}

View File

@@ -0,0 +1,491 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef LIS2DH12_H
#define LIS2DH12_H
#include "nrf_twi_sensor.h"
#include "lis2dh12_internal.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Possible sensor addresses.
*/
#define LIS2DH12_BASE_ADDRESS_LOW 0x18U
#define LIS2DH12_BASE_ADDRESS_HIGH 0x19U
// WHO_AM_I register value.
#define LIS2DH12_WHO_AM_I 0x33
/**
* @brief Sensor driver usage.
*
* Sensor instance has to be defined first in global context using @ref LIS2DH12_INSTANCE DEF.
* After that it has to be initialized using @ref lis2dh12_init.
* At this point sensor instance is ready and all other functions can be used.
*
* Sensor settings are modified using asynchronous macros, using them does not change
* real sensor settings until @ref lis2dh12_cfg_commit is called.
* Example:
* LIS2DH12_DATA_CFG(m_sensor, LIS2DH12_ODR_200HZ, false, true, true, true, LIS2DH12_SCALE_2G, 1);
* lis2dh12_cfg_commit(&m_sensor);
*
* There are designated functions to read status sensor registers e.g. @ref lis2dh12_status_read
* As parameters they receive function to be called after register is read, and pointer where
* register value should be stored. From that value specific parameters can be extracted
* using @ref NRF_TWI_SENSOR_REG_VAL_GET macro. For specific bitmasks, check lis2dh12_internal.h
* Example:
* bool zyxor = NRF_TWI_SENSOR_REG_VAL_GET(status_reg, LIS2DH12_ZYXOR_MASK, LIS2DH12_ZYXOR_POS);
*
* Other functions are self-explanatory or have description on their usage.
*/
/**
* @brief Output data rate settings.
*/
typedef enum
{
LIS2DH12_ODR_POWERDOWN,
LIS2DH12_ODR_1HZ,
LIS2DH12_ODR_10HZ,
LIS2DH12_ODR_25HZ,
LIS2DH12_ODR_50HZ,
LIS2DH12_ODR_100HZ,
LIS2DH12_ODR_200HZ,
LIS2DH12_ODR_400HZ,
LIS2DH12_ODR_1620HZ,
LIS2DH12_ODR_1344_5376HZ
} lis2dh12_odr_t;
/**
* @brief Fifo mode settings.
*/
typedef enum
{
LIS2DH12_BYPASS,
LIS2DH12_FIFO,
LIS2DH12_STREAM,
LIS2DH12_STREAM_TO_FIFO
} lis2dh12_fifo_mode_t;
/**
* @brief Filter mode setting.
*/
typedef enum
{
LIS2DH12_FILTER_MODE_NORMAL_W_RESET,
LIS2DH12_FILTER_MODE_REFERENCE,
LIS2DH12_FILTER_MODE_NORMAL,
LIS2DH12_FILTER_MODE_AUTO_RESET
} lis2dh12_filter_mode_t;
/**
* @brief Filter frequency setting.
*/
typedef enum
{
LIS2DH12_FILTER_FREQ_1,
LIS2DH12_FILTER_FREQ_2,
LIS2DH12_FILTER_FREQ_3,
LIS2DH12_FILTER_FREQ_4
} lis2dh12_filter_freq_t;
/**
* @brief Accelerometer scale setting.
*/
typedef enum
{
LIS2DH12_SCALE_2G,
LIS2DH12_SCALE_4G,
LIS2DH12_SCALE_8G,
LIS2DH12_SCALE_16G
} lis2dh12_scale_t;
/**
* @brief Structure containing accelerometer data.
*/
typedef struct
{
int16_t x;
int16_t y;
int16_t z;
} lis2dh12_data_t;
/**
* @brief Data callback prototype.
*
* @param[in] result Result of operation (NRF_SUCCESS on success,
* otherwise a relevant error code).
* @param[in] p_data Pointer to raw sensor data structure.
*/
typedef void (* lis2dh12_data_cb_t)(ret_code_t result, lis2dh12_data_t * p_data);
/**
* @brief Temperature callback prototype.
*
* @param[in] result Result of operation (NRF_SUCCESS on success,
* otherwise a relevant error code).
* @param[in] p_temp Temperature value.
*/
typedef void (* lis2dh12_temp_cb_t)(ret_code_t result, int16_t * p_temp);
/**
* @brief Macro for defining sensor instance.
*
* @param[in] _lis2dh12_inst_name Sensor instance name.
* @param[in] _p_twi_sensor Pointer to common TWI sensor instance.
* @param[in] _sensor_address Sensor base address.
*/
#define LIS2DH12_INSTANCE_DEF(_lis2dh12_inst_name, _p_twi_sensor, _sensor_address) \
LIS2DH12_INTERNAL_INSTANCE_DEF(_lis2dh12_inst_name, _p_twi_sensor, _sensor_address)
/**
* @brief Macro for setting data acquisition configuration.
*
* @param[in] _s Sensor instance.
* @param[in] _odr Data rate. @ref lis2dh12_odr_t
* @param[in] _lp Power mode. True if low power mode is enabled.
* @param[in] _z_en Enable measure in z-axis. True if enabled.
* @param[in] _y_en Enable measure in y-axis. True if enabled.
* @param[in] _x_en Enable measure in x-axis. True if enabled.
* @param[in] _scale Measurement scale. @ref lis2dh12_scale_t
* @param[in] _high_res High resolution mode. True if enabled.
* Low power can't be enabled when in high resolution mode.
*/
#define LIS2DH12_DATA_CFG(_s, _odr, _lp, _z_en, _y_en, _x_en, _scale, _high_res) \
LIS2DH12_INTERNAL_DATA_CFG(_s, _odr, _lp, _z_en, _y_en, _x_en, _scale, _high_res)
/**
* @brief Function for setting filter configuration.
*
* @param[in] _s Sensor instance.
* @param[in] _mode Filter mode. @ref lis2dh12_filter_mode_t
* @param[in] _freq Filter frequency. @ref lis2dh12_filter_freq_t
* @param[in] _d_en Enable filter for data acquisition.
* @param[in] _c_en Enable filter for click interrupt.
* @param[in] _i1_en Enable filter for interrupt 1 aoi.
* @param[in] _i2_en Enable filter for interrupt 2 aoi.
*/
#define LIS2DH12_FILTER_CFG(_s, _mode, _freq, _d_en, _c_en, _i1_en, _i2_en) \
LIS2DH12_INTERNAL_FILTER_CFG(_s, _mode, _freq, _d_en, _c_en, _i1_en, _i2_en)
/**
* @brief Macro for configuring INT1 pin.
*
* @param[in] _s Sensor instance.
* @param[in] _cl Enable CLICK interrupt on pin.
* @param[in] _ia1 Enable IA1 interrupt on pin.
* @param[in] _ia2 Enable IA2 interrupt on pin.
* @param[in] _zyxda Enable ZYXDA interrupt on pin.
* @param[in] _wtm Enable FIFO watermark interrupt on pin.
* @param[in] _ovr Enable FIFO overrun interrupt on pin.
* @param[in] _pol Pin active state. Affects also int2 pin.
* @arg true Pin is active low.
* @arg false Pin is active high
* @param[in] _d4d Enable 4D detection on INT1 pin when 6D is enabled on interrupt 1.
*/
#define LIS2DH12_INT1_PIN_CFG(_s, _cl, _ia1, _ia2, _zyxda, _wtm, _ovr, _pol, _d4d) \
LIS2DH12_INTERNAL_INT1_PIN_CFG(_s, _cl, _ia1, _ia2, _zyxda, _wtm, _ovr, _pol, _d4d)
/**
* @brief Macro for configuring INT2 pin.
*
* @param[in] _s Sensor instance.
* @param[in] _cl Enable CLICK interrupt on pin.
* @param[in] _ia1 Enable IA1 interrupt on pin.
* @param[in] _ia2 Enable IA2 interrupt on pin.
* @param[in] _boot Enable boot on pin.
* @param[in] _avt Enable activity interrupt on pin.
* @param[in] _pol Pin active state. Affects also int1 pin.
* @arg true Pin is active low.
* @arg false Pin is active high
* @param[in] _d4d Enable 4D detection on INT2 pin when 6D is enabled on interrupt 2.
*/
#define LIS2DH12_INT2_PIN_CFG(_s, _cl, _ia1, _ia2, _boot, _act, _pol, _d4d) \
LIS2DH12_INTERNAL_INT2_PIN_CFG(_s, _cl, _ia1, _ia2, _boot, _act, _pol, _d4d)
/**
* @brief Macro for configuring interrupt 1.
*
* @param[in] _s Sensor instance.
* @param[in] _thr Interrupt threshold.
* @param[in] _dur Interrupt duration.
* @param[in] _aoi And/Or combination of interrupt events. True if and.
* @param[in] _6d 6-direction detection enable. True if enabled.
* @param[in] _zh Enable interrupt on Z high event or direction recognition.
* @param[in] _zl Enable interrupt on Z low event or direction recognition.
* @param[in] _yh Enable interrupt on Y high event or direction recognition.
* @param[in] _yl Enable interrupt on Y low event or direction recognition.
* @param[in] _xh Enable interrupt on X high event or direction recognition.
* @param[in] _xl Enable interrupt on X low event or direction recognition.
* @param[in] _lir Latch interrupt 1 request. True if enabled.
*/
#define LIS2DH12_INT1_CFG(_s, _thr, _dur, _aoi, _6d, _zh, _zl, _yh, yl, _xh, _xl, _lir) \
LIS2DH12_INTERNAL_INT1_CFG(_s, _thr, _dur, _aoi, _6d, _zh, _zl, _yh, yl, _xh, _xl, _lir)
/**
* @brief Macro for configuring interrupt 2.
*
* @param[in] _s Sensor instance.
* @param[in] _thr Interrupt threshold.
* @param[in] _dur Interrupt duration.
* @param[in] _aoi And/Or combination of interrupt events. True if and.
* @param[in] _6d 6-direction detection enable. True if enabled.
* @param[in] _zh Enable interrupt on Z high event or direction recognition.
* @param[in] _zl Enable interrupt on Z low event or direction recognition.
* @param[in] _yh Enable interrupt on Y high event or direction recognition.
* @param[in] _yl Enable interrupt on Y low event or direction recognition.
* @param[in] _xh Enable interrupt on X high event or direction recognition.
* @param[in] _xl Enable interrupt on X low event or direction recognition.
* @param[in] _lir Latch interrupt 1 request. True if enabled.
*/
#define LIS2DH12_INT2_CFG(_s, _thr, _dur, _aoi, _6d, _zh, _zl, _yh, yl, _xh, _xl, _lir) \
LIS2DH12_INTERNAL_INT2_CFG(_s, _thr, _dur, _aoi, _6d, _zh, _zl, _yh, yl, _xh, _xl, _lir)
/**
* @brief Function for setting click configuration.
*
* @param[in] _s Sensor instance.
* @param[in] _zd Enable interrupt double-click on Z-axis.
* @param[in] _zs Enable interrupt single-click on Z-axis.
* @param[in] _yd Enable interrupt double-click on Y-axis.
* @param[in] _ys Enable interrupt single-click on Y-axis.
* @param[in] _xd Enable interrupt double-click on X-axis.
* @param[in] _xs Enable interrupt single-click on X-axis.
* @param[in] _lir Keep high until CLICK_SRC is read.
* @arg true Interrupt is kept high until CLICK_SRC is read.
* @arg false Interrupt is kept high for the duration of latency window.
* @param[in] _ths Click threshold.
* @param[in] _lim Click time limit.
* @param[in] _ltc Click time latency.
* @param[in] _win Click time window.
*/
#define LIS2DH12_CLICK_CFG(_s, _zd, _zs, _yd, _ys, _xd, _xs, _lir, _ths, _lim, _ltc, _win) \
LIS2DH12_INTERNAL_CLICK_CFG(_s, _zd, _zs, _yd, _ys, _xd, _xs, _lir, _ths, _lim, _ltc, _win)
/**
* @brief Macro for setting sleep configuration.
*
* @param[in] _s Sensor instance.
* @param[in] _ths Sleep-to-wake, return-to-sleep activation threshold in low-power mode.
* @param[in] _dur Sleep-to-wake, return-to-sleep duration.
*/
#define LIS2DH12_SLEEP_CFG(_s, _ths, _dur) \
LIS2DH12_INTERNAL_SLEEP_CFG(_s, _ths, _dur)
/**
* @brief Macro for setting reference value for interrupt generation.
*
* @param[in] _s Sensor instance.
* @param[in] _ref Reference value.
*/
#define LIS2DH_REF_SET(_s, _ref) \
LIS2DH_INTERNAL_REF_SET(_s, _ref)
/**
* @brief Macro for setting FIFO configuration.
*
* @param[in] _s Sensor instance.
* @param[in] _en Enables FIFO. True if enabled. False clears FIFO setting.
* @param[in] _mode FIFO mode. @ref lis2dh12_fifo_mode_t
* @param[in] _t_sel Trigger event pin selection. True if int2 pin, false if int1 pin.
* @param[in] _t_thr Trigger threshold.
*/
#define LIS2DH12_FIFO_CFG(_s, _en, _mode, _t_sel, _t_thr) \
LIS2DH12_INTERNAL_FIFO_CFG(_s, _en, _mode, _t_sel, _t_thr)
/**
* @brief Function for initializing LIS2DH12 instance.
*
* @param[in] p_inst Pointer to sensor instance defined by macro. @ref LIS2DH12_INSTANCE_DEF
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t lis2dh12_init(lis2dh12_instance_t * p_inst);
/**
* @brief Function for writing configuration to sensor.
*
* @param[in] p_inst Pointer to sensor instance.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t lis2dh12_cfg_commit(lis2dh12_instance_t * p_inst);
/**
* @brief Function for reading accelerometer data.
*
* @param[in] p_inst Pointer to sensor instance.
* @param[in] user_cb Function to be called after data read is complete.
* @param[in] p_data Pointer to data structure.
* @param[in] samples Number of samples to read.
*
* @note When trying to read more than one sample and FIFO is disabled,
* current output value will be copied to all read samples.
* When trying to read more samples than there is currently in FIFO,
* excess samples will be equal to 0.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
ret_code_t lis2dh12_data_read(lis2dh12_instance_t * p_inst,
lis2dh12_data_cb_t user_cb,
lis2dh12_data_t * p_data,
uint8_t samples);
/**
* @brief Function for enabling temperature measurement.
*
* @param[in] p_inst Pointer to sensor instance.
* @param[in] temp_en Temperature measure enable. True if enabled.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t lis2dh12_temp_enable(lis2dh12_instance_t * p_inst, bool temp_en);
/**
* @brief Function for reading temperature data.
*
* @param[in] p_inst Pointer to sensor instance.
* @param[in] user_cb Function to be called after temperature read is complete.
* @param[in] p_temp Temperature value. Pointer to single int16_t.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
ret_code_t lis2dh12_temp_read(lis2dh12_instance_t * p_inst,
lis2dh12_temp_cb_t user_cb,
int16_t * p_temp);
/**
* @brief Function for reading temperature status register.
*
* @param[in] p_inst Pointer to sensor instance.
* @param[in] user_cb Function to be called after register read.
* @param[in] p_data Pointer to register data. Single uint8_t.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
__STATIC_INLINE ret_code_t lis2dh12_temp_status_read(lis2dh12_instance_t * p_inst,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * p_data);
/**
* @brief Function for reading WHO_AM_I register.
*
* @param[in] p_inst Pointer to sensor instance.
* @param[in] user_cb Function to be called after register read.
* @param[in] p_data Pointer to register data. Single uint8_t.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
__STATIC_INLINE ret_code_t lis2dh12_who_am_i_read(lis2dh12_instance_t * p_inst,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * p_data);
/**
* @brief Function for reading status register.
*
* @param[in] p_inst Pointer to sensor instance.
* @param[in] user_cb Function to be called after register read.
* @param[in] p_data Pointer to register data. Single uint8_t.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
__STATIC_INLINE ret_code_t lis2dh12_status_read(lis2dh12_instance_t * p_inst,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * p_data);
/**
* @brief Function for reading FIFO source register.
*
* @param[in] p_inst Pointer to sensor instance.
* @param[in] user_cb Function to be called after register read.
* @param[in] p_data Pointer to register data. Single uint8_t.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
__STATIC_INLINE ret_code_t lis2dh12_fifo_src_read(lis2dh12_instance_t * p_inst,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * p_data);
/**
* @brief Function for reading interrupt 1 source register.
*
* @param[in] p_inst Pointer to sensor instance.
* @param[in] user_cb Function to be called after register read.
* @param[in] p_data Pointer to register data. Single uint8_t.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
__STATIC_INLINE ret_code_t lis2dh12_int1_src_read(lis2dh12_instance_t * p_inst,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * p_data);
/**
* @brief Function for reading interrupt 2 source register.
*
* @param[in] p_inst Pointer to sensor instance.
* @param[in] user_cb Function to be called after register read.
* @param[in] p_data Pointer to register data. Single uint8_t.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
__STATIC_INLINE ret_code_t lis2dh12_int2_src_read(lis2dh12_instance_t * p_inst,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * p_data);
/**
* @brief Function for reading click source register.
*
* @param[in] p_inst Pointer to sensor instance.
* @param[in] user_cb Function to be called after register read.
* @param[in] p_data Pointer to register data. Single uint8_t.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
__STATIC_INLINE ret_code_t lis2dh12_click_src_read(lis2dh12_instance_t * p_inst,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * p_data);
#ifdef __cplusplus
}
#endif
#endif // LIS2DH12_H

View File

@@ -0,0 +1,823 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef LIS2DH12_INTERNAL_H
#define LIS2DH12_INTERNAL_H
#ifdef __cplusplus
extern "C" {
#endif
#define LIS2DH12_AUTO_INCR_MASK 0x80
/**
* @brief LIS2DH12 sensor registers.
*/
#define LIS2DH12_REG_STATUS_AUX 0x07
#define LIS2DH12_REG_OUT_TEMP_L 0x0C
#define LIS2DH12_REG_OUT_TEMP_H 0x0D
#define LIS2DH12_REG_WHO_AM_I 0x0F
#define LIS2DH12_REG_CTRL_REG0 0x1E
#define LIS2DH12_REG_TEMP_CFG_REG 0x1F
#define LIS2DH12_REG_CTRL_REG1 0x20
#define LIS2DH12_REG_CTRL_REG2 0x21
#define LIS2DH12_REG_CTRL_REG3 0x22
#define LIS2DH12_REG_CTRL_REG4 0x23
#define LIS2DH12_REG_CTRL_REG5 0x24
#define LIS2DH12_REG_CTRL_REG6 0x25
#define LIS2DH12_REG_REFERENCE 0x26
#define LIS2DH12_REG_STATUS 0x27
#define LIS2DH12_REG_OUT_X_L 0x28
#define LIS2DH12_REG_OUT_X_H 0x29
#define LIS2DH12_REG_OUT_Y_L 0x2A
#define LIS2DH12_REG_OUT_Y_H 0x2B
#define LIS2DH12_REG_OUT_Z_L 0x2C
#define LIS2DH12_REG_OUT_Z_H 0x2D
#define LIS2DH12_REG_FIFO_CTRL 0x2E
#define LIS2DH12_REG_FIFO_SRC 0x2F
#define LIS2DH12_REG_INT1_CFG 0x30
#define LIS2DH12_REG_INT1_SRC 0x31
#define LIS2DH12_REG_INT1_THS 0x32
#define LIS2DH12_REG_INT1_DURATION 0x33
#define LIS2DH12_REG_INT2_CFG 0x34
#define LIS2DH12_REG_INT2_SRC 0x35
#define LIS2DH12_REG_INT2_THS 0x36
#define LIS2DH12_REG_INT2_DURATION 0x37
#define LIS2DH12_REG_CLICK_CFG 0x38
#define LIS2DH12_REG_CLICK_SRC 0x39
#define LIS2DH12_REG_CLICK_THS 0x3A
#define LIS2DH12_REG_TIME_LIMIT 0x3B
#define LIS2DH12_REG_TIME_LATENCY 0x3C
#define LIS2DH12_REG_TIME_WINDOW 0x3D
#define LIS2DH12_REG_ACT_THS 0x3E
#define LIS2DH12_REG_ACT_DUR 0x3F
/**
* @brief Config register defaults.
*/
#define LIS2DH12_DEF_CTRL_REG0 0x10
#define LIS2DH12_DEF_CTRL_REG1 0x07
#define LIS2DH12_BYTES_PER_SAMPLE 6
#define LIS2DH12_BYTES_PER_TEMP 2
/**
* @brief Status reg aux bitmasks.
*/
// Bitmasks for TOR.
#define LIS2DH12_TOR_POS 6
#define LIS2DH12_TOR_MASK (1 << LIS2DH12_TOR_POS)
// Bitmasks for TDA.
#define LIS2DH12_TDA_POS 2
#define LIS2DH12_TDA_MASK (1 << LIS2DH12_TDA_POS)
/**
* @brief Control register 0 bitmasks
*/
#define LIS2DH12_CTRL_REG0_VALID_MASK 0x7F
#define LIS2DH12_CTRL_REG0_VALID_SET 0x10
// Bitmasks for SDO_PU_DISC.
#define LIS2DH12_SDO_PU_DISC_POS 7
#define LIS2DH12_SDO_PU_DISC_MASK (1 << LIS2DH12_SDO_PU_DISC_POS)
/**
* @brief Temp config register bitmasks
*/
#define LIS2DH12_TEMP_CONF_VALID_MASK 0x3F
// Bitmasks for TEMP_EN
#define LIS2DH12_TEMP_EN_POS 6
#define LIS2DH12_TEMP_EN_MASK (3 << LIS2DH12_TEMP_EN_POS)
/**
* @brief Control register 1 bitmasks
*/
// Bitmasks for ODR.
#define LIS2DH12_ODR_POS 4
#define LIS2DH12_ODR_MASK (0x0F << LIS2DH12_ODR_POS)
// Bitmasks for LP_EN
#define LIS2DH12_LP_EN_POS 3
#define LIS2DH12_LP_EN_MASK (1 << LIS2DH12_LP_EN_POS)
// Bitmasks for Z_EN
#define LIS2DH12_Z_EN_POS 2
#define LIS2DH12_Z_EN_MASK (1 << LIS2DH12_Z_EN_POS)
// Bitmasks for Y_EN
#define LIS2DH12_Y_EN_POS 1
#define LIS2DH12_Y_EN_MASK (1 << LIS2DH12_Y_EN_POS)
// Bitmasks for X_EN
#define LIS2DH12_X_EN_POS 0
#define LIS2DH12_X_EN_MASK (1 << LIS2DH12_X_EN_POS)
/**
* @brief Control register 2 bitmasks.
*/
// Bitmasks for HPM.
#define LIS2DH12_HPM_POS 6
#define LIS2DH12_HPM_MASK (3 << LIS2DH12_HPM_POS)
// Bitmasks for HPCF.
#define LIS2DH12_HPCF_POS 4
#define LIS2DH12_HPCF_MASK (3 << LIS2DH12_HPCF_POS)
// Bitmasks for FDS.
#define LIS2DH12_FDS_POS 3
#define LIS2DH12_FDS_MASK (1 << LIS2DH12_FDS_POS)
// Bitmasks for HPCLICK.
#define LIS2DH12_HP_C_POS 2
#define LIS2DH12_HP_C_MASK (1 << LIS2DH12_HP_C_POS)
// Bitmasks for HP_IA2.
#define LIS2DH12_HP_I2_POS 1
#define LIS2DH12_HP_I2_MASK (1 << LIS2DH12_HP_I2_POS)
// Bitmasks for HP_IA1.
#define LIS2DH12_HP_I1_POS 0
#define LIS2DH12_HP_I1_MASK (1 << LIS2DH12_HP_I1_POS)
/**
* @brief Control register 3 bitmasks.
*/
// Bitmasks for I1_CLICK.
#define LIS2DH12_I1_CLICK_POS 7
#define LIS2DH12_I1_CLICK_MASK (1 << LIS2DH12_I1_CLICK_POS)
// Bitmasks for I1_IA1.
#define LIS2DH12_I1_IA1_POS 6
#define LIS2DH12_I1_IA1_MASK (1 << LIS2DH12_I1_IA1_POS)
// Bitmasks for I1_IA2.
#define LIS2DH12_I1_IA2_POS 5
#define LIS2DH12_I1_IA2_MASK (1 << LIS2DH12_I1_IA2_POS)
// Bitmasks for I1_ZYXDA.
#define LIS2DH12_I1_ZYXDA_POS 4
#define LIS2DH12_I1_ZYXDA_MASK (1 << LIS2DH12_I1_ZYXDA_POS)
// Bitmasks for I1_WTM.
#define LIS2DH12_I1_WTM_POS 2
#define LIS2DH12_I1_WTM_MASK (1 << LIS2DH12_I1_WTM_POS)
// Bitmasks for I1_OVERRUN.
#define LIS2DH12_I1_OVERRUN_POS 1
#define LIS2DH12_I1_OVERRUN_MASK (1 << LIS2DH12_I1_OVERRUN_POS)
/**
* @brief Control register 4 bitmasks.
*/
// Bitmasks for BDU.
#define LIS2DH12_BDU_POS 7
#define LIS2DH12_BDU_MASK (1 << LIS2DH12_BDU_POS)
// Bitmasks for BLE.
#define LIS2DH12_BLE_POS 6
#define LIS2DH12_BLE_MASK (1 << LIS2DH12_BLE_POS)
// Bitmasks for FS.
#define LIS2DH12_FS_POS 4
#define LIS2DH12_FS_MASK (3 << LIS2DH12_FS_POS)
// Bitmasks for HR.
#define LIS2DH12_HR_POS 3
#define LIS2DH12_HR_MASK (1 << LIS2DH12_HR_POS)
// Bitmasks for ST.
#define LIS2DH12_ST_POS 1
#define LIS2DH12_ST_MASK (3 << LIS2DH12_ST_POS)
// Bitmasks for SIM.
#define LIS2DH12_SIM_POS 0
#define LIS2DH12_SIM_MASK (1 << LIS2DH12_SIM_POS)
/**
* @brief Control register 5 bitmasks.
*/
// Bitmasks for BOOT.
#define LIS2DH12_BOOT_POS 7
#define LIS2DH12_BOOT_MASK (1 << LIS2DH12_BOOT_POS)
// Bitmasks for FIFO_EN.
#define LIS2DH12_FIFO_EN_POS 6
#define LIS2DH12_FIFO_EN_MASK (1 << LIS2DH12_FIFO_EN_POS)
// Bitmasks for LIR_INT1.
#define LIS2DH12_LIR_INT1_POS 3
#define LIS2DH12_LIR_INT1_MASK (1 << LIS2DH12_LIR_INT1_POS)
// Bitmasks for D4D_INT1.
#define LIS2DH12_D4D_INT1_POS 2
#define LIS2DH12_D4D_INT1_MASK (1 << LIS2DH12_D4D_INT1_POS)
// Bitmasks for LIR_INT2.
#define LIS2DH12_LIR_INT2_POS 1
#define LIS2DH12_LIR_INT2_MASK (1 << LIS2DH12_LIR_INT2_POS)
// Bitmasks for D4D_INT2.
#define LIS2DH12_D4D_INT2_POS 0
#define LIS2DH12_D4D_INT2_MASK (1 << LIS2DH12_D4D_INT2_POS)
/**
* @brief Control register 6 bitmasks.
*/
// Bitmasks for I2_CLICK.
#define LIS2DH12_I2_CLICK_POS 7
#define LIS2DH12_I2_CLICK_MASK (1 << LIS2DH12_I2_CLICK_POS)
// Bitmasks for I2_IA1.
#define LIS2DH12_I2_IA1_POS 6
#define LIS2DH12_I2_IA1_MASK (1 << LIS2DH12_I2_IA1_POS)
// Bitmasks for I2_IA2.
#define LIS2DH12_I2_IA2_POS 5
#define LIS2DH12_I2_IA2_MASK (1 << LIS2DH12_I2_IA2_POS)
// Bitmasks for I2_BOOT.
#define LIS2DH12_I2_BOOT_POS 4
#define LIS2DH12_I2_BOOT_MASK (1 << LIS2DH12_I2_BOOT_POS)
// Bitmasks for I2_ACT.
#define LIS2DH12_I2_ACT_POS 3
#define LIS2DH12_I2_ACT_MASK (1 << LIS2DH12_I2_ACT_POS)
// Bitmasks for INT_POLARITY.
#define LIS2DH12_INT_POLARITY_POS 1
#define LIS2DH12_INT_POLARITY_MASK (1 << LIS2DH12_INT_POLARITY_POS)
/**
* @brief Status register bitmasks.
*/
// Bitmasks for ZYXOR.
#define LIS2DH12_ZYXOR_POS 7
#define LIS2DH12_ZYXOR_MASK (1 << LIS2DH12_ZYXOR_POS)
// Bitmasks for ZOR.
#define LIS2DH12_ZOR_POS 6
#define LIS2DH12_ZOR_MASK (1 << LIS2DH12_ZOR_POS)
// Bitmasks for YOR.
#define LIS2DH12_YOR_POS 5
#define LIS2DH12_YOR_MASK (1 << LIS2DH12_YOR_POS)
// Bitmasks for XOR.
#define LIS2DH12_XOR_POS 4
#define LIS2DH12_XOR_MASK (1 << LIS2DH12_XOR_POS)
// Bitmasks for ZYXDA.
#define LIS2DH12_ZYXDA_POS 3
#define LIS2DH12_ZYXDA_MASK (1 << LIS2DH12_ZYXDA_POS)
// Bitmasks for ZDA.
#define LIS2DH12_ZDA_POS 2
#define LIS2DH12_ZDA_MASK (1 << LIS2DH12_ZDA_POS)
// Bitmasks for YDA.
#define LIS2DH12_YDA_POS 1
#define LIS2DH12_YDA_MASK (1 << LIS2DH12_YDA_POS)
// Bitmasks for XDA.
#define LIS2DH12_XDA_POS 0
#define LIS2DH12_XDA_MASK (1 << LIS2DH12_XDA_POS)
/**
* @brief FIFO control register bitmasks.
*/
// Bitmasks for FM.
#define LIS2DH12_FM_POS 6
#define LIS2DH12_FM_MASK (3 << LIS2DH12_FM_POS)
// Bitmasks for TR.
#define LIS2DH12_TR_POS 5
#define LIS2DH12_TR_MASK (1 << LIS2DH12_TR_POS)
// Bitmasks for FTH.
#define LIS2DH12_FTH_POS 0
#define LIS2DH12_FTH_MASK (0x1F << LIS2DH12_FTH_POS)
/**
* @brief FIFO source register bitmasks.
*/
// Bitmasks for WTM.
#define LIS2DH12_WTM_POS 7
#define LIS2DH12_WTM_MASK (1 << LIS2DH12_WTM_POS)
// Bitmasks for OVRN_FIFO.
#define LIS2DH12_OVRN_FIFO_POS 6
#define LIS2DH12_OVRN_FIFO_MASK (1 << LIS2DH12_OVRN_FIFO_POS)
// Bitmasks for EMPTY.
#define LIS2DH12_EMPTY_POS 5
#define LIS2DH12_EMPTY_MASK (1 << LIS2DH12_EMPTY_POS)
// Bitmasks for FSS.
#define LIS2DH12_FSS_POS 0
#define LIS2DH12_FSS_MASK (0x1F << LIS2DH12_FSS_POS)
/**
* @brief Interrupt config register bitmasks.
*/
// Bitmasks for INT_AOI.
#define LIS2DH12_INT_AOI_POS 7
#define LIS2DH12_INT_AOI_MASK (1 << LIS2DH12_INT_AOI_POS)
// Bitmasks for INT_6D.
#define LIS2DH12_INT_6D_POS 6
#define LIS2DH12_INT_6D_MASK (1 << LIS2DH12_INT_6D_POS)
// Bitmasks for INT_ZHIE.
#define LIS2DH12_INT_ZHIE_POS 5
#define LIS2DH12_INT_ZHIE_MASK (1 << LIS2DH12_INT_ZHIE_POS)
// Bitmasks for INT_ZLIE.
#define LIS2DH12_INT_ZLIE_POS 4
#define LIS2DH12_INT_ZLIE_MASK (1 << LIS2DH12_INT_ZLIE_POS)
// Bitmasks for INT_YHIE.
#define LIS2DH12_INT_YHIE_POS 3
#define LIS2DH12_INT_YHIE_MASK (1 << LIS2DH12_INT_YHIE_POS)
// Bitmasks for INT_YLIE.
#define LIS2DH12_INT_YLIE_POS 2
#define LIS2DH12_INT_YLIE_MASK (1 << LIS2DH12_INT_YLIE_POS)
// Bitmasks for INT_XHIE.
#define LIS2DH12_INT_XHIE_POS 1
#define LIS2DH12_INT_XHIE_MASK (1 << LIS2DH12_INT_XHIE_POS)
// Bitmasks for INT_XLIE.
#define LIS2DH12_INT_XLIE_POS 0
#define LIS2DH12_INT_XLIE_MASK (1 << LIS2DH12_INT_XLIE_POS)
/**
* @brief Interrupt source register bitmasks.
*/
// Bitmasks for IA.
#define LIS2DH12_INT_IA_POS 6
#define LIS2DH12_INT_IA_MASK (1 << LIS2DH12_INT_IA_POS)
// Bitmasks for ZH.
#define LIS2DH12_INT_ZH_POS 5
#define LIS2DH12_INT_ZH_MASK (1 << LIS2DH12_INT_ZH_POS)
// Bitmasks for ZL.
#define LIS2DH12_INT_ZL_POS 4
#define LIS2DH12_INT_ZL_MASK (1 << LIS2DH12_INT_ZL_POS)
// Bitmasks for YH.
#define LIS2DH12_INT_YH_POS 3
#define LIS2DH12_INT_YH_MASK (1 << LIS2DH12_INT_YH_POS)
// Bitmasks for YL.
#define LIS2DH12_INT_YL_POS 2
#define LIS2DH12_INT_YL_MASK (1 << LIS2DH12_INT_YL_POS)
// Bitmasks for XH.
#define LIS2DH12_INT_XH_POS 1
#define LIS2DH12_INT_XH_MASK (1 << LIS2DH12_INT_XH_POS)
// Bitmasks for XL.
#define LIS2DH12_INT_XL_POS 0
#define LIS2DH12_INT_XL_MASK (1 << LIS2DH12_INT_XL_POS)
/**
* @brief Interrupt threshold register bitmasks.
*/
// Bitmasks for THS.
#define LIS2DH12_INT_THS_POS 0
#define LIS2DH12_INT_THS_MASK (0x7F << LIS2DH12_INT_THS_POS)
/**
* @brief Interrupt duration register bitmasks.
*/
// Bitmasks for DUR.
#define LIS2DH12_INT_DUR_POS 0
#define LIS2DH12_INT_DUR_MASK (0x7F << LIS2DH12_INT_DUR_POS)
/**
* @brief Click config register bitmasks.
*/
// Bitmasks for ZD.
#define LIS2DH12_CLICK_ZD_POS 5
#define LIS2DH12_CLICK_ZD_MASK (1 << LIS2DH12_CLICK_ZD_POS)
// Bitmasks for ZS.
#define LIS2DH12_CLICK_ZS_POS 4
#define LIS2DH12_CLICK_ZS_MASK (1 << LIS2DH12_CLICK_ZS_POS)
// Bitmasks for YD.
#define LIS2DH12_CLICK_YD_POS 3
#define LIS2DH12_CLICK_YD_MASK (1 << LIS2DH12_CLICK_YD_POS)
// Bitmasks for YS.
#define LIS2DH12_CLICK_YS_POS 2
#define LIS2DH12_CLICK_YS_MASK (1 << LIS2DH12_CLICK_YS_POS)
// Bitmasks for XD.
#define LIS2DH12_CLICK_XD_POS 1
#define LIS2DH12_CLICK_XD_MASK (1 << LIS2DH12_CLICK_XD_POS)
// Bitmasks for XS.
#define LIS2DH12_CLICK_XS_POS 0
#define LIS2DH12_CLICK_XS_MASK (1 << LIS2DH12_CLICK_XS_POS)
/**
* @brief Click source register bitmasks.
*/
// Bitmasks for IA.
#define LIS2DH12_CLICK_IA_POS 6
#define LIS2DH12_CLICK_IA_MASK (1 << LIS2DH12_CLICK_IA_POS)
// Bitmasks for DCLICK.
#define LIS2DH12_CLICK_DCLICK_POS 5
#define LIS2DH12_CLICK_DCLICK_MASK (1 << LIS2DH12_CLICK_DCLICK_POS)
// Bitmasks for SCLICK.
#define LIS2DH12_CLICK_SCLICK_POS 4
#define LIS2DH12_CLICK_SCLICK_MASK (1 << LIS2DH12_CLICK_SCLICK_POS)
// Bitmasks for SIGN.
#define LIS2DH12_CLICK_SIGN_POS 3
#define LIS2DH12_CLICK_SIGN_MASK (1 << LIS2DH12_CLICK_SIGN_POS)
// Bitmasks for Z.
#define LIS2DH12_CLICK_Z_POS 2
#define LIS2DH12_CLICK_Z_MASK (1 << LIS2DH12_CLICK_Z_POS)
// Bitmasks for Y.
#define LIS2DH12_CLICK_Y_POS 1
#define LIS2DH12_CLICK_Y_MASK (1 << LIS2DH12_CLICK_Y_POS)
// Bitmasks for X.
#define LIS2DH12_CLICK_X_POS 0
#define LIS2DH12_CLICK_X_MASK (1 << LIS2DH12_CLICK_X_POS)
/**
* @brief Click threshold register bitmasks.
*/
// Bitmasks for LIR.
#define LIS2DH12_CLICK_LIR_POS 7
#define LIS2DH12_CLICK_LIR_MASK (1 << LIS2DH12_CLICK_LIR_POS)
// Bitmasks for THS.
#define LIS2DH12_CLICK_THS_POS 0
#define LIS2DH12_CLICK_THS_MASK (0x7F << LIS2DH12_CLICK_THS_POS)
/**
* @brief Click time limit register bitmasks.
*/
// Bitmasks for TLI.
#define LIS2DH12_CLICK_TLI_POS 0
#define LIS2DH12_CLICK_TLI_MASK (0x7F << LIS2DH12_CLICK_TLI_POS)
/**
* @brief Activation threshold register bitmasks.
*/
// Bitmasks for THS.
#define LIS2DH12_ACT_THS_POS 0
#define LIS2DH12_ACT_THS_MASK (0x7F << LIS2DH12_ACT_THS_POS)
/**
* @brief Structure holding sensor instance
*/
typedef struct
{
nrf_twi_sensor_t * const p_sensor_data;
uint8_t const sensor_addr;
uint8_t ctrl0;
uint8_t temp_cfg;
uint8_t ctrl1;
uint8_t ctrl2;
uint8_t ctrl3;
uint8_t ctrl4;
uint8_t ctrl5;
uint8_t ctrl6;
uint8_t reference;
uint8_t fifo_ctrl;
uint8_t int1_cfg;
uint8_t int1_ths;
uint8_t int1_dur;
uint8_t int2_cfg;
uint8_t int2_ths;
uint8_t int2_dur;
uint8_t click_cfg;
uint8_t click_ths;
uint8_t time_lim;
uint8_t latency;
uint8_t time_win;
uint8_t act_ths;
uint8_t act_dur;
} lis2dh12_instance_t;
/**
* @brief Macro for defining sensor instance.
*/
#define LIS2DH12_INTERNAL_INSTANCE_DEF(_lis2dh12_inst_name, _p_twi_sensor, _sensor_address) \
static lis2dh12_instance_t _lis2dh12_inst_name = \
{ \
.p_sensor_data = _p_twi_sensor, \
.sensor_addr = _sensor_address \
}
/**
* @brief Macro for setting data acquisition configuration.
*/
#define LIS2DH12_INTERNAL_DATA_CFG(_s, _odr, _lp, _z_en, _y_en, _x_en, _scale, _high_res) \
NRF_TWI_SENSOR_REG_SET(_s.ctrl1, LIS2DH12_ODR_MASK, LIS2DH12_ODR_POS, _odr); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl1, LIS2DH12_LP_EN_MASK, LIS2DH12_LP_EN_POS, _lp); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl1, LIS2DH12_Z_EN_MASK, LIS2DH12_Z_EN_POS, _z_en); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl1, LIS2DH12_Y_EN_MASK, LIS2DH12_Y_EN_POS, _y_en); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl1, LIS2DH12_X_EN_MASK, LIS2DH12_X_EN_POS, _x_en); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl4, LIS2DH12_FS_MASK, LIS2DH12_FS_POS, _scale); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl4, LIS2DH12_HR_MASK, LIS2DH12_HR_POS, _high_res)
/**
* @brief Function for setting filter configuration.
*/
#define LIS2DH12_INTERNAL_FILTER_CFG(_s, _mode, _freq, _d_en, _c_en, _i1_en, _i2_en) \
NRF_TWI_SENSOR_REG_SET(_s.ctrl2, LIS2DH12_HPM_MASK, LIS2DH12_HPM_POS, _mode); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl2, LIS2DH12_HPCF_MASK, LIS2DH12_HPCF_POS, _freq); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl2, LIS2DH12_FDS_MASK, LIS2DH12_FDS_POS, _d_en); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl2, LIS2DH12_HP_C_MASK, LIS2DH12_HP_C_POS, _c_en); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl2, LIS2DH12_HP_I1_MASK, LIS2DH12_HP_I1_POS, _i1_en); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl2, LIS2DH12_HP_I2_MASK, LIS2DH12_HP_I2_POS, _i2_en)
/**
* @brief Macro for configuring INT1 pin.
*/
#define LIS2DH12_INTERNAL_INT1_PIN_CFG(_s, _cl, _ia1, _ia2, _zyxda, _wtm, _ovr, _pol, _d4d) \
NRF_TWI_SENSOR_REG_SET(_s.ctrl3, LIS2DH12_I1_CLICK_MASK, LIS2DH12_I1_CLICK_POS, _cl); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl3, LIS2DH12_I1_IA1_MASK, LIS2DH12_I1_IA1_POS, _ia1); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl3, LIS2DH12_I1_IA2_MASK, LIS2DH12_I1_IA2_POS, _ia2); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl3, LIS2DH12_I1_ZYXDA_MASK, LIS2DH12_I1_ZYXDA_POS, _zyxda); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl3, LIS2DH12_I1_WTM_MASK, LIS2DH12_I1_WTM_POS, _wtm); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl3, LIS2DH12_I1_OVERRUN_MASK, LIS2DH12_I1_OVERRUN_POS, _ovr); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl6, LIS2DH12_INT_POLARITY_MASK, LIS2DH12_INT_POLARITY_POS, _pol); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl5, LIS2DH12_D4D_INT1_MASK, LIS2DH12_D4D_INT1_POS, _d4d)
/**
* @brief Macro for configuring INT2 pin.
*/
#define LIS2DH12_INTERNAL_INT2_PIN_CFG(_s, _cl, _ia1, _ia2, _boot, _act, _pol, _d4d) \
NRF_TWI_SENSOR_REG_SET(_s.ctrl6, LIS2DH12_I2_CLICK_MASK, LIS2DH12_I2_CLICK_POS, _cl); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl6, LIS2DH12_I2_IA1_MASK, LIS2DH12_I2_IA1_POS, _ia1); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl6, LIS2DH12_I2_IA2_MASK, LIS2DH12_I2_IA2_POS, _ia2); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl6, LIS2DH12_I2_BOOT_MASK, LIS2DH12_I2_BOOT_POS, _boot);\
NRF_TWI_SENSOR_REG_SET(_s.ctrl6, LIS2DH12_I2_ACT_MASK, LIS2DH12_I2_ACT_POS, _act); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl6, LIS2DH12_INT_POLARITY_MASK, LIS2DH12_INT_POLARITY_POS, _pol); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl5, LIS2DH12_D4D_INT2_MASK, LIS2DH12_D4D_INT2_POS, _d4d)
/**
* @brief Macro for configuring interrupt 1.
*/
#define LIS2DH12_INTERNAL_INT1_CFG(_s, _thr, _dur, _aoi, _6d, _zh, _zl, _yh, yl, _xh, _xl, _lir) \
NRF_TWI_SENSOR_REG_SET(_s.int1_ths, LIS2DH12_INT_THS_MASK, LIS2DH12_INT_THS_POS, _thr); \
NRF_TWI_SENSOR_REG_SET(_s.int1_dur, LIS2DH12_INT_DUR_MASK, LIS2DH12_INT_DUR_POS, _dur); \
NRF_TWI_SENSOR_REG_SET(_s.int1_cfg, LIS2DH12_INT_AOI_MASK, LIS2DH12_INT_AOI_POS, _aoi); \
NRF_TWI_SENSOR_REG_SET(_s.int1_cfg, LIS2DH12_INT_6D_MASK, LIS2DH12_INT_6D_POS, _6d); \
NRF_TWI_SENSOR_REG_SET(_s.int1_cfg, LIS2DH12_INT_ZHIE_MASK, LIS2DH12_INT_ZHIE_POS, _zh); \
NRF_TWI_SENSOR_REG_SET(_s.int1_cfg, LIS2DH12_INT_ZLIE_MASK, LIS2DH12_INT_ZLIE_POS, _zl); \
NRF_TWI_SENSOR_REG_SET(_s.int1_cfg, LIS2DH12_INT_YHIE_MASK, LIS2DH12_INT_YHIE_POS, _yh); \
NRF_TWI_SENSOR_REG_SET(_s.int1_cfg, LIS2DH12_INT_YLIE_MASK, LIS2DH12_INT_YLIE_POS, _yl); \
NRF_TWI_SENSOR_REG_SET(_s.int1_cfg, LIS2DH12_INT_XHIE_MASK, LIS2DH12_INT_XHIE_POS, _xh); \
NRF_TWI_SENSOR_REG_SET(_s.int1_cfg, LIS2DH12_INT_XLIE_MASK, LIS2DH12_INT_XLIE_POS, _xl); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl5, LIS2DH12_LIR_INT1_MASK, LIS2DH12_LIR_INT1_POS, _lir)
/**
* @brief Macro for configuring interrupt 2.
*/
#define LIS2DH12_INTERNAL_INT2_CFG(_s, _thr, _dur, _aoi, _6d, _zh, _zl, _yh, yl, _xh, _xl, _lir) \
NRF_TWI_SENSOR_REG_SET(_s.int2_ths, LIS2DH12_INT_THS_MASK, LIS2DH12_INT_THS_POS, _thr); \
NRF_TWI_SENSOR_REG_SET(_s.int2_dur, LIS2DH12_INT_DUR_MASK, LIS2DH12_INT_DUR_POS, _dur); \
NRF_TWI_SENSOR_REG_SET(_s.int2_cfg, LIS2DH12_INT_AOI_MASK, LIS2DH12_INT_AOI_POS, _aoi); \
NRF_TWI_SENSOR_REG_SET(_s.int2_cfg, LIS2DH12_INT_6D_MASK, LIS2DH12_INT_6D_POS, _6d); \
NRF_TWI_SENSOR_REG_SET(_s.int2_cfg, LIS2DH12_INT_ZHIE_MASK, LIS2DH12_INT_ZHIE_POS, _zh); \
NRF_TWI_SENSOR_REG_SET(_s.int2_cfg, LIS2DH12_INT_ZLIE_MASK, LIS2DH12_INT_ZLIE_POS, _zl); \
NRF_TWI_SENSOR_REG_SET(_s.int2_cfg, LIS2DH12_INT_YHIE_MASK, LIS2DH12_INT_YHIE_POS, _yh); \
NRF_TWI_SENSOR_REG_SET(_s.int2_cfg, LIS2DH12_INT_YLIE_MASK, LIS2DH12_INT_YLIE_POS, _yl); \
NRF_TWI_SENSOR_REG_SET(_s.int2_cfg, LIS2DH12_INT_XHIE_MASK, LIS2DH12_INT_XHIE_POS, _xh); \
NRF_TWI_SENSOR_REG_SET(_s.int2_cfg, LIS2DH12_INT_XLIE_MASK, LIS2DH12_INT_XLIE_POS, _xl); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl5, LIS2DH12_LIR_INT2_MASK, LIS2DH12_LIR_INT2_POS, _lir)
/**
* @brief Function for setting click configuration.
*/
#define LIS2DH12_INTERNAL_CLICK_CFG(_s, _zd, _zs, _yd, _ys, _xd, _xs, _lir, _ths, _lim, _ltc, _win) \
NRF_TWI_SENSOR_REG_SET(_s.click_cfg, LIS2DH12_CLICK_ZD_MASK, LIS2DH12_CLICK_ZD_POS, _zd); \
NRF_TWI_SENSOR_REG_SET(_s.click_cfg, LIS2DH12_CLICK_ZS_MASK, LIS2DH12_CLICK_ZD_POS, _zd); \
NRF_TWI_SENSOR_REG_SET(_s.click_cfg, LIS2DH12_CLICK_YD_MASK, LIS2DH12_CLICK_YD_POS, _yd); \
NRF_TWI_SENSOR_REG_SET(_s.click_cfg, LIS2DH12_CLICK_YS_MASK, LIS2DH12_CLICK_YS_POS, _ys); \
NRF_TWI_SENSOR_REG_SET(_s.click_cfg, LIS2DH12_CLICK_XD_MASK, LIS2DH12_CLICK_XD_POS, _xd); \
NRF_TWI_SENSOR_REG_SET(_s.click_cfg, LIS2DH12_CLICK_XS_MASK, LIS2DH12_CLICK_XS_POS, _xs); \
NRF_TWI_SENSOR_REG_SET(_s.click_ths, LIS2DH12_CLICK_LIR_MASK, LIS2DH12_CLICK_LIR_POS, _lir); \
NRF_TWI_SENSOR_REG_SET(_s.click_ths, LIS2DH12_CLICK_THS_MASK, LIS2DH12_CLICK_THS_POS, _ths); \
NRF_TWI_SENSOR_REG_SET(_s.time_lim, LIS2DH12_CLICK_TLI_MASK, LIS2DH12_CLICK_TLI_POS, _lim); \
_s.latency = _ltc; \
_s.time_win = _win
/**
* @brief Macro for setting sleep configuration.
*/
#define LIS2DH12_INTERNAL_SLEEP_CFG(_s, _ths, _dur) \
NRF_TWI_SENSOR_REG_SET(_s.act_ths, LIS2DH12_ACT_THS_MASK, LIS2DH12_ACT_THS_POS, _ths); \
_s.act_dur = _dur
/**
* @brief Macro for setting reference value for interrupt generation.
*/
#define LIS2DH12_INTERNAL_REF_SET(_s, _ref) \
_s.reference = _ref
/**
* @brief Macro for setting FIFO configuration.
*/
#define LIS2DH12_INTERNAL_FIFO_CFG(_s, _en, _mode, _t_sel, _t_thr) \
NRF_TWI_SENSOR_REG_SET(_s.fifo_ctrl, LIS2DH12_FM_MASK, LIS2DH12_FM_POS, _mode); \
NRF_TWI_SENSOR_REG_SET(_s.fifo_ctrl, LIS2DH12_TR_MASK, LIS2DH12_TR_POS, _t_sel); \
NRF_TWI_SENSOR_REG_SET(_s.fifo_ctrl, LIS2DH12_FTH_MASK, LIS2DH12_FTH_POS, _t_thr); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl5, LIS2DH12_FIFO_EN_MASK, LIS2DH12_FIFO_EN_POS, _en)
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE ret_code_t lis2dh12_temp_status_read(lis2dh12_instance_t * p_inst,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * p_data)
{
ASSERT(p_inst != NULL);
return nrf_twi_sensor_reg_read(p_inst->p_sensor_data,
p_inst->sensor_addr,
LIS2DH12_REG_STATUS_AUX,
user_cb,
p_data,
1);
}
__STATIC_INLINE ret_code_t lis2dh12_who_am_i_read(lis2dh12_instance_t * p_inst,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * p_data)
{
ASSERT(p_inst != NULL);
return nrf_twi_sensor_reg_read(p_inst->p_sensor_data,
p_inst->sensor_addr,
LIS2DH12_REG_WHO_AM_I,
user_cb,
p_data,
1);
}
__STATIC_INLINE ret_code_t lis2dh12_status_read(lis2dh12_instance_t * p_inst,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * p_data)
{
ASSERT(p_inst != NULL);
return nrf_twi_sensor_reg_read(p_inst->p_sensor_data,
p_inst->sensor_addr,
LIS2DH12_REG_STATUS,
user_cb,
p_data,
1);
}
__STATIC_INLINE ret_code_t lis2dh12_fifo_src_read(lis2dh12_instance_t * p_inst,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * p_data)
{
ASSERT(p_inst != NULL);
return nrf_twi_sensor_reg_read(p_inst->p_sensor_data,
p_inst->sensor_addr,
LIS2DH12_REG_FIFO_SRC,
user_cb,
p_data,
1);
}
__STATIC_INLINE ret_code_t lis2dh12_int1_src_read(lis2dh12_instance_t * p_inst,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * p_data)
{
ASSERT(p_inst != NULL);
return nrf_twi_sensor_reg_read(p_inst->p_sensor_data,
p_inst->sensor_addr,
LIS2DH12_REG_INT1_SRC,
user_cb,
p_data,
1);
}
__STATIC_INLINE ret_code_t lis2dh12_int2_src_read(lis2dh12_instance_t * p_inst,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * p_data)
{
ASSERT(p_inst != NULL);
return nrf_twi_sensor_reg_read(p_inst->p_sensor_data,
p_inst->sensor_addr,
LIS2DH12_REG_INT2_SRC,
user_cb,
p_data,
1);
}
__STATIC_INLINE ret_code_t lis2dh12_click_src_read(lis2dh12_instance_t * p_inst,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * p_data)
{
ASSERT(p_inst != NULL);
return nrf_twi_sensor_reg_read(p_inst->p_sensor_data,
p_inst->sensor_addr,
LIS2DH12_REG_CLICK_SRC,
user_cb,
p_data,
1);
}
#endif //SUPPRESS_INLINE_IMPLEMENTATION
#ifdef __cplusplus
}
#endif
#endif // LIS2DH12_INTERNAL_H

View File

@@ -0,0 +1,320 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "lps22hb.h"
ret_code_t lps22hb_init(lps22hb_instance_t * p_instance)
{
ASSERT(p_instance != NULL);
p_instance->interrupt_cfg = 0;
p_instance->ctrl_reg[0] = 0;
p_instance->ctrl_reg[1] = LPS22HB_CTRL_REG2_DEFAULT;
p_instance->ctrl_reg[2] = 0;
p_instance->fifo_ctrl = 0;
ret_code_t err_code;
if (p_instance->p_sensor_data->p_twi_mngr->p_queue->size < LPS22HB_MIN_QUEUE_SIZE)
{
return NRF_ERROR_INVALID_LENGTH;
}
err_code = lps22hb_cfg_commit(p_instance);
return err_code;
}
ret_code_t lps22hb_autorifp_enable(lps22hb_instance_t * p_instance, bool enable)
{
ASSERT(p_instance != NULL);
uint8_t reg = p_instance->interrupt_cfg;
if (enable == true)
{
NRF_TWI_SENSOR_REG_SET(reg, LPS22HB_AUTORIFP_MASK, LPS22HB_AUTORIFP_POS, 1);
}
else
{
NRF_TWI_SENSOR_REG_SET(reg, LPS22HB_RESET_ARP_MASK, LPS22HB_RESET_ARP_POS, 1);
}
uint8_t send_msg[] = {
LPS22HB_REG_INTERRUPT_CONFIG,
reg
};
return nrf_twi_sensor_write(p_instance->p_sensor_data,
p_instance->sensor_addr,
send_msg,
ARRAY_SIZE(send_msg),
true);
}
ret_code_t lps22hb_autozero_enable(lps22hb_instance_t * p_instance, bool enable)
{
ASSERT(p_instance != NULL);
uint8_t reg = p_instance->interrupt_cfg;
if (enable == true)
{
NRF_TWI_SENSOR_REG_SET(reg, LPS22HB_AUTOZERO_MASK, LPS22HB_AUTOZERO_POS, 1);
}
else
{
NRF_TWI_SENSOR_REG_SET(reg, LPS22HB_RESET_AZ_MASK, LPS22HB_RESET_AZ_POS, 1);
}
uint8_t send_msg[] = {
LPS22HB_REG_INTERRUPT_CONFIG,
reg
};
return nrf_twi_sensor_write(p_instance->p_sensor_data,
p_instance->sensor_addr,
send_msg,
ARRAY_SIZE(send_msg),
true);
}
void lps22hb_data_rate_set(lps22hb_instance_t * p_instance, lps22hb_odr_t odr)
{
ASSERT(p_instance != NULL);
NRF_TWI_SENSOR_REG_SET(p_instance->ctrl_reg[0], LPS22HB_ODR_MASK, LPS22HB_ODR_POS, odr);
}
ret_code_t lps22hb_data_read(lps22hb_instance_t * p_instance,
lps22hb_data_callback_t user_callback,
lps22hb_data_t * p_out_data,
uint8_t samples)
{
ASSERT(p_instance != NULL);
ret_code_t err_code;
err_code = nrf_twi_sensor_reg_read(p_instance->p_sensor_data,
p_instance->sensor_addr,
LPS22HB_REG_PRESS_OUT_XL,
(nrf_twi_sensor_reg_cb_t) user_callback,
(uint8_t *) p_out_data,
samples * LPS22HB_BYTES_PER_SAMPLE);
return err_code;
}
void lps22hb_data_decode(lps22hb_data_t * p_data, uint8_t samples)
{
ASSERT(p_data != NULL);
lps22hb_raw_data_t * p_in_data = (lps22hb_raw_data_t *) p_data;
uint32_t pres;
uint16_t temp;
for (int i = samples-1; i >= 0; i--)
{
pres = ((uint32_t) p_in_data[i].press_out_xl) |
(((uint32_t) p_in_data[i].press_out_l) << 8) |
(((uint32_t) p_in_data[i].press_out_h) << 16);
pres <<= 8;
temp = ((uint16_t) p_in_data[i].temp_out_l) |
(((uint16_t) p_in_data[i].temp_out_h) << 8);
// Dividing by 256 because signed integer can't be shifted by 8
p_data[i].pressure = *((int32_t *) &pres) / 256;
p_data[i].temperature = *((int16_t *) &temp);
}
}
ret_code_t lps22hb_threshold_set(lps22hb_instance_t * p_instance, uint16_t thr)
{
ASSERT(p_instance != NULL);
thr *= 16;
uint8_t send_msg[] = {
LPS22HB_REG_THS_P_L,
thr & 0x00FFU,
thr >> 8
};
ret_code_t err_code;
err_code = nrf_twi_sensor_write(p_instance->p_sensor_data,
p_instance->sensor_addr,
send_msg,
ARRAY_SIZE(send_msg),
true);
return err_code;
}
ret_code_t lps22hb_ref_pressure_set(lps22hb_instance_t * p_instance, int32_t pressure)
{
ASSERT(p_instance != NULL);
// Multiplying by 256 because signed integer can't be shifted by 8
pressure *= 256;
uint32_t pres = *((uint32_t *) &pressure);
pres >>= 8;
uint8_t send_msg[] = {
LPS22HB_REG_REF_P_XL,
pres & 0x00FFU,
(pres >> 8) & 0x00FFU,
(pres >> 16) & 0x00FFU
};
ret_code_t err_code;
err_code = nrf_twi_sensor_write(p_instance->p_sensor_data,
p_instance->sensor_addr,
send_msg,
ARRAY_SIZE(send_msg),
true);
return err_code;
}
ret_code_t lps22hb_offset_set(lps22hb_instance_t * p_instance, int16_t offset)
{
ASSERT(p_instance != NULL);
offset *= 16;
uint16_t off = *((uint16_t *) &offset);
uint8_t send_msg[] = {
LPS22HB_REG_RPDS_L,
off & 0x00FFU,
off >> 8
};
ret_code_t err_code;
err_code = nrf_twi_sensor_write(p_instance->p_sensor_data,
p_instance->sensor_addr,
send_msg,
ARRAY_SIZE(send_msg),
true);
return err_code;
}
ret_code_t lps22hb_cfg_commit(lps22hb_instance_t * p_instance)
{
ASSERT(p_instance != NULL);
p_instance->ctrl_reg[1] |= LPS22HB_CTRL_REG2_DEFAULT;
p_instance->ctrl_reg[0] &= ~LPS22HB_CTRL1_VALID_MASK;
p_instance->ctrl_reg[1] &= ~LPS22HB_CTRL2_VALID_MASK;
ret_code_t err_code;
err_code = nrf_twi_sensor_reg_write(p_instance->p_sensor_data,
p_instance->sensor_addr,
LPS22HB_REG_INTERRUPT_CONFIG,
&p_instance->interrupt_cfg,
1);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
err_code = nrf_twi_sensor_reg_write(p_instance->p_sensor_data,
p_instance->sensor_addr,
LPS22HB_REG_CTRL1,
p_instance->ctrl_reg,
3);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
err_code = nrf_twi_sensor_reg_write(p_instance->p_sensor_data,
p_instance->sensor_addr,
LPS22HB_REG_FIFO_CTRL,
&p_instance->fifo_ctrl,
1);
return err_code;
}
ret_code_t lps22hb_sw_reset(lps22hb_instance_t * p_instance)
{
ASSERT(p_instance != NULL);
uint8_t reg_val = p_instance->ctrl_reg[1];
NRF_TWI_SENSOR_REG_SET(reg_val, LPS22HB_SWRESET_MASK, LPS22HB_SWRESET_POS, 1);
uint8_t send_msg[] = {
LPS22HB_REG_CTRL2,
reg_val
};
ret_code_t err_code;
err_code = nrf_twi_sensor_write(p_instance->p_sensor_data,
p_instance->sensor_addr,
send_msg,
ARRAY_SIZE(send_msg),
true);
return err_code;
}
ret_code_t lps22hb_boot(lps22hb_instance_t * p_instance)
{
ASSERT(p_instance != NULL);
uint8_t reg_val = p_instance->ctrl_reg[1];
NRF_TWI_SENSOR_REG_SET(reg_val, LPS22HB_BOOT_MASK, LPS22HB_BOOT_POS, 1);
uint8_t send_msg[] = {
LPS22HB_REG_CTRL2,
reg_val
};
ret_code_t err_code;
err_code = nrf_twi_sensor_write(p_instance->p_sensor_data,
p_instance->sensor_addr,
send_msg,
ARRAY_SIZE(send_msg),
true);
return err_code;
}
ret_code_t lps22hb_oneshot(lps22hb_instance_t * p_instance)
{
ASSERT(p_instance != NULL);
uint8_t reg_val = p_instance->ctrl_reg[1];
NRF_TWI_SENSOR_REG_SET(reg_val, LPS22HB_ONE_SHOT_MASK, LPS22HB_ONE_SHOT_POS, 1);
uint8_t send_msg[] = {
LPS22HB_REG_CTRL2,
reg_val
};
ret_code_t err_code;
err_code = nrf_twi_sensor_write(p_instance->p_sensor_data,
p_instance->sensor_addr,
send_msg,
ARRAY_SIZE(send_msg),
true);
return err_code;
}
ret_code_t lps22hb_low_power_enable(lps22hb_instance_t * p_instance, bool enable)
{
ASSERT(p_instance != NULL);
uint8_t send_msg[] = {
LPS22HB_REG_RES_CONF,
enable
};
ret_code_t err_code;
err_code = nrf_twi_sensor_write(p_instance->p_sensor_data,
p_instance->sensor_addr,
send_msg,
ARRAY_SIZE(send_msg),
true);
return err_code;
}

View File

@@ -0,0 +1,512 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef LPS22HB_H
#define LPS22HB_H
#include "nrf_twi_sensor.h"
#include "lps22hb_internal.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Possible sensor addresses.
*/
#define LPS22HB_BASE_ADDRESS_LOW 0x5CU
#define LPS22HB_BASE_ADDRESS_HIGH 0x5DU
// WHO_AM_I register value
#define LPS22HB_WHO_AM_I 0xB1
// Minimum nrf_twi_sensor message buffer size and nrf_twi_mngr queue length.
#define LPS22HB_MIN_QUEUE_SIZE 4
/**
* @brief Sensor driver usage.
*
* Sensor instance has to be defined first in global context using @ref LPS22HB_INSTANCE DEF.
* After that it has to be initialized using @ref lps22hb_init.
* At this point sensor instance is ready and all other functions can be used.
*
* There are two ways in which sensor settings are set:
*
* First one are asynchronous macros, using them does not change real sensor settings
* until @ref lps22hb_cfg_commit is called.
* Example:
* LPS22HB_DATA_CFG(m_sensor1, LPS22HB_ODR_POWERDOWN, false, false);
* LPS22HB_FIFO_CFG(m_sensor1, LPS22HB_STREAM, true, false, 15);
* lps22hb_cfg_commit(&m_sensor1);
*
* Second way are functions, functions schedule TWI operation using @ref nrf_twi_sensor module.
* After calling function, setting will be automatically send to sensor when TWI bus is free.
* Example:
* lps22hb_low_power_enable(&m_sensor1, true);
* lps22hb_offset_set(&m_sensor1, -27);
*
* There are designated functions to read status sensor registers e.g. @ref lps22hb_int_source_read
* As parameters they receive function to be called after register is read, and pointer where
* register value should be stored. From that value specific parameters can be extracted
* using @ref NRF_TWI_SENSOR_REG_VAL_GET macro.
* Example:
* uint8_t ia = NRF_TWI_SENSOR_REG_VAL_GET(int_source_reg, LPS22HB_IA_MASK, LPS22HB_IA_POS);
*
* Other functions are self-explanatory or have description on their usage.
*/
/**
* @brief Output data rate settings.
*/
typedef enum
{
LPS22HB_ODR_POWERDOWN,
LPS22HB_ODR_1HZ,
LPS22HB_ODR_10HZ,
LPS22HB_ODR_25HZ,
LPS22HB_ODR_50HZ,
LPS22HB_ODR_75HZ
} lps22hb_odr_t;
/**
* @brief Fifo mode settings.
*/
typedef enum
{
LPS22HB_BYPASS,
LPS22HB_FIFO,
LPS22HB_STREAM,
LPS22HB_STREAM_TO_FIFO,
LPS22HB_BYPASS_TO_STREAM,
LPS22HB_RESERVED_FIFO,
LPS22HB_DYNAMIC_STREAM,
LPS22HB_BYPASS_TO_FIFO
} lps22hb_fifo_mode_t;
/**
* @brief Low pass filter configuration.
*/
typedef enum
{
LPS22HB_LPFP_DISABLE = 1,
LPS22HB_LPFP_ODR_DIV_9,
LPS22HB_LPFP_ODR_DIV_20
} lps22hb_lpfp_t;
/**
* @brief Pressure and temperature output data.
*
* @note To get pressure in hPa it has to be divided by 4096.
* To get temperature in degrees it has to be divided by 100.
*/
typedef struct
{
int32_t pressure;
int16_t temperature;
} lps22hb_data_t;
/**
* @brief Data callback prototype.
*
* @param[in] result Result of operation (NRF_SUCCESS on success,
* otherwise a relevant error code).
* @param[in] p_raw_data Pointer to raw sensor data structure.
*/
typedef void (* lps22hb_data_callback_t)(ret_code_t result, lps22hb_data_t * p_raw_data);
/**
* @brief Macro creating lps22hb sensor instance.
*
* @param[in] _lps22hb_inst_name Sensor instance name.
* @param[in] _p_twi_sensor Pointer to common TWI sensor instance.
* @param[in] _sensor_address Sensor base address.
*/
#define LPS22HB_INSTANCE_DEF(_lps22hb_inst_name, _p_twi_sensor, _sensor_address) \
LPS22HB_INTERNAL_INSTANCE_DEF(_lps22hb_inst_name, _p_twi_sensor, _sensor_address)
/**
* ===============================================================================================
* @brief Sensor configuration macros.
*
* @note After setting configuration using these macros, it has to be committed to sensor
* using @ref lps22hb_cfg_commit
*/
/**
* @brief Macro for interrupt configuration.
*
* @param[in] _s Sensor instance.
* @param[in] _diff_en Enable interrupt generation. True if enabled.
* @param[in] _lir Latch interrupt request to INT_SOURCE register. True if enabled.
* @param[in] _ple Enable interrupt generation on pressure low event. True if enabled.
* @param[in] _phe Enable interrupt generation on pressure high event. True if enabled.
*/
#define LPS22HB_INT_CFG(_s, _diff_en, _lir, _ple, _phe)\
LPS22HB_INTERNAL_INT_CFG(_s, _diff_en, _lir, _ple, _phe)
/**
* @brief Macro for data acquisition configuration.
*
* @param[in] _s Sensor instance.
* @param[in] _odr Desired output data rate. @ref lps22hb_odr_t
* @param[in] _f_en Enables filter. True if enabled.
* @param[in] _f_cfg Filter configuration.
* @arg true Filter bandwidth is ODR/20
* @arg false Filter bandwidth is ODR/9
*/
#define LPS22HB_DATA_CFG(_s, _odr, _f_en, _f_cfg)\
LPS22HB_INTERNAL_DATA_CFG(_s, _odr, _f_en, _f_cfg)
/**
* @brief Macro for FIFO configuration.
*
* @param[in] _s Sensor instance.
* @param[in] _f_mode FIFO mode. @ref lps22hb_fifo_mode_t
* @param[in] _f_en Enable FIFO. True if enabled.
* @param[in] _f_stop Stop on FIFO watermark. True if enabled.
* @param[in] _f_wtm FIFO watermark value. Between 0 and 31.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
#define LPS22HB_FIFO_CFG(_s, _f_mode, _f_en, _f_stop, _f_wtm)\
LPS22HB_INTERNAL_FIFO_CFG(_s, _f_mode, _f_en, _f_stop, _f_wtm)
/**
* @brief Macro for INT_DRDY pin configuration.
* @param[in] _s Sensor instance.
* @param[in] _activ Active state.
* @arg true Active low.
* @arg false Active high.
* @param[in] _pp_od Pin operation.
* @arg true Open drain.
* @arg false Push-pull.
* @param[in] _fss FIFO full flag. True if enabled.
* @param[in] _fth FIFO watermark status. True if enabled.
* @param[in] _ovr FIFO overrun interrupt. True if enabled.
* @param[in] _drdy Data Ready signal. True if enabled.
* @param[in] _high Pressure higher than interrupt threshold. True if enabled.
* @param[in] _low Pressure lower than interrupt threshold. True if enabled.
*/
#define LPS22HB_DRDY_CFG(_s, _activ, _pp_od, _fss, _fth, _ovr, _drdy, _high, _low)\
LPS22HB_INTERNAL_DRDY_CFG(_s, _activ, _pp_od, _fss, _fth, _ovr, _drdy, _high, _low)
/**
* ===============================================================================================
*/
/**
* @brief Function for initializing lps22hb sensor.
*
* Writes configuration data in sensor instance to sensor.
*
* @param[in] p_instance Pointer to sensor instance created by macro
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t lps22hb_init(lps22hb_instance_t * p_instance);
/**
* @brief Function for enabling autorifp.
*
* @param[in] p_instance Pointer to sensor instance
* @param[in] enable Autorifp setting.
* @arg true Autorifp is enabled.
* @arg false Autorifp is disabled and reset.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t lps22hb_autorifp_enable(lps22hb_instance_t * p_instance, bool enable);
/**
* @brief Function for enabling autozero.
*
* @param[in] p_instance Pointer to sensor instance
* @param[in] enable Autozero setting.
* @arg true Autozero is enabled.
* @arg false Autozero is disabled and reset.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t lps22hb_autozero_enable(lps22hb_instance_t * p_instance, bool enable);
/**
* @brief Function performing software reset.
*
* @param[in] p_instance Pointer to sensor instance.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t lps22hb_sw_reset(lps22hb_instance_t * p_instance);
/**
* @brief Function performing boot.
*
* @param[in] p_instance Pointer to sensor instance.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t lps22hb_boot(lps22hb_instance_t * p_instance);
/**
* @brief Function setting oneshot.
*
* @param[in] p_instance Pointer to sensor instance.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t lps22hb_oneshot(lps22hb_instance_t * p_instance);
/**
* @brief Function for reading pressure and temperature data.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] user_callback Function to be called when data is gathered.
* @param[out] p_out_data Pointer to raw data buffer.
* @param[in] samples Number of data samples to read.
*
* @note Data can be read in two ways. With or without sensors FIFO.
* FIFO mode depends on FIFO mode set using lps22hb_fifo_mode_set function.
* FIFO is enabled using lps22hb_fifo_enable function.
* Without FIFO only one sample can be acquired, p_out_data can be pointer to single variable.
* With FIFO enabled, data can be read in burst mode, p_out_data table has to be same
* or bigger than number of samples to read.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
ret_code_t lps22hb_data_read(lps22hb_instance_t * p_instance,
lps22hb_data_callback_t user_callback,
lps22hb_data_t * p_out_data,
uint8_t samples);
/**
* @brief Function for converting raw sensor data to real.
*
* @param[in/out] p_data Pointer to data to be processed.
* @param[in] samples Number of samples to be processed.
*
* @note After data is processed, structure contains pressure in hPa*4096
* and temperature in Celsius degrees*100
*/
void lps22hb_data_decode(lps22hb_data_t * p_data, uint8_t samples);
/**
* @brief Function for setting reference pressure.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] pressure Reference pressure in hPa*4096
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t lps22hb_ref_pressure_set(lps22hb_instance_t * p_instance, int32_t pressure);
/**
* @brief Function for setting pressure offset.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] offset Pressure offset in hPa.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t lps22hb_offset_set(lps22hb_instance_t * p_instance, int16_t offset);
/**
* @brief Function for setting interrupt threshold.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] threshold Interrupt threshold in hPa.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t lps22hb_threshold_set(lps22hb_instance_t * p_instance, uint16_t threshold);
/**
* @brief Function for enabling low power mode.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] enable Enable low power mode. True if enabled.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t lps22hb_low_power_enable(lps22hb_instance_t * p_instance, bool enable);
/**
* @brief Function for setting sensor configuration.
*
* @param[in] p_instance Pointer to sensor instance.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t lps22hb_cfg_commit(lps22hb_instance_t * p_instance);
/**
* @brief Function for resetting filter.
*
* @param[in] p_instance Pointer to sensor instance.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
__STATIC_INLINE ret_code_t lps22hb_reset_filter(lps22hb_instance_t * p_instance);
/**
* @brief Function for reading who am i register.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] user_cb Function to be called after register is read.
* @param[out] reg_val Register value, single uint8_t.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
__STATIC_INLINE ret_code_t lps22hb_who_am_i_read(lps22hb_instance_t * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * reg_val);
/**
* @brief Function for reading interrupt source register.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] user_cb Function to be called after register is read.
* @param[out] reg_val Register value, single uint8_t.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
__STATIC_INLINE ret_code_t lps22hb_int_source_read(lps22hb_instance_t * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * reg_val);
/**
* @brief Function for reading fifo status register.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] user_cb Function to be called after register is read.
* @param[out] reg_val Register value, single uint8_t.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
__STATIC_INLINE ret_code_t lps22hb_fifo_status_read(lps22hb_instance_t * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * reg_val);
/**
* @brief Function for reading status register.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] user_cb Function to be called after register is read.
* @param[out] reg_val Register value, single uint8_t.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
__STATIC_INLINE ret_code_t lps22hb_status_read(lps22hb_instance_t * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * reg_val);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE ret_code_t lps22hb_reset_filter(lps22hb_instance_t * p_instance)
{
ASSERT(p_instance != NULL);
static uint8_t temp;
return nrf_twi_sensor_reg_read(p_instance->p_sensor_data,
p_instance->sensor_addr,
LPS22HB_REG_LPFP_RES,
NULL,
&temp,
1);
}
__STATIC_INLINE ret_code_t lps22hb_who_am_i_read(lps22hb_instance_t * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * reg_val)
{
ASSERT(p_instance != NULL);
return nrf_twi_sensor_reg_read(p_instance->p_sensor_data,
p_instance->sensor_addr,
LPS22HB_REG_WHO_AM_I,
user_cb,
reg_val,
1);
}
__STATIC_INLINE ret_code_t lps22hb_int_source_read(lps22hb_instance_t * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * reg_val)
{
ASSERT(p_instance != NULL);
return nrf_twi_sensor_reg_read(p_instance->p_sensor_data,
p_instance->sensor_addr,
LPS22HB_REG_INT_SOURCE,
user_cb,
reg_val,
1);
}
__STATIC_INLINE ret_code_t lps22hb_fifo_status_read(lps22hb_instance_t * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * reg_val)
{
ASSERT(p_instance != NULL);
return nrf_twi_sensor_reg_read(p_instance->p_sensor_data,
p_instance->sensor_addr,
LPS22HB_REG_FIFO_STATUS,
user_cb,
reg_val,
1);
}
__STATIC_INLINE ret_code_t lps22hb_status_read(lps22hb_instance_t * p_instance,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * reg_val)
{
ASSERT(p_instance != NULL);
return nrf_twi_sensor_reg_read(p_instance->p_sensor_data,
p_instance->sensor_addr,
LPS22HB_REG_STATUS,
user_cb,
reg_val,
1);
}
#endif //SUPPRESS_INLINE_IMPLEMENTATION
#ifdef __cplusplus
}
#endif
#endif // LPS22HB_H

View File

@@ -0,0 +1,365 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef LPS22HB_INTERNAL_H
#define LPS22HB_INTERNAL_H
#ifdef __cplusplus
extern "C" {
#endif
#define LPS22HB_BYTES_PER_SAMPLE 5
/**
* @brief LPS22HB sensor registers.
*/
#define LPS22HB_REG_INTERRUPT_CONFIG 0x0B
#define LPS22HB_REG_THS_P_L 0x0C
#define LPS22HB_REG_THS_P_H 0x0D
#define LPS22HB_REG_WHO_AM_I 0x0F
#define LPS22HB_REG_CTRL1 0x10
#define LPS22HB_REG_CTRL2 0x11
#define LPS22HB_REG_CTRL3 0x12
#define LPS22HB_REG_FIFO_CTRL 0x14
#define LPS22HB_REG_REF_P_XL 0x15
#define LPS22HB_REG_REF_P_L 0x16
#define LPS22HB_REG_REF_P_H 0x17
#define LPS22HB_REG_RPDS_L 0x18
#define LPS22HB_REG_RPDS_H 0x19
#define LPS22HB_REG_RES_CONF 0x1A
#define LPS22HB_REG_INT_SOURCE 0x25
#define LPS22HB_REG_FIFO_STATUS 0x26
#define LPS22HB_REG_STATUS 0x27
#define LPS22HB_REG_PRESS_OUT_XL 0x28
#define LPS22HB_REG_PRESS_OUT_L 0x29
#define LPS22HB_REG_PRESS_OUT_H 0x2A
#define LPS22HB_REG_TEMP_OUT_L 0x2B
#define LPS22HB_REG_TEMP_OUT_H 0x2C
#define LPS22HB_REG_LPFP_RES 0x33
/**
* @brief Interrupt config register bitmasks.
*/
// Bitmasks for AUTORIFP.
#define LPS22HB_AUTORIFP_POS 7
#define LPS22HB_AUTORIFP_MASK (1 << LPS22HB_AUTORIFP_POS)
// Bitmasks for RESET_ARP.
#define LPS22HB_RESET_ARP_POS 6
#define LPS22HB_RESET_ARP_MASK (1 << LPS22HB_RESET_ARP_POS)
// Bitmasks for AUTOZERO.
#define LPS22HB_AUTOZERO_POS 5
#define LPS22HB_AUTOZERO_MASK (1 << LPS22HB_AUTOZERO_POS)
// Bitmasks for RESET_AZ.
#define LPS22HB_RESET_AZ_POS 4
#define LPS22HB_RESET_AZ_MASK (1 << LPS22HB_RESET_AZ_POS)
// Bitmasks for DIFF_EN.
#define LPS22HB_DIFF_EN_POS 3
#define LPS22HB_DIFF_EN_MASK (1 << LPS22HB_DIFF_EN_POS)
// Bitmasks for LIR.
#define LPS22HB_LIR_POS 2
#define LPS22HB_LIR_MASK (1 << LPS22HB_LIR_POS)
// Bitmasks for PLE.
#define LPS22HB_PLE_POS 1
#define LPS22HB_PLE_MASK (1 << LPS22HB_PLE_POS)
// Bitmasks for PHE.
#define LPS22HB_PHE_POS 0
#define LPS22HB_PHE_MASK (1 << LPS22HB_PHE_POS)
/**
* @brief Control register 1 bitmasks.
*/
// Register validity bitmask.
#define LPS22HB_CTRL1_VALID_MASK 0x80
// Bitmasks for ODR.
#define LPS22HB_ODR_POS 4
#define LPS22HB_ODR_MASK (7 << LPS22HB_ODR_POS)
// Bitmasks for EN_LPFP.
#define LPS22HB_EN_LPFP_POS 3
#define LPS22HB_EN_LPFP_MASK (1 << LPS22HB_EN_LPFP_POS)
// Bitmasks for LPFP_CFG.
#define LPS22HB_LPFP_CFG_POS 2
#define LPS22HB_LPFP_CFG_MASK (1 << LPS22HB_LPFP_CFG_POS)
// Bitmasks for BDU.
#define LPS22HB_BDU_POS 1
#define LPS22HB_BDU_MASK (1 << LPS22HB_BDU_POS)
// Bitmasks for SIM.
#define LPS22HB_SIM_POS 0
#define LPS22HB_SIM_MASK (1 << LPS22HB_SIM_POS)
/**
* @brief Control register 2 bitmasks.
*/
// Register validity bitmask.
#define LPS22HB_CTRL2_VALID_MASK 0x02
// Bitmasks for BOOT.
#define LPS22HB_BOOT_POS 7
#define LPS22HB_BOOT_MASK (1 << LPS22HB_BOOT_POS)
// Bitmasks for FIFO_EN.
#define LPS22HB_FIFO_EN_POS 6
#define LPS22HB_FIFO_EN_MASK (1 << LPS22HB_FIFO_EN_POS)
// Bitmasks for STOP_ON_FTH.
#define LPS22HB_STOP_ON_FTH_POS 5
#define LPS22HB_STOP_ON_FTH_MASK (1 << LPS22HB_STOP_ON_FTH_POS)
// Bitmasks for IF_ADD_INC.
#define LPS22HB_IF_ADD_INC_POS 4
#define LPS22HB_IF_ADD_INC_MASK (1 << LPS22HB_IF_ADD_INC_POS)
// Bitmasks for I2C_DIS.
#define LPS22HB_I2C_DIS_POS 3
#define LPS22HB_I2C_DIS_MASK (1 << LPS22HB_I2C_DIS_POS)
// Bitmasks for SWRESET.
#define LPS22HB_SWRESET_POS 2
#define LPS22HB_SWRESET_MASK (1 << LPS22HB_SWRESET_POS)
// Bitmasks for ONE_SHOT.
#define LPS22HB_ONE_SHOT_POS 0
#define LPS22HB_ONE_SHOT_MASK (1 << LPS22HB_ONE_SHOT_POS)
/**
* @brief Control register 3 bitmasks.
*/
// Bitmasks for INT_H_L.
#define LPS22HB_INT_H_L_POS 7
#define LPS22HB_INT_H_L_MASK (1 << LPS22HB_INT_H_L_POS)
// Bitmasks for PP_OD.
#define LPS22HB_PP_OD_POS 6
#define LPS22HB_PP_OD_MASK (1 << LPS22HB_PP_OD_POS)
// Bitmasks for F_FSS5.
#define LPS22HB_F_FSS5_POS 5
#define LPS22HB_F_FSS5_MASK (1 << LPS22HB_F_FSS5_POS)
// Bitmasks for F_FTH.
#define LPS22HB_F_FTH_POS 4
#define LPS22HB_F_FTH_MASK (1 << LPS22HB_F_FTH_POS)
// Bitmasks for F_OVR.
#define LPS22HB_F_OVR_POS 3
#define LPS22HB_F_OVR_MASK (1 << LPS22HB_F_OVR_POS)
// Bitmasks for DRDY.
#define LPS22HB_DRDY_POS 2
#define LPS22HB_DRDY_MASK (1 << LPS22HB_DRDY_POS)
// Bitmasks for INT_S.
#define LPS22HB_INT_S_POS 0
#define LPS22HB_INT_S_MASK (3 << LPS22HB_INT_S_POS)
/**
* @brief Fifo control register bitmasks.
*/
// Bitmasks for F_MODE.
#define LPS22HB_F_MODE_POS 5
#define LPS22HB_F_MODE_MASK (7 << LPS22HB_F_MODE_POS)
// Bitmasks for WTM
#define LPS22HB_WTM_POS 0
#define LPS22HB_WTM_MASK (0x1F << LPS22HB_WTM_POS)
/**
* @brief Low power mode register bitmasks.
*/
// Register validity bitmask.
#define LPS22HB_RES_CONF_VALID_MASK 0xFE
// Bitmasks for LC_EN
#define LPS22HB_LC_EN_POS 0
#define LPS22HB_LC_EN_MASK (1 << LPS22HB_LC_EN_POS)
/**
* @brief INT source register bitmasks.
*/
// Bitmasks for IA
#define LPS22HB_IA_POS 2
#define LPS22HB_IA_MASK (1 << LPS22HB_IA_POS)
// Bitmasks for PL
#define LPS22HB_PL_POS 1
#define LPS22HB_PL_MASK (1 << LPS22HB_PL_POS)
// Bitmasks for PH
#define LPS22HB_PH_POS 0
#define LPS22HB_PH_MASK (1 << LPS22HB_PH_POS)
/**
* @brief FIFO status register bitmasks.
*/
// Bitmasks for FTH_FIFO
#define LPS22HB_FTH_FIFO_POS 7
#define LPS22HB_FTH_FIFO_MASK (1 << LPS22HB_FTH_FIFO_POS)
// Bitmasks for OVR
#define LPS22HB_OVR_POS 6
#define LPS22HB_OVR_MASK (1 << LPS22HB_OVR_POS)
// Bitmasks for stored data level
#define LPS22HB_FSS_POS 0
#define LPS22HB_FSS_MASK (0x3F << LPS22HB_FSS_POS)
/**
* @brief Status register bitmasks.
*/
// Bitmasks for T_OR.
#define LPS22HB_T_OR_POS 5
#define LPS22HB_T_OR_MASK (1 << LPS22HB_T_OR_POS)
// Bitmasks for P_OR.
#define LPS22HB_P_OR_POS 4
#define LPS22HB_P_OR_MASK (1 << LPS22HB_P_OR_POS)
// Bitmasks for T_DA.
#define LPS22HB_T_DA_POS 1
#define LPS22HB_T_DA_MASK (1 << LPS22HB_T_DA_POS)
// Bitmasks for P_DA.
#define LPS22HB_P_DA_POS 0
#define LPS22HB_P_DA_MASK (1 << LPS22HB_P_DA_POS)
/**
* @brief Config registers defaults.
*/
#define LPS22HB_CTRL_REG2_DEFAULT 0x10
/**
* @brief Raw pressure and temperature data.
*
* @note For internal use only.
*/
typedef struct
{
uint8_t press_out_xl;
uint8_t press_out_l;
uint8_t press_out_h;
uint8_t temp_out_l;
uint8_t temp_out_h;
} lps22hb_raw_data_t;
/**
* @brief Structure holding sensor instance
*
* @note For internal use only.
*/
typedef struct
{
nrf_twi_sensor_t * const p_sensor_data;
uint8_t const sensor_addr;
uint8_t interrupt_cfg;
uint8_t ctrl_reg[3];
uint8_t fifo_ctrl;
} lps22hb_instance_t;
#define LPS22HB_INTERNAL_INSTANCE_DEF(_lps22hb_inst_name, _p_twi_sensor, _sensor_address) \
static lps22hb_instance_t _lps22hb_inst_name = \
{ \
.p_sensor_data = _p_twi_sensor, \
.sensor_addr = _sensor_address, \
}
#define LPS22HB_INTERNAL_INT_CFG(_s, _diff_en, _lir, _ple, _phe) \
NRF_TWI_SENSOR_REG_SET(_s.interrupt_cfg, LPS22HB_DIFF_EN_MASK, LPS22HB_DIFF_EN_POS, _diff_en); \
NRF_TWI_SENSOR_REG_SET(_s.interrupt_cfg, LPS22HB_LIR_MASK, LPS22HB_LIR_POS, _lir); \
NRF_TWI_SENSOR_REG_SET(_s.interrupt_cfg, LPS22HB_PLE_MASK, LPS22HB_PLE_POS, _ple); \
NRF_TWI_SENSOR_REG_SET(_s.interrupt_cfg, LPS22HB_PHE_MASK, LPS22HB_PHE_POS, _phe);
#define LPS22HB_INTERNAL_DATA_CFG(_s, _odr, _f_en, _f_cfg) \
NRF_TWI_SENSOR_REG_SET(_s.ctrl_reg[0], LPS22HB_ODR_MASK, LPS22HB_ODR_POS, _odr); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl_reg[0], LPS22HB_EN_LPFP_MASK, LPS22HB_EN_LPFP_POS, _f_en); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl_reg[0], LPS22HB_LPFP_CFG_MASK, LPS22HB_LPFP_CFG_POS, _f_cfg);
#define LPS22HB_INTERNAL_FIFO_CFG(_s, _f_mode, _f_en, _f_stop, _f_wtm) \
NRF_TWI_SENSOR_REG_SET(_s.fifo_ctrl, LPS22HB_F_MODE_MASK, LPS22HB_F_MODE_POS, _f_mode); \
NRF_TWI_SENSOR_REG_SET(_s.fifo_ctrl, LPS22HB_WTM_MASK, LPS22HB_WTM_POS, _f_wtm); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl_reg[1], LPS22HB_FIFO_EN_MASK, LPS22HB_FIFO_EN_POS, _f_en); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl_reg[1], \
LPS22HB_STOP_ON_FTH_MASK, \
LPS22HB_STOP_ON_FTH_POS, \
_f_stop)
#define LPS22HB_INTERNAL_DRDY_CFG(_s, _activ, _pp_od, _fss, _fth, _ovr, _drdy, _high, _low) \
NRF_TWI_SENSOR_REG_SET(_s.ctrl_reg[2], LPS22HB_INT_H_L_MASK, LPS22HB_INT_H_L_POS, _activ); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl_reg[2], LPS22HB_PP_OD_MASK, LPS22HB_PP_OD_POS, _pp_od); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl_reg[2], LPS22HB_F_FSS5_MASK, LPS22HB_F_FSS5_POS, _fss); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl_reg[2], LPS22HB_F_FTH_MASK, LPS22HB_F_FTH_POS, _fth); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl_reg[2], LPS22HB_F_OVR_MASK, LPS22HB_F_OVR_POS, _ovr); \
NRF_TWI_SENSOR_REG_SET(_s.ctrl_reg[2], \
LPS22HB_INT_S_MASK, \
LPS22HB_INT_S_POS, \
(_low << 1) + _high);
#ifdef __cplusplus
}
#endif
#endif // LPS22HB_INTERNAL_H

View File

@@ -0,0 +1,71 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "max9850.h"
#include <string.h>
ret_code_t max9850_init(max9850_config_t const * p_max9850)
{
ret_code_t ret = NRF_SUCCESS;
ret = nrf_drv_twi_init(&p_max9850->twi, &p_max9850->twi_cfg, NULL, NULL);
if (ret != NRF_SUCCESS)
{
return ret;
}
nrf_drv_twi_enable(&p_max9850->twi);
/*Probe device*/
uint8_t rx[] = {0};
ret = nrf_drv_twi_rx(&p_max9850->twi, p_max9850->twi_addr, rx, sizeof(rx));
if (ret != NRF_SUCCESS)
{
return ret;
}
uint8_t regs[sizeof(max9850_regmap_t) + 1];
regs[0] = 0x00;
memcpy(regs + 1, &p_max9850->regmap, sizeof(max9850_regmap_t));
/*Write configuration*/
return nrf_drv_twi_tx(&p_max9850->twi, p_max9850->twi_addr, regs, sizeof(regs), false);
}

View File

@@ -0,0 +1,130 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef MAX9850_H__
#define MAX9850_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "nrf_drv_twi.h"
/**
* @brief Default MAX9850 TWI configuration
*
* @param scl_pin SCL pin number
* @param sda_pin SDA pin number
*/
#define MAX9850_DEFAULT_TWI_CONFIG(scl_pin, sda_pin) { \
.scl = scl_pin, \
.sda = sda_pin, \
.frequency = NRF_DRV_TWI_FREQ_100K, \
.interrupt_priority = APP_IRQ_PRIORITY_HIGH, \
.clear_bus_init = false, \
.hold_bus_uninit = false \
}
/**
* @brief Internal MAX9850 register map
* */
typedef struct {
uint8_t status_a; //!< Status register A (R)
uint8_t status_b; //!< Status register B (R)
uint8_t volume; //!< Volume control (RW)
uint8_t general_purpose; //!< General purpose register (RW)
uint8_t interrupt_enable; //!< Interrupt enable (RW)
uint8_t enable; //!< Enable register (RW)
uint8_t clock; //!< Clock control (RW)
uint8_t charge_pump; //!< Charge pump (RW)
uint8_t lrclk_msb; //!< LRCLK MSB register (RW)
uint8_t lrclk_lsb; //!< LRCLK LSB register (RW)
uint8_t digital_audio; //!< Digital audio (RW)
} max9850_regmap_t;
/**
* @brief MAX9850 register map after reset
* */
#define MAX9850_DEFAULT_REGMAP() { \
.status_a = 0, \
.status_b = 0, \
.volume = 0x0C, \
.general_purpose = 0, \
.interrupt_enable = 0, \
.enable = 0, \
.clock = 0, \
.charge_pump = 0, \
.lrclk_msb = 0, \
.lrclk_lsb = 0, \
.digital_audio = 0, \
}
/**
* @brief Helper macro for creating MAX9850 TWI address
* */
#define MAX9850_TWI_ADDR(v) (0x10 + (v))
/**
* @brief MAX9850 configuration
* */
typedef struct {
nrf_drv_twi_t twi; //!< TWI instance
nrf_drv_twi_config_t twi_cfg; //!< TWI configuration
max9850_regmap_t regmap; //!< MAX9850 register map
uint8_t twi_addr; //!< MAX9850 TWI address
} max9850_config_t;
/**
* @brief Initializes MAX9850 IC
*
* @param p_max9850 MAX9850 configuration
*
* @return Standard error code
* */
ret_code_t max9850_init(max9850_config_t const * p_max9850);
#ifdef __cplusplus
}
#endif
#endif /* MAX9850_H__ */

View File

@@ -0,0 +1,156 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "mcp4725.h"
#include "nrf_drv_twi.h"
#include "nrf_delay.h"
#include "boards.h"
#include "app_util_platform.h"
/*lint ++flb "Enter library region" */
#define MCP4725_BASE_ADDRESS 0x60 //!< MCP4725 base address
#define MCP4725_DAC_ADDRESS 0x40 //!< MCP4725 write-to-dac register
#define MCP4725_EEPROM_ADDRESS 0x60 //!< MCP4725 write-to-eeprom register
#define RDY_BIT_POS 0x07 //!< Position of RDY bit
/* TWI instance. */
static const nrf_drv_twi_t m_twi = NRF_DRV_TWI_INSTANCE(TWI_INSTANCE_ID_USED);
/* Twi transfer indicators. */
volatile bool m_xfer_done = false;
volatile bool m_read_done = false;
/**
* @brief TWI events handler.
*/
static void twi_handler(nrf_drv_twi_evt_t const * p_event, void * p_context)
{
switch (p_event->type)
{
case NRF_DRV_TWI_EVT_DONE:
if (p_event->xfer_desc.type == NRF_DRV_TWI_XFER_TX)
{
m_xfer_done = true;
}
if (p_event->xfer_desc.type == NRF_DRV_TWI_XFER_RX)
{
m_read_done = true;
}
break;
default:
break;
}
}
/**
* @brief TWI initialization.
*
* @param[in] p_pins_config Pointer to structere holding pins numbers to be used by TWI.
*/
static ret_code_t twi_init(mcp4725_pins_config_t const * p_pins_config)
{
ret_code_t err_code;
const nrf_drv_twi_config_t twi_mcp4725_config = {
.scl = p_pins_config->scl_pin,
.sda = p_pins_config->sda_pin,
.frequency = NRF_DRV_TWI_FREQ_100K,
.interrupt_priority = APP_IRQ_PRIORITY_HIGH,
.clear_bus_init = false
};
err_code = nrf_drv_twi_init(&m_twi, &twi_mcp4725_config, twi_handler, NULL);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
nrf_drv_twi_enable(&m_twi);
return NRF_SUCCESS;
}
ret_code_t mcp4725_setup(mcp4725_pins_config_t const * p_pins_config)
{
ret_code_t err_code = twi_init(p_pins_config);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
return NRF_SUCCESS;
}
ret_code_t mcp4725_set_voltage(uint16_t val, bool write_eeprom)
{
/* Shift parameter val to get 2 8-bits values. */
uint8_t reg[3] = {write_eeprom ? MCP4725_EEPROM_ADDRESS : MCP4725_DAC_ADDRESS,
(val>>4), (val<<4)};
m_xfer_done = false;
ret_code_t err_code = nrf_drv_twi_tx(&m_twi, MCP4725_BASE_ADDRESS, reg, sizeof(reg), false);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
while (m_xfer_done == false);
return NRF_SUCCESS;
}
bool mcp4725_is_busy(void)
{
uint8_t busy;
m_read_done = false;
ret_code_t err_code = nrf_drv_twi_rx(&m_twi, MCP4725_BASE_ADDRESS, &busy, sizeof(busy));
if (err_code != NRF_SUCCESS)
{
return err_code;
}
while (m_read_done == false);
return (bool)(!(busy >> RDY_BIT_POS));
}
/*lint --flb "Leave library region" */

View File

@@ -0,0 +1,107 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef MCP4725_H
#define MCP4725_H
/*lint ++flb "Enter library region" */
#include <stdbool.h>
#include <stdint.h>
#include "app_util_platform.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @file
* @brief MCP4725 digital DAC driver.
*
*
* @defgroup mcp4725 MCP4725 digital DAC driver
* @{
* @ingroup ext_drivers
* @brief MCP4725 digital DAC driver.
*/
typedef struct
{
uint8_t scl_pin;
uint8_t sda_pin;
}mcp4725_pins_config_t;
/**
* @brief Function for setting up the driver.
*
* @param[in] p_pins_config Pointer to structere holding pins numbers to be used by TWI.
*
* @return Values returned by @ref nrfx_twi_init.
*/
ret_code_t mcp4725_setup(mcp4725_pins_config_t const * p_pins_config);
/**
* @brief Function for setting new value to DAC.
*
* @param[in] val 12-bit value. Base on it voltage is set (Vout = (val/4095) * Vcc).
* @param[in] write_eeprom Defines if value will be written to DAC only or to EEPROM memmory also.
*
* @return Values returned by @ref nrfx_twi_tx.
*/
ret_code_t mcp4725_set_voltage(uint16_t val, bool write_eeprom);
/**
* @brief Function for checking if DAC is busy saving data in EEPROM.
*
* @retval true If DAC is busy.
* @retval false If Dac is not busy.
*/
bool mcp4725_is_busy(void);
/**
*@}
**/
/*lint --flb "Leave library region" */
#ifdef __cplusplus
}
#endif
#endif //MCP4725_H

View File

@@ -0,0 +1,108 @@
/**
* Copyright (c) 2009 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <stdbool.h>
#include <stdint.h>
#include "twi_master.h"
#include "mpu6050.h"
/*lint ++flb "Enter library region" */
#define ADDRESS_WHO_AM_I (0x75U) // !< WHO_AM_I register identifies the device. Expected value is 0x68.
#define ADDRESS_SIGNAL_PATH_RESET (0x68U) // !<
static const uint8_t expected_who_am_i = 0x68U; // !< Expected value to get from WHO_AM_I register.
static uint8_t m_device_address; // !< Device address in bits [7:1]
bool mpu6050_init(uint8_t device_address)
{
bool transfer_succeeded = true;
m_device_address = (uint8_t)(device_address << 1);
// Do a reset on signal paths
uint8_t reset_value = 0x04U | 0x02U | 0x01U; // Resets gyro, accelerometer and temperature sensor signal paths.
transfer_succeeded &= mpu6050_register_write(ADDRESS_SIGNAL_PATH_RESET, reset_value);
// Read and verify product ID
transfer_succeeded &= mpu6050_verify_product_id();
return transfer_succeeded;
}
bool mpu6050_verify_product_id(void)
{
uint8_t who_am_i;
if (mpu6050_register_read(ADDRESS_WHO_AM_I, &who_am_i, 1))
{
if (who_am_i != expected_who_am_i)
{
return false;
}
else
{
return true;
}
}
else
{
return false;
}
}
bool mpu6050_register_write(uint8_t register_address, uint8_t value)
{
uint8_t w2_data[2];
w2_data[0] = register_address;
w2_data[1] = value;
return twi_master_transfer(m_device_address, w2_data, 2, TWI_ISSUE_STOP);
}
bool mpu6050_register_read(uint8_t register_address, uint8_t * destination, uint8_t number_of_bytes)
{
bool transfer_succeeded;
transfer_succeeded = twi_master_transfer(m_device_address, &register_address, 1, TWI_DONT_ISSUE_STOP);
transfer_succeeded &= twi_master_transfer(m_device_address|TWI_READ_BIT, destination, number_of_bytes, TWI_ISSUE_STOP);
return transfer_succeeded;
}
/*lint --flb "Leave library region" */

View File

@@ -0,0 +1,110 @@
/**
* Copyright (c) 2009 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef MPU6050_H
#define MPU6050_H
/*lint ++flb "Enter library region" */
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @file
* @brief MPU6050 gyro/accelerometer driver.
*
*
* @defgroup nrf_drivers_mpu6050 MPU6050 gyro/accelerometer driver
* @{
* @ingroup ext_drivers
* @brief MPU6050 gyro/accelerometer driver.
*/
/**
* @brief Function for initializing MPU6050 and verifies it's on the bus.
*
* @param device_address Device TWI address in bits [6:0].
* @return
* @retval true MPU6050 found on the bus and ready for operation.
* @retval false MPU6050 not found on the bus or communication failure.
*/
bool mpu6050_init(uint8_t device_address);
/**
@brief Function for writing a MPU6050 register contents over TWI.
@param[in] register_address Register address to start writing to
@param[in] value Value to write to register
@retval true Register write succeeded
@retval false Register write failed
*/
bool mpu6050_register_write(uint8_t register_address, const uint8_t value);
/**
@brief Function for reading MPU6050 register contents over TWI.
Reads one or more consecutive registers.
@param[in] register_address Register address to start reading from
@param[in] number_of_bytes Number of bytes to read
@param[out] destination Pointer to a data buffer where read data will be stored
@retval true Register read succeeded
@retval false Register read failed
*/
bool mpu6050_register_read(uint8_t register_address, uint8_t *destination, uint8_t number_of_bytes);
/**
@brief Function for reading and verifying MPU6050 product ID.
@retval true Product ID is what was expected
@retval false Product ID was not what was expected
*/
bool mpu6050_verify_product_id(void);
/**
*@}
**/
/*lint --flb "Leave library region" */
#ifdef __cplusplus
}
#endif
#endif /* MPU6050_H */

View File

@@ -0,0 +1,559 @@
/**
* Copyright (c) 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf21540.h"
#include "nrf_assert.h"
#include "nrf21540_defs.h"
#include "nrf21540_macro.h"
#include "nrf_radio.h"
#include "nrf_ppi.h"
#include "nrf_gpiote.h"
#include "nrf_timer.h"
#include "boards.h"
#if NRF21540_DO_NOT_USE_NATIVE_RADIO_IRQ_HANDLER
#include "nrf_egu.h"
#endif
#define NRF21540_BUSY_CHECK(mode) \
if (mode == NRF21540_EXEC_MODE_BLOCKING) \
{ \
while(is_driver_busy()) \
{ \
\
} \
} \
else if (is_driver_busy()) \
{ \
return NRF_ERROR_BUSY; \
}
#define NRF21540_ERROR_CHECK(invalid_state_condition) \
if (device_state_get() == NRF21540_STATE_ERROR) \
{ \
m_nrf21540_data.busy = false; \
return NRF_ERROR_INTERNAL; \
} \
if (invalid_state_condition) \
{ \
m_nrf21540_data.busy = false; \
return NRF_ERROR_INVALID_STATE; \
}
/**@brief nRF21540 chip state.
*
* @details driver state variable possible values.
*/
typedef enum {
NRF21540_STATE_OFF, ///< Chip inactive, line PDN is low, SPI communication impossible.
NRF21540_STATE_READY, ///< SPI is active, but nether transmit nor receive can be performed.
NRF21540_STATE_TX, ///< Transmit state - chip can perform transmiting data.
NRF21540_STATE_RX, ///< Receive state - chip can receive data.
NRF21540_STATE_ERROR, ///< Invalid state - requires reinit.
} nrf21540_state_t;
/**@brief nRF21540 static data. */
static struct
{
volatile nrf21540_state_t cur_state; ///< driver state variable.
volatile nrf21540_trx_t cur_direction; ///< currently serviced radio communication direction.
volatile bool busy; ///< driver is busy at the moment (during changing state phase).
#if NRF21540_DO_NOT_USE_NATIVE_RADIO_IRQ_HANDLER
volatile uint32_t shorts;
#endif
} m_nrf21540_data;
/**@brief Function checks if nRF21540 driver is busy now.
*
* @details Based on driver busy variable.
*
* @return true if nRF21540 driver is busy.
*/
static inline bool is_driver_busy(void)
{
return m_nrf21540_data.busy;
}
/**@brief Function checks if nRF21540 is powered down.
*
* @details Based on driver state variable.
*
* @return true if nRF21540 is in power down state.
*/
static inline bool is_device_off(void)
{
return m_nrf21540_data.cur_state == NRF21540_STATE_OFF;
}
/**@brief Function checks if nRF21540 is powered up state.
*
* @details Based on driver state variable.
*
* @return true if nRF21540 is in power up state.
*/
static inline bool is_device_on(void)
{
return m_nrf21540_data.cur_state != NRF21540_STATE_OFF;
}
/**@brief Function checks if nRF21540 can transmit or receive data.
*
* @details Based on driver state variable.
*
* @return true if nRF21540 is in TX or RX mode.
*/
static inline bool is_device_ready_for_transmission(void)
{
return (m_nrf21540_data.cur_state == NRF21540_STATE_TX ||
m_nrf21540_data.cur_state == NRF21540_STATE_RX);
}
/**@brief Function changes driver state.
*
* @details Changes driver state variable value.
*
* @param[in] new_state state that will be store.
*/
static inline void device_state_set(nrf21540_state_t new_state)
{
m_nrf21540_data.cur_state = new_state;
}
/**@brief Function returns driver state variable value.
*
* @details Based on driver state variable.
*
* @return @ref nrf21540_state_t based state variable value.
*/
static inline nrf21540_state_t device_state_get(void)
{
return m_nrf21540_data.cur_state;
}
/**@brief Function returns task related to transmission direction.
*
* @param[in] dir direction of radio transfer. See @nrf21540_trx_t.
*
* @return task corresponding to given transmission direction.
*/
static inline nrf_radio_task_t nrf21540_task_get(nrf21540_trx_t dir)
{
return dir == NRF21540_TX ? NRF_RADIO_TASK_TXEN : NRF_RADIO_TASK_RXEN;
}
/**@brief Function clears and disbles all PPI connections used by nRF21540 driver.
*
* @details Changes driver state variable value.
*/
static void ppi_cleanup(void)
{
nrf_ppi_channel_disable(NRF21540_PDN_PPI_CHANNEL);
nrf_ppi_channel_disable(NRF21540_USER_PPI_CHANNEL);
nrf_ppi_channel_disable(NRF21540_TRX_PPI_CHANNEL);
nrf_ppi_channel_and_fork_endpoint_setup(NRF21540_PDN_PPI_CHANNEL, 0, 0, 0);
nrf_ppi_channel_and_fork_endpoint_setup(NRF21540_USER_PPI_CHANNEL, 0, 0, 0);
nrf_ppi_channel_and_fork_endpoint_setup(NRF21540_TRX_PPI_CHANNEL, 0, 0, 0);
}
/**@brief Function clears nRF21540 driver events. */
static void events_clear()
{
nrf_timer_event_clear(NRF21540_TIMER, NRF21540_TIMER_CC_PD_PG_EVENT);
nrf_timer_event_clear(NRF21540_TIMER, NRF21540_TIMER_CC_START_TO_PDN_UP_EVENT);
NRF21540_RADIO_EVENT_CLEAR(NRF21540_RADIO_EVENT_READY);
NRF21540_RADIO_EVENT_CLEAR(NRF21540_RADIO_EVENT_DISABLED);
}
/**@brief Timer interrupt handler.
*
* @details checking time related events occurences and changing driver state if necessary.
*/
void NRF21540_TIMER_IRQ_HANDLER(void)
{
if (nrf_timer_event_check(NRF21540_TIMER, NRF21540_TIMER_CC_PD_PG_EVENT))
{
nrf_timer_event_clear(NRF21540_TIMER, NRF21540_TIMER_CC_PD_PG_EVENT);
if (is_device_off() && nrf_gpio_pin_read(NRF21540_PDN_PIN) == 1)
{
device_state_set(NRF21540_STATE_READY);
}
else if (is_device_on() && nrf_gpio_pin_read(NRF21540_PDN_PIN) == 0)
{
device_state_set(NRF21540_STATE_OFF);
ppi_cleanup();
m_nrf21540_data.busy = false;
}
else
{
device_state_set(NRF21540_STATE_ERROR);
ppi_cleanup();
m_nrf21540_data.busy = false;
}
}
}
/**@brief nRF21540 interrupt handler.
*
* @details checking radio related events occurences and changing driver state if necessary.
*/
void NRF21540_RADIO_IRQ_HANDLER(void)
{
if (NRF21540_RADIO_EVENT_CHECK(NRF21540_RADIO_EVENT_READY))
{
NRF21540_RADIO_EVENT_CLEAR(NRF21540_RADIO_EVENT_READY);
nrf_ppi_channel_disable(NRF21540_USER_PPI_CHANNEL);
#if NRF21540_DO_NOT_USE_NATIVE_RADIO_IRQ_HANDLER
if (NRF21540_RADIO_SHORTS_ENABLE_CHECK(RADIO_SHORTS_READY_START_Msk))
{
nrf_radio_task_trigger(NRF_RADIO_TASK_START);
}
#endif
if (device_state_get() == NRF21540_STATE_READY)
{
device_state_set(m_nrf21540_data.cur_direction == NRF21540_TX ?
NRF21540_STATE_TX : NRF21540_STATE_RX);
ppi_cleanup();
NRF21540_RADIO_INT_DISABLE(NRF21540_RADIO_READY_Msk);
m_nrf21540_data.busy = false;
}
}
if (NRF21540_RADIO_EVENT_CHECK(NRF21540_RADIO_EVENT_DISABLED))
{
NRF21540_RADIO_EVENT_CLEAR(NRF21540_RADIO_EVENT_DISABLED);
nrf_ppi_channel_disable(NRF21540_USER_PPI_CHANNEL);
nrf_timer_task_trigger(NRF21540_TIMER, NRF_TIMER_TASK_START);
if (is_device_ready_for_transmission())
{
NRF21540_RADIO_INT_DISABLE(NRF21540_RADIO_DISABLED_Msk);
device_state_set(NRF21540_STATE_READY);
}
}
}
/**@brief Function resets nRF21540 driver.
*
* @details sets driver state variable to NRF21540_STATE_OFF value,
* cleans all used PPIs and events.
*/
static void driver_reset(void)
{
device_state_set(NRF21540_STATE_OFF);
ppi_cleanup();
events_clear();
NRF21540_RADIO_INT_DISABLE(NRF21540_RADIO_INTERRUPT_MASK);
m_nrf21540_data.busy = false;
}
/**@brief Function sets either TX or RX direction.
*
* @details Configuration of all necessarily peripherals to transmit or receive data,
* dependenly on interface used (SPI, or GPIO). Procedure configures nRF21540 chip and
* starts transmitting/receiving. Procedure will be started immediately if
* @ref trigger_event is 0. Otherwise event which address is @ref trigger_event value
* will start procedure.
*
* @param[in] dir RX or TX communication that will be performed.
* @param[in] trigger_event address of event which will trigger the procedure.
* @param[in] mode if NRF21540_EXEC_MODE_BLOCKING the function will wait for tx/rx
* possibility.
* @return NRF_ERROR_INTERNAL when driver is in error state.
* Reinitialization is required.
* NRF_ERROR_INVALID_STATE when nRF21540's state isn't proper
* to perform the operation (@sa nrf21540_state_t).
* NRF_ERROR_BUSY when driver performs another operation at
* the moment.
* NRF_SUCCESS on success.
*/
static ret_code_t trx_set(nrf21540_trx_t dir, uint32_t trigger_event,
nrf21540_execution_mode_t mode)
{
ASSERT(!(mode == NRF21540_EXEC_MODE_BLOCKING && trigger_event != 0));
NRF21540_BUSY_CHECK(mode);
NRF21540_ERROR_CHECK((dir == NRF21540_TX && device_state_get() == NRF21540_STATE_TX) ||
(dir == NRF21540_RX && device_state_get() == NRF21540_STATE_RX));
uint32_t ramp_up_time = nrf_radio_modecnf0_ru_get() ? FAST_RAMP_UP_TIME : RAMP_UP_TIME;
nrf_radio_task_t radio_task_to_start = nrf21540_task_get(dir);
m_nrf21540_data.busy = true;
events_clear();
NRF21540_RADIO_INT_ENABLE(NRF21540_RADIO_READY_Msk);
if (is_device_off())
{
nrf_ppi_channel_endpoint_setup(NRF21540_PDN_PPI_CHANNEL,
(uint32_t)nrf_timer_event_address_get(NRF21540_TIMER,
NRF21540_TIMER_CC_START_TO_PDN_UP_EVENT),
nrf_gpiote_task_addr_get(NRF21540_PDN_GPIOTE_TASK_SET));
nrf_ppi_channel_enable(NRF21540_PDN_PPI_CHANNEL);
nrf_timer_cc_write(NRF21540_TIMER,
NRF21540_TIMER_CC_PD_PG_CHANNEL,
ramp_up_time - NRF21540_PA_PG_TRX_TIME_US);
nrf_timer_cc_write(NRF21540_TIMER,
NRF21540_TIMER_CC_START_TO_PDN_UP_CHANNEL,
ramp_up_time - NRF21540_PA_PG_TRX_TIME_US - NRF21540_PD_PG_TIME_US);
#if NRF21540_USE_GPIO_MANAGEMENT
nrf21540_gpio_trx_enable(dir);
#elif NRF21540_USE_SPI_MANAGEMENT
nrf21540_spim_for_trx_configure(dir, NRF21540_ENABLE);
#endif
nrf_timer_shorts_enable(NRF21540_TIMER,
NRF21540_TIMER_CC_FINISHED_CHANNEL_STOP_MASK |
NRF21540_TIMER_CC_FINISHED_CHANNEL_CLEAR_MASK);
NRF21540_RADIO_SHORTS_ENABLE(RADIO_SHORTS_READY_START_Msk);
if (trigger_event == 0)
{
//start immediately.
nrf_timer_task_trigger(NRF21540_TIMER, NRF_TIMER_TASK_START);
nrf_radio_task_trigger(radio_task_to_start);
}
else
{
//start when user event occurs.
nrf_ppi_channel_and_fork_endpoint_setup(
NRF21540_USER_PPI_CHANNEL,
trigger_event,
(uint32_t) nrf_timer_task_address_get(NRF21540_TIMER, NRF_TIMER_TASK_START),
(uint32_t) nrf_radio_task_address_get(radio_task_to_start));
nrf_ppi_channel_enable(NRF21540_USER_PPI_CHANNEL);
}
}
else
{
// at the moment we are not able to switch direction on the fly.
// @todo switching between RXEN and TXEN.
NRF21540_ERROR_CHECK(device_state_get() == NRF21540_STATE_RX);
if (trigger_event == 0)
{
nrf_radio_task_trigger(radio_task_to_start);
}
else
{
// start when user event occurs
nrf_ppi_channel_endpoint_setup(
NRF21540_USER_PPI_CHANNEL,
trigger_event,
(uint32_t) nrf_radio_task_address_get(radio_task_to_start));
nrf_ppi_channel_enable(NRF21540_USER_PPI_CHANNEL);
}
}
m_nrf21540_data.cur_direction = dir;
if (mode == NRF21540_EXEC_MODE_BLOCKING)
{
while (!is_device_ready_for_transmission());
}
return NRF_SUCCESS;
}
ret_code_t nrf21540_init(void)
{
driver_reset();
// GPIOTE for PDN pin configuration
nrf_gpiote_task_configure(NRF21540_PDN_GPIOTE_CHANNEL_NO,
NRF21540_PDN_PIN,
(nrf_gpiote_polarity_t) GPIOTE_CONFIG_POLARITY_None,
NRF_GPIOTE_INITIAL_VALUE_LOW);
nrf_gpiote_task_enable(NRF21540_PDN_GPIOTE_CHANNEL_NO);
nrf21540_gpio_init();
NVIC_SetPriority(NRF21540_TIMER_IRQn, NRF21540_INTERRUPT_PRIORITY);
NVIC_EnableIRQ(NRF21540_TIMER_IRQn);
nrf_timer_int_enable(NRF21540_TIMER, NRF21540_TIM_INTERRUPT_MASK);
#if NRF21540_USE_SPI_MANAGEMENT
ret_code_t ret = NRF_SUCCESS;
ret = nrf21540_spi_init();
if (ret != NRF_SUCCESS)
{
device_state_set(NRF21540_STATE_ERROR);
return ret;
}
#endif //NRF21540_USE_SPI_MANAGEMENT
#if NRF21540_DO_NOT_USE_NATIVE_RADIO_IRQ_HANDLER
nrf_ppi_channel_endpoint_setup(NRF21540_RADIO_READY_TO_EGU_PPI_CHANNEL,
nrf_radio_event_address_get(NRF_RADIO_EVENT_READY),
(uint32_t)nrf_egu_task_address_get(NRF21540_EGU, NRF21540_RADIO_READY_EGU_TASK));
nrf_ppi_channel_enable(NRF21540_RADIO_READY_TO_EGU_PPI_CHANNEL);
nrf_ppi_channel_endpoint_setup(NRF21540_RADIO_DISABLED_TO_EGU_PPI_CHANNEL,
nrf_radio_event_address_get(NRF_RADIO_EVENT_DISABLED),
(uint32_t)nrf_egu_task_address_get(NRF21540_EGU, NRF21540_RADIO_DISABLED_EGU_TASK));
nrf_ppi_channel_enable(NRF21540_RADIO_DISABLED_TO_EGU_PPI_CHANNEL);
#endif
NVIC_SetPriority(NRF21540_RADIO_IRQn, NRF21540_INTERRUPT_PRIORITY);
NVIC_EnableIRQ(NRF21540_RADIO_IRQn);
return NRF_SUCCESS;
}
ret_code_t nrf21540_pdn_drive(bool state, nrf21540_execution_mode_t mode)
{
NRF21540_BUSY_CHECK(mode);
NRF21540_ERROR_CHECK((state == true && is_device_on()) ||
(state == false && is_device_off()));
nrf21540_state_t final_state;
if (state)
{
final_state = NRF21540_STATE_READY;
}
else
{
final_state = NRF21540_STATE_OFF;
}
nrf_timer_cc_write(NRF21540_TIMER,
NRF21540_TIMER_CC_PD_PG_CHANNEL,
state ? NRF21540_PD_PG_TIME_US : 0);
nrf_timer_shorts_enable(NRF21540_TIMER,
NRF21540_TIMER_CC_FINISHED_CHANNEL_STOP_MASK |
NRF21540_TIMER_CC_FINISHED_CHANNEL_CLEAR_MASK);
nrf_timer_event_clear(NRF21540_TIMER, NRF21540_TIMER_CC_PD_PG_EVENT);
nrf_gpiote_task_force(NRF21540_PDN_GPIOTE_CHANNEL_NO,
!state ? NRF_GPIOTE_INITIAL_VALUE_LOW : NRF_GPIOTE_INITIAL_VALUE_HIGH);
nrf_timer_task_trigger(NRF21540_TIMER, NRF_TIMER_TASK_START);
if (mode == NRF21540_EXEC_MODE_BLOCKING)
{
while (device_state_get() != final_state)
{
}
}
return NRF_SUCCESS;
}
ret_code_t nrf21540_tx_set(uint32_t user_trigger_event, nrf21540_execution_mode_t mode)
{
NRF21540_ERROR_CHECK(device_state_get() == NRF21540_STATE_TX);
return trx_set(NRF21540_TX, user_trigger_event, mode);
}
ret_code_t nrf21540_rx_set(uint32_t user_trigger_event, nrf21540_execution_mode_t mode)
{
NRF21540_ERROR_CHECK(device_state_get() == NRF21540_STATE_RX);
return trx_set(NRF21540_RX, user_trigger_event, mode);
}
bool nrf21540_is_error(void)
{
return device_state_get() == NRF21540_STATE_ERROR ? true : false;
}
ret_code_t nrf21540_ant_set(nrf21540_antenna_t antenna)
{
NRF21540_BUSY_CHECK(NRF21540_EXEC_MODE_NON_BLOCKING);
return nrf21540_gpio_ant_set(antenna);
}
ret_code_t nrf21540_pwr_mode_set(nrf21540_pwr_mode_t mode)
{
NRF21540_BUSY_CHECK(NRF21540_EXEC_MODE_NON_BLOCKING);
#if NRF21540_USE_GPIO_MANAGEMENT
return nrf21540_gpio_pwr_mode_set(mode);
#elif NRF21540_USE_SPI_MANAGEMENT
return nrf21540_spi_pwr_mode_set(mode);
#endif
}
ret_code_t nrf21540_power_down(uint32_t user_trigger_event, nrf21540_execution_mode_t mode)
{
ASSERT(!(mode == NRF21540_EXEC_MODE_BLOCKING && user_trigger_event != 0));
NRF21540_ERROR_CHECK(is_device_off());
NRF21540_BUSY_CHECK(mode);
m_nrf21540_data.busy = true;
events_clear();
NRF21540_RADIO_INT_ENABLE(NRF21540_RADIO_DISABLED_Msk);
if (device_state_get() == NRF21540_STATE_READY)
{
// when device is in ready state we jus driving PDN line down and switch off the radio.
(void)nrf21540_pdn_drive(false, NRF21540_EXEC_MODE_NON_BLOCKING);
nrf_radio_task_trigger(NRF_RADIO_TASK_DISABLE);
}
else
{
// When device is in tx/rx state we have to leave it and then drive PDN down.
// Line PDN should be driven low after 5us from triggering TXEN/RXEN.
uint32_t * trx_drv_task_address;
nrf21540_trx_t cur_direction;
if (device_state_get() == NRF21540_STATE_TX)
{
cur_direction = NRF21540_TX;
}
else if (device_state_get() == NRF21540_STATE_RX)
{
cur_direction = NRF21540_RX;
}
else
{
return NRF_ERROR_INTERNAL;
}
nrf_ppi_channel_endpoint_setup(NRF21540_PDN_PPI_CHANNEL,
(uint32_t)nrf_timer_event_address_get(NRF21540_TIMER,
NRF21540_TIMER_CC_TRX_PG_EVENT),
nrf_gpiote_task_addr_get(NRF21540_PDN_GPIOTE_TASK_CLR));
nrf_ppi_channel_enable(NRF21540_PDN_PPI_CHANNEL);
nrf_timer_shorts_enable(NRF21540_TIMER,
NRF21540_TIMER_CC_FINISHED_CHANNEL_STOP_MASK |
NRF21540_TIMER_CC_FINISHED_CHANNEL_CLEAR_MASK);
nrf_timer_cc_write(NRF21540_TIMER,
NRF21540_TIMER_CC_TRX_PG_CHANNEL,
NRF21540_TRX_PG_TIME_US);
#if NRF21540_USE_GPIO_MANAGEMENT
trx_drv_task_address = (uint32_t*) nrf21540_gpio_trx_task_start_address_get(cur_direction,
NRF21540_DISABLE);
#elif NRF21540_USE_SPI_MANAGEMENT
nrf21540_spim_for_trx_configure(cur_direction, NRF21540_DISABLE);
trx_drv_task_address = (uint32_t*) nrf21540_spim_trx_task_start_address_get();
#endif
if (user_trigger_event == 0)
{
*trx_drv_task_address = 1;
nrf_radio_task_trigger(NRF_RADIO_TASK_DISABLE);
}
else
{
// start when user event occurs.
nrf_ppi_channel_and_fork_endpoint_setup(
NRF21540_USER_PPI_CHANNEL,
user_trigger_event,
(uint32_t)nrf_radio_task_address_get(NRF_RADIO_TASK_DISABLE),
(uint32_t) trx_drv_task_address);
nrf_ppi_channel_enable(NRF21540_USER_PPI_CHANNEL);
}
if (mode == NRF21540_EXEC_MODE_BLOCKING)
{
while (is_device_on());
}
}
return NRF_SUCCESS;
}

View File

@@ -0,0 +1,194 @@
/**
* Copyright (c) 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF21540_H_
#define NRF21540_H_
#include <stdbool.h>
#include <stdint.h>
#include "nrf21540_spi.h"
#include "nrf21540_gpio.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @file
* @brief nRF21540 front-end Bluetooth range extender.
*
*
* @defgroup nrf21540 nRF21540 front-end Bluetooth range extender.
* @{
* @ingroup ext_drivers
* @brief nRF21540 front-end Bluetooth range extender.
*/
#if NRF21540_USE_SPI_MANAGEMENT
#if NRF21540_USE_GPIO_MANAGEMENT
#error Only one management manner can be active
#endif
#elif !NRF21540_USE_GPIO_MANAGEMENT
#error At least one management manner must be active
#endif // NRF21540_USE_SPI_MANAGEMENT
/**@brief Initialization of modules needed by nRF21540:
* - SPI
* - GPIO
* - GPIOTE
* - PPI
* - RADIO
* - NVIC
*
* @return NRF based error code.
* NRF_ERROR_INTERNAL when driver is in error state,
* or SPI initialization has failed. Reinitialization is required.
* NRF_ERROR_INVALID_STATE when nRF21540's state isn't proper
* to perform the operation (@sa nrf21540_state_t).
* NRF_SUCCESS on success.
*/
ret_code_t nrf21540_init(void);
/**@brief Set nRF21540 to TX mode.
*
* @note Dependently on configuration GPIO or SPI interface will be used.
*
* @param[in] user_trigger_event event that triggers start of procedure - this event
* will be connected to appropriate PPI channel.
* @ref NRF21540_EXECUTE_NOW value causes start procedure
* immediately.
* @param[in] mode @ref NRF21540_EXEC_MODE_BLOCKING - function will wait for
* finishing configuration including settling times required
* by nRF21540 (waits till all procedure has finished).
* @ref NRF21540_EXEC_MODE_NON_BLOCKING - function will start
* procedure and set busy flag. User code can be executed
* at this time and busy flag will be unset when done.
* @return NRF based error code.
* NRF_ERROR_INTERNAL when driver is in error state.
* Reinitialization is required.
* NRF_ERROR_INVALID_STATE when nRF21540's state isn't proper
* to perform the operation (@sa nrf21540_state_t).
* NRF_SUCCESS on success.
*/
ret_code_t nrf21540_tx_set(uint32_t user_trigger_event, nrf21540_execution_mode_t mode);
/**@brief Set nRF21540 to TX mode.
*
* @note Dependently on configuration GPIO or SPI interface will be used
* (NRF21540_USE_SPI_MANAGEMENT/NRF21540_USE_GPIO_MANAGEMENT).
*
* @param[in] user_trigger_event event that triggers start of procedure - this event
* will be connected to appropriate PPI channel.
* @ref NRF21540_EXECUTE_NOW value causes start procedure
* immediately.
* @param[in] mode @ref NRF21540_EXEC_MODE_BLOCKING - function will wait for
* finishing configuration including settling times required
* by nRF21540 (waits till all procedure has finished).
* @ref NRF21540_EXEC_MODE_NON_BLOCKING - function will start
* procedure and set busy flag. User code can be executed
* at this time and busy flag will be unset when done.
* @return NRF based error code.
* NRF_ERROR_INTERNAL when driver is in error state.
* Reinitialization is required.
* NRF_ERROR_INVALID_STATE when nRF21540's state isn't proper
* to perform the operation (@sa nrf21540_state_t).
* NRF_SUCCESS on success.
*/
ret_code_t nrf21540_rx_set(uint32_t user_trigger_event, nrf21540_execution_mode_t mode);
/**@brief Function choses one of two physical antenna outputs.
*
* @param[in] antenna One of antenna outputs. See @ref nrf21540_antenna_t.
* @return NRF based error code.
* NRF_ERROR_BUSY when driver performs another operation at
* the moment.
* NRF_SUCCESS on success.
*/
ret_code_t nrf21540_ant_set(nrf21540_antenna_t antenna);
/**@brief Function choses one of two predefined power modes in nRF21540.
*
* @details Refer to nRF21540 Objective Product Specification, section: TX power control.
*
* @param[in] mode Power mode. See @ref nrf21540_pwr_mode_t.
* @return NRF based error code.
* NRF_ERROR_BUSY when driver performs another operation at
* the moment.
* NRF_SUCCESS on success.
*/
ret_code_t nrf21540_pwr_mode_set(nrf21540_pwr_mode_t mode);
/**@brief nRF21540 power down.
*
* @details Disables chip functionality and enter power save mode.
*
* @note Dependently on configuration GPIO or SPI interface will be used.
*
* @param[in] user_trigger_event event that triggers start of procedure - this event
* will be connected to appropriate PPI channel.
* @ref NRF21540_EXECUTE_NOW value causes start procedure
* immediately.
* @param[in] mode @ref NRF21540_EXEC_MODE_BLOCKING - function will wait for
* finishing configuration including settling times required
* by nRF21540 (waits till all procedure has finished).
* @ref NRF21540_EXEC_MODE_NON_BLOCKING - function will start
* procedure and set busy flag. User code can be executed
* at this time and busy flag will be unset when done.
* @return NRF_ERROR_INTERNAL when driver is in error state.
* Reinitialization is required then.
* NRF_ERROR_INVALID_STATE when nRF21540's state isn't proper
* to perform the operation (@sa nrf21540_state_t).
* NRF_ERROR_BUSY when driver performs another operation at
* the moment.
* NRF_SUCCESS on success.
*/
ret_code_t nrf21540_power_down(uint32_t user_trigger_event, nrf21540_execution_mode_t mode);
/**@brief Checks if nRF21540 driver is in error state.
*
* @return true if driver is in error state and should be reinitialized.
*/
bool nrf21540_is_error(void);
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF21540_H_

View File

@@ -0,0 +1,183 @@
/**
* Copyright (c) 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF21540_DEFS_H_
#define NRF21540_DEFS_H_
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Macros creating instance channels number dependent parameters.
*/
#define NRF21540_TIMER CONCAT_2(NRF_TIMER, NRF21540_TIMER_NO)
#define NRF21540_TIMER_IRQ_HANDLER CONCAT_3(TIMER, NRF21540_TIMER_NO, _IRQHandler)
#define NRF21540_TIMER_IRQn CONCAT_3(TIMER, NRF21540_TIMER_NO, _IRQn)
#define NRF21540_TIM_INTERRUPT_MASK CONCAT_3(TIMER_INTENSET_COMPARE, \
NRF21540_TIMER_CC_PD_PG_CHANNEL_NO, _Msk)
#if NRF21540_TIMER_CC_START_TO_PDN_UP_CHANNEL_NO == NRF21540_TIMER_CC_PD_PG_CHANNEL_NO
#error These CC channels must be different
#endif
#if (NRF21540_PDN_PPI_CHANNEL_NO == NRF21540_USER_PPI_CHANNEL_NO) || \
(NRF21540_PDN_PPI_CHANNEL_NO == NRF21540_TRX_PPI_CHANNEL_NO) || \
(NRF21540_TRX_PPI_CHANNEL_NO == NRF21540_USER_PPI_CHANNEL_NO)
#error These PPI channels must be different
#endif
#define NRF21540_USER_PPI_CHANNEL CONCAT_2(NRF_PPI_CHANNEL, NRF21540_USER_PPI_CHANNEL_NO)
#define NRF21540_PDN_PPI_CHANNEL CONCAT_2(NRF_PPI_CHANNEL, NRF21540_PDN_PPI_CHANNEL_NO)
#define NRF21540_TRX_PPI_CHANNEL CONCAT_2(NRF_PPI_CHANNEL, NRF21540_TRX_PPI_CHANNEL_NO)
#define NRF21540_USER_PPI_CHANNEL CONCAT_2(NRF_PPI_CHANNEL, NRF21540_USER_PPI_CHANNEL_NO)
#define NRF21540_PDN_PPI_CHANNEL CONCAT_2(NRF_PPI_CHANNEL, NRF21540_PDN_PPI_CHANNEL_NO)
#define NRF21540_TRX_PPI_CHANNEL CONCAT_2(NRF_PPI_CHANNEL, NRF21540_TRX_PPI_CHANNEL_NO)
#define NRF21540_TIMER_CC_FINISHED_CHANNEL_STOP_MASK CONCAT_3(NRF_TIMER_SHORT_COMPARE, NRF21540_TIMER_CC_PD_PG_CHANNEL_NO, _STOP_MASK)
#define NRF21540_TIMER_CC_FINISHED_CHANNEL_CLEAR_MASK CONCAT_3(NRF_TIMER_SHORT_COMPARE, NRF21540_TIMER_CC_PD_PG_CHANNEL_NO, _CLEAR_MASK)
#define NRF21540_TIMER_CC_START_TO_PDN_UP_CHANNEL CONCAT_2(NRF_TIMER_CC_CHANNEL, NRF21540_TIMER_CC_START_TO_PDN_UP_CHANNEL_NO)
#define NRF21540_TIMER_CC_PD_PG_CHANNEL CONCAT_2(NRF_TIMER_CC_CHANNEL, NRF21540_TIMER_CC_PD_PG_CHANNEL_NO)
#define NRF21540_TIMER_CC_TRX_PG_CHANNEL NRF21540_TIMER_CC_PD_PG_CHANNEL
#define NRF21540_TIMER_CC_START_TO_PDN_UP_EVENT CONCAT_2(NRF_TIMER_EVENT_COMPARE, NRF21540_TIMER_CC_START_TO_PDN_UP_CHANNEL_NO)
#define NRF21540_TIMER_CC_PD_PG_EVENT CONCAT_2(NRF_TIMER_EVENT_COMPARE, NRF21540_TIMER_CC_PD_PG_CHANNEL_NO)
#define NRF21540_TIMER_CC_TRX_PG_EVENT NRF21540_TIMER_CC_PD_PG_EVENT
#if (NRF21540_PDN_GPIOTE_CHANNEL_NO == NRF21540_PA_GPIOTE_CHANNEL_NO) || \
(NRF21540_PDN_GPIOTE_CHANNEL_NO == NRF21540_LNA_GPIOTE_CHANNEL_NO) || \
(NRF21540_LNA_GPIOTE_CHANNEL_NO == NRF21540_PA_GPIOTE_CHANNEL_NO)
#error These GPIOTE channels must be different
#endif
#define NRF21540_PDN_GPIOTE_TASK_CLR CONCAT_2(NRF_GPIOTE_TASKS_CLR_, NRF21540_PDN_GPIOTE_CHANNEL_NO)
#define NRF21540_LNA_GPIOTE_TASK_CLR CONCAT_2(NRF_GPIOTE_TASKS_CLR_, NRF21540_LNA_GPIOTE_CHANNEL_NO)
#define NRF21540_PA_GPIOTE_TASK_CLR CONCAT_2(NRF_GPIOTE_TASKS_CLR_, NRF21540_PA_GPIOTE_CHANNEL_NO)
#define NRF21540_PDN_GPIOTE_TASK_SET CONCAT_2(NRF_GPIOTE_TASKS_SET_, NRF21540_PDN_GPIOTE_CHANNEL_NO)
#define NRF21540_LNA_GPIOTE_TASK_SET CONCAT_2(NRF_GPIOTE_TASKS_SET_, NRF21540_LNA_GPIOTE_CHANNEL_NO)
#define NRF21540_PA_GPIOTE_TASK_SET CONCAT_2(NRF_GPIOTE_TASKS_SET_, NRF21540_PA_GPIOTE_CHANNEL_NO)
#define NRF21540_GPIO_TASK_SET(channel) CONCAT_2(NRF_GPIOTE_TASKS_SET_, channel)
#define NRF21540_GPIO_TASK_CLR(channel) CONCAT_2(NRF_GPIOTE_TASKS_CLR_, channel)
#if !NRF21540_DO_NOT_USE_NATIVE_RADIO_IRQ_HANDLER
#define NRF21540_RADIO_IRQ_HANDLER RADIO_IRQHandler
#define NRF21540_RADIO_IRQn RADIO_IRQn
#define NRF21540_RADIO_READY_Msk RADIO_INTENSET_READY_Msk
#define NRF21540_RADIO_EVENT_READY NRF_RADIO_EVENT_READY
#define NRF21540_RADIO_DISABLED_Msk RADIO_INTENSET_DISABLED_Msk
#define NRF21540_RADIO_EVENT_DISABLED NRF_RADIO_EVENT_DISABLED
#else
#if (NRF21540_USER_PPI_CHANNEL_NO == NRF21540_RADIO_READY_TO_EGU_PPI_CHANNEL_NO) || \
(NRF21540_PDN_PPI_CHANNEL_NO == NRF21540_RADIO_READY_TO_EGU_PPI_CHANNEL_NO) || \
(NRF21540_TRX_PPI_CHANNEL_NO == NRF21540_RADIO_READY_TO_EGU_PPI_CHANNEL_NO) || \
(NRF21540_USER_PPI_CHANNEL_NO == NRF21540_RADIO_DISABLED_TO_EGU_PPI_CHANNEL_NO) || \
(NRF21540_PDN_PPI_CHANNEL_NO == NRF21540_RADIO_DISABLED_TO_EGU_PPI_CHANNEL_NO) || \
(NRF21540_TRX_PPI_CHANNEL_NO == NRF21540_RADIO_DISABLED_TO_EGU_PPI_CHANNEL_NO) || \
(NRF21540_RADIO_READY_TO_EGU_PPI_CHANNEL_NO == NRF21540_RADIO_DISABLED_TO_EGU_PPI_CHANNEL_NO)
#error These PPI channels must be different
#endif
#if (NRF21540_RADIO_READY_EGU_CHANNEL_NO == NRF21540_RADIO_DISABLED_EGU_CHANNEL_NO)
#error These EGU channels must be different
#endif
#define NRF21540_EGU CONCAT_2(NRF_EGU, NRF21540_EGU_NO)
#define SWIx_EGU CONCAT_3(SWI, NRF21540_EGU_NO, _EGU)
#define NRF21540_RADIO_IRQ_HANDLER CONCAT_3(SWIx_EGU, NRF21540_EGU_NO, _IRQHandler)
#define NRF21540_RADIO_IRQn CONCAT_3(SWIx_EGU, NRF21540_EGU_NO, _IRQn)
#define NRF21540_RADIO_READY_Msk (1 << NRF21540_RADIO_READY_EGU_CHANNEL_NO)
#define NRF21540_RADIO_DISABLED_Msk (1 << NRF21540_RADIO_DISABLED_EGU_CHANNEL_NO)
#define NRF21540_RADIO_EVENT_READY CONCAT_2(NRF_EGU_EVENT_TRIGGERED, NRF21540_RADIO_READY_EGU_CHANNEL_NO)
#define NRF21540_RADIO_EVENT_DISABLED CONCAT_2(NRF_EGU_EVENT_TRIGGERED, NRF21540_RADIO_DISABLED_EGU_CHANNEL_NO)
#define NRF21540_RADIO_READY_EGU_TASK CONCAT_2(NRF_EGU_TASK_TRIGGER, NRF21540_RADIO_READY_EGU_CHANNEL_NO)
#define NRF21540_RADIO_DISABLED_EGU_TASK CONCAT_2(NRF_EGU_TASK_TRIGGER, NRF21540_RADIO_DISABLED_EGU_CHANNEL_NO)
#define NRF21540_RADIO_READY_TO_EGU_PPI_CHANNEL CONCAT_2(NRF_PPI_CHANNEL, NRF21540_RADIO_READY_TO_EGU_PPI_CHANNEL_NO)
#define NRF21540_RADIO_DISABLED_TO_EGU_PPI_CHANNEL CONCAT_2(NRF_PPI_CHANNEL, NRF21540_RADIO_DISABLED_TO_EGU_PPI_CHANNEL_NO)
#endif //!NRF21540_DO_NOT_USE_NATIVE_RADIO_IRQ_HANDLER
#define NRF21540_RADIO_INTERRUPT_MASK (NRF21540_RADIO_READY_Msk | NRF21540_RADIO_DISABLED_Msk)
/**@brief Time in microseconds when PA GPIO is activated before the radio is ready for
* transmission.
*/
#define NRF21540_PA_PG_TRX_TIME_US 13
/**@brief Time in microseconds when LNA GPIO is activated before the radio is ready for
* reception.
*/
#define NRF21540_LNA_PG_TRX_TIME_US 13
/**@brief The time between activating the PDN and asserting the RX_EN/TX_EN.
*/
#define NRF21540_PD_PG_TIME_US 18
/**@brief The time between deasserting the RX_EN/TX_EN and deactivating PDN.
*/
#define NRF21540_TRX_PG_TIME_US 5
/**@brief Timing definitions for radio peripheral on nRF uc.
*/
#define TX_FAST_RAMP_UP_TIME 40 ///< Radio fast ramp up time in us for tx
#define RX_FAST_RAMP_UP_TIME 40 ///< Radio fast ramp up time in us for rx
#define TX_RAMP_UP_TIME 130 ///< Radio normal ramp up time in us for tx
#define RX_RAMP_UP_TIME 130 ///< Radio normal ramp up time in us for rx
#if (TX_RAMP_UP_TIME == RX_RAMP_UP_TIME && TX_FAST_RAMP_UP_TIME == RX_FAST_RAMP_UP_TIME)
#define FAST_RAMP_UP_TIME TX_FAST_RAMP_UP_TIME
#define RAMP_UP_TIME TX_RAMP_UP_TIME
#else
#error ramp up times for rx and tx direction are different. Driver needs rework
#endif
#if (FAST_RAMP_UP_TIME < (NRF21540_PA_PG_TRX_TIME_US + NRF21540_PD_PG_TIME_US))
#error fast ramp up time must be greater or equal than (TPD->PG + TPG->TRX)
#endif
#if (FAST_RAMP_UP_TIME > RAMP_UP_TIME)
#error fast ramp up time connot be greater than ramp up time
#endif
#ifdef __cplusplus
}
#endif
#endif // NRF21540_DEFS_H_

View File

@@ -0,0 +1,126 @@
/**
* Copyright (c) 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf21540_gpio.h"
#include "nrf_assert.h"
#include "boards.h"
#include "nrf21540_defs.h"
#include "nrf_gpiote.h"
#include "nrf_ppi.h"
#include "nrf_timer.h"
void nrf21540_gpio_init(void)
{
nrf_gpio_cfg_output(NRF21540_ANTSEL_PIN);
#if NRF21540_USE_GPIO_MANAGEMENT
nrf_gpio_cfg_output(NRF21540_MODE_PIN);
//GPIOTE for TXEN pin configuration
nrf_gpiote_task_configure(NRF21540_PA_GPIOTE_CHANNEL_NO,
NRF21540_TXEN_PIN,
(nrf_gpiote_polarity_t) GPIOTE_CONFIG_POLARITY_None,
NRF_GPIOTE_INITIAL_VALUE_LOW);
nrf_gpiote_task_enable(NRF21540_PA_GPIOTE_CHANNEL_NO);
//GPIOTE for RXEN pin configuration
nrf_gpiote_task_configure(NRF21540_LNA_GPIOTE_CHANNEL_NO,
NRF21540_RXEN_PIN,
(nrf_gpiote_polarity_t) GPIOTE_CONFIG_POLARITY_None,
NRF_GPIOTE_INITIAL_VALUE_LOW);
nrf_gpiote_task_enable(NRF21540_LNA_GPIOTE_CHANNEL_NO);
#endif /*NRF21540_USE_GPIO_MANAGEMENT*/
}
ret_code_t nrf21540_gpio_ant_set(nrf21540_antenna_t antenna)
{
if (antenna == NRF21540_ANT1)
{
nrf_gpio_pin_clear(NRF21540_ANTSEL_PIN);
}
else if (antenna == NRF21540_ANT2)
{
nrf_gpio_pin_set(NRF21540_ANTSEL_PIN);
}
else
{
return NRF_ERROR_INVALID_PARAM;
}
return NRF_SUCCESS;
}
#if NRF21540_USE_GPIO_MANAGEMENT
uint32_t nrf21540_gpio_trx_task_start_address_get(nrf21540_trx_t dir,
nrf21540_bool_state_t required_state)
{
uint8_t gpiote_rx_tx_channel =
dir == NRF21540_TX ?
NRF21540_PA_GPIOTE_CHANNEL_NO :
NRF21540_LNA_GPIOTE_CHANNEL_NO;
return required_state == NRF21540_ENABLE ?
nrf_gpiote_task_addr_get(nrf_gpiote_set_task_get(gpiote_rx_tx_channel)) :
nrf_gpiote_task_addr_get(nrf_gpiote_clr_task_get(gpiote_rx_tx_channel));
}
void nrf21540_gpio_trx_enable(nrf21540_trx_t dir)
{
uint32_t gpiote_task_start = nrf21540_gpio_trx_task_start_address_get(dir, NRF21540_ENABLE);
nrf_ppi_channel_endpoint_setup(NRF21540_TRX_PPI_CHANNEL,
(uint32_t)nrf_timer_event_address_get(NRF21540_TIMER,
NRF21540_TIMER_CC_PD_PG_EVENT),
gpiote_task_start);
nrf_ppi_channel_enable(NRF21540_TRX_PPI_CHANNEL);
}
ret_code_t nrf21540_gpio_pwr_mode_set(nrf21540_pwr_mode_t mode)
{
if (mode == NRF21540_PWR_MODE_A)
{
nrf_gpio_pin_clear(NRF21540_MODE_PIN);
}
else if (mode == NRF21540_PWR_MODE_B)
{
nrf_gpio_pin_set(NRF21540_MODE_PIN);
}
else
{
return NRF_ERROR_INVALID_PARAM;
}
return NRF_SUCCESS;
}
#endif /*NRF21540_USE_GPIO_MANAGEMENT*/

View File

@@ -0,0 +1,97 @@
/**
* Copyright (c) 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF21540_GPIO_H_
#define NRF21540_GPIO_H_
#include "nrf_gpio.h"
#include "nrf21540_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**@brief Function initializes GPIO interface.
*/
void nrf21540_gpio_init(void);
/**@brief Function choses one of two physical antenna outputs.
*
* @param[in] antenna one of antenna outputs. See @ref nrf21540_antenna_t.
* @return NRF_ERROR_INVALID_PARAM when invalid argument given.
* NRF_SUCCESS on success.
*/
ret_code_t nrf21540_gpio_ant_set(nrf21540_antenna_t antenna);
#if NRF21540_USE_GPIO_MANAGEMENT
/**@brief Function returns address of task which triggers RX_EN/TX_EN pin
* to set nRF21540 radio trasfer direction.
*
* @param[in] dir Direction of the radio transmission. See @ref nrf21540_trx_t.
* @param[in] required_state State of RX/TX transfer. See @ref nrf21540_bool_state_t.
* @return Address of appropriate task.
*/
uint32_t nrf21540_gpio_trx_task_start_address_get(nrf21540_trx_t dir,
nrf21540_bool_state_t required_state);
/**@brief Function configures the chip and peripherals for TX/RX transfer purpose.
*
* @details enables/disables RX/TX transfers.
*
* @param[in] dir direction of radio transfer. See @ref nrf21540_trx_t.
*/
void nrf21540_gpio_trx_enable(nrf21540_trx_t dir);
/**@brief Function choses one of two predefined power modes in nRF21540.
*
* @details Refer to nRF21540 Objective Product Specification, section: TX power control.
*
* @param[in] mode Power mode. See @ref nrf21540_pwr_mode_t.
* @return NRF_ERROR_INVALID_PARAM when invalid argument given.
* NRF_SUCCESS on success.
*/
ret_code_t nrf21540_gpio_pwr_mode_set(nrf21540_pwr_mode_t mode);
#endif /*NRF21540_USE_GPIO_MANAGEMENT*/
#ifdef __cplusplus
}
#endif
#endif // NRF21540_GPIO_H_

View File

@@ -0,0 +1,125 @@
/**
* Copyright (c) 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF21540_MACRO_H_
#define NRF21540_MACRO_H_
#include "nrf21540_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/**@brief Macro for retrieving the state of the nRF21540 radio event. */
#if !NRF21540_DO_NOT_USE_NATIVE_RADIO_IRQ_HANDLER
#define NRF21540_RADIO_EVENT_CHECK(event) \
nrf_radio_event_check(event)
#else
#define NRF21540_RADIO_EVENT_CHECK(event) \
nrf_egu_event_check(NRF21540_EGU, event)
#endif
/**@brief Macro for clearing the nRF21540 radio event. */
#if !NRF21540_DO_NOT_USE_NATIVE_RADIO_IRQ_HANDLER
#define NRF21540_RADIO_EVENT_CLEAR(event) \
nrf_radio_event_clear(event)
#else
#define NRF21540_RADIO_EVENT_CLEAR(event) \
nrf_egu_event_clear(NRF21540_EGU, event)
#endif
/**@brief Macro for triggering the nRF21540 radio task. */
#if !NRF21540_DO_NOT_USE_NATIVE_RADIO_IRQ_HANDLER
#define NRF21540_RADIO_TASK_TRIGGER(task) \
nrf_radio_task_trigger(event)
#else
#define NRF21540_RADIO_TASK_TRIGGER(task) \
nrf_egu_task_trigger(NRF21540_EGU, event)
#endif
/**@brief Macro for disabling the nRF21540 interrupts. */
#if !NRF21540_DO_NOT_USE_NATIVE_RADIO_IRQ_HANDLER
#define NRF21540_RADIO_INT_DISABLE(mask) \
nrf_radio_int_disable(mask)
#else
#define NRF21540_RADIO_INT_DISABLE(mask) \
nrf_egu_int_disable(NRF21540_EGU, mask)
#endif
/**@brief Macro for enabling the nRF21540 interrupts. */
#if !NRF21540_DO_NOT_USE_NATIVE_RADIO_IRQ_HANDLER
#define NRF21540_RADIO_INT_ENABLE(mask) \
nrf_radio_int_enable(mask)
#else
#define NRF21540_RADIO_INT_ENABLE(mask) \
nrf_egu_int_enable(NRF21540_EGU, mask)
#endif
/**@brief Macro for enabling the nRF21540 shorts. */
#if !NRF21540_DO_NOT_USE_NATIVE_RADIO_IRQ_HANDLER
#define NRF21540_RADIO_SHORTS_ENABLE(shorts_mask) \
nrf_radio_shorts_enable(shorts_mask)
#else
#define NRF21540_RADIO_SHORTS_ENABLE(shorts_mask) \
(m_nrf21540_data.shorts |= shorts_mask)
#endif
/**@brief Macro for disabling the nRF21540 shorts. */
#if !NRF21540_DO_NOT_USE_NATIVE_RADIO_IRQ_HANDLER
#define NRF21540_RADIO_SHORTS_DISABLE(shorts_mask) \
nrf_radio_shorts_disable(shorts_mask)
#else
#define NRF21540_RADIO_SHORTS_DISABLE(shorts_mask) \
(m_nrf21540_data.shorts &= ~shorts_mask)
#endif
/**@brief Macro for disabling the nRF21540 shorts. */
#if !NRF21540_DO_NOT_USE_NATIVE_RADIO_IRQ_HANDLER
#define NRF21540_RADIO_SHORTS_ENABLE_CHECK(shorts_mask) \
(nrf_radio_shorts_get() && shorts_mask)
#else
#define NRF21540_RADIO_SHORTS_ENABLE_CHECK(shorts_mask) \
(m_nrf21540_data.shorts && shorts_mask)
#endif
#ifdef __cplusplus
}
#endif
#endif // NRF21540_MACRO_H_

View File

@@ -0,0 +1,269 @@
/**
* Copyright (c) 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf21540_spi.h"
#include <string.h>
#include "nrf_assert.h"
#include "boards.h"
#include "nrf_ppi.h"
#include "nrf21540_defs.h"
#include "nrf_timer.h"
#if NRF21540_USE_SPI_MANAGEMENT
static uint8_t m_spi_tx_data[NRF21540_SPI_LENGTH_BYTES]; ///< SPI tx buffer.
static uint8_t m_spi_rx_data[NRF21540_SPI_LENGTH_BYTES]; ///< SPI rx buffer.
static volatile bool m_spi_xfer_done; ///< Flag indicates that SPI completed the transfer.
/**@brief Structure keeps content of important registers of nRF21540.
*
* @details Driver keeps this data because it needs to operate at single bits
* included in these registers (otherwise it should read it content
* during every operation).
*/
static struct {
uint8_t CONFREG0; ///< CONFREG0 register's content.
uint8_t CONFREG1; ///< CONFREG1 register's content.
} m_confreg_statics;
static const nrfx_spim_t spi = NRFX_SPIM_INSTANCE(NRF21540_SPIM_NO); /**< SPI instance. */
/**@brief Function waits for SPI transfer has finished
*
* @details Used in blocking mode transfer
*/
static inline void wait_for_transfer_end(void)
{
while (!m_spi_xfer_done)
{}
m_spi_xfer_done = false;
}
/**@brief Handler called by nrfx driver when SPI event occurs.
*
* @param[in] p_event Event which triggers the handler.
* @param[in] p_context Context.
*/
static void spim_event_handler(nrfx_spim_evt_t const *p_event, void *p_context)
{
m_spi_xfer_done = true;
}
/**@brief Function reads the content of nRF21540 chip register.
*
* @details Preparation of read register operation. Every register has one byte size.
*
* @param[in] reg Register address to read.
* @param[in] mode if NRF21540_EXEC_MODE_BLOCKING the function will wait for data
* received.
* @param[in] start_now if enabled, transmision immediately initialized,
* otherwise transfer will be triggered by external event.
*/
static uint8_t spi_reg_read(nrf21540_reg_t reg, nrf21540_execution_mode_t mode, bool start_now)
{
ASSERT(!(mode == NRF21540_EXEC_MODE_BLOCKING && start_now == false));
nrfx_spim_xfer_desc_t xfer_desc = NRFX_SPIM_XFER_TRX(m_spi_tx_data,
NRF21540_SPI_LENGTH_BYTES,
m_spi_rx_data,
NRF21540_SPI_LENGTH_BYTES);
m_spi_tx_data[NRF21540_SPI_COMMAND_ADDR_BYTE] =
(NRF21540_SPI_COMMAND_READ << NRF21540_SPI_COMMAND_Pos) | (reg << NRF21540_SPI_REG_Pos);
(void)nrfx_spim_xfer(&spi, &xfer_desc, 0);
if (mode == NRF21540_EXEC_MODE_BLOCKING)
{
wait_for_transfer_end();
}
return m_spi_rx_data[NRF21540_SPI_DATA_BYTE];
}
/**@brief Function writes the content of nRF21540 chip register.
*
* @details Preparation of data to send. Every register has one byte size.
*
* @param[in] reg Register address to write.
* @param[in] data Data to write.
* @param[in] mode if NRF21540_EXEC_MODE_BLOCKING the function will wait for transfer
* finished after sending data.
* @param[in] start_now if enabled, transmision immediately initialized,
* otherwise transfer will be triggered by external event.
*/
static void spi_reg_write(nrf21540_reg_t reg, uint8_t data, nrf21540_execution_mode_t mode, bool start_now)
{
ASSERT(!(mode == NRF21540_EXEC_MODE_BLOCKING && start_now == false));
nrfx_spim_xfer_desc_t xfer_desc = NRFX_SPIM_XFER_TRX(m_spi_tx_data,
NRF21540_SPI_LENGTH_BYTES,
m_spi_rx_data,
NRF21540_SPI_LENGTH_BYTES);
m_spi_tx_data[NRF21540_SPI_COMMAND_ADDR_BYTE] =
(NRF21540_SPI_COMMAND_WRITE << NRF21540_SPI_COMMAND_Pos) | (reg << NRF21540_SPI_REG_Pos);
m_spi_tx_data[NRF21540_SPI_DATA_BYTE] = data;
uint32_t flags = start_now ? 0 : NRFX_SPIM_FLAG_HOLD_XFER;
(void)nrfx_spim_xfer(&spi, &xfer_desc, flags);
if (mode == NRF21540_EXEC_MODE_BLOCKING)
{
wait_for_transfer_end();
}
}
/**@brief Function reads content of important nRF21540's registers and stores
* it to dedicated structure (@ref m_confreg_statics).
*
* @return Return NRF based error code.
*/
static ret_code_t m_confreg_statics_content_update(void)
{
ret_code_t ret = nrf21540_pdn_drive(true, NRF21540_EXEC_MODE_BLOCKING);
if (ret != NRF_SUCCESS)
{
return ret;
}
m_confreg_statics.CONFREG0 = spi_reg_read(NRF21540_REG_CONFREG0,
NRF21540_EXEC_MODE_BLOCKING, true);
m_confreg_statics.CONFREG1 = spi_reg_read(NRF21540_REG_CONFREG1,
NRF21540_EXEC_MODE_BLOCKING, true);
return nrf21540_pdn_drive(false, NRF21540_EXEC_MODE_BLOCKING);
}
ret_code_t nrf21540_spi_init(void)
{
ret_code_t ret;
nrfx_spim_config_t spi_config = NRFX_SPIM_DEFAULT_CONFIG;
spi_config.frequency = NRF_SPIM_FREQ_4M;
spi_config.ss_pin = NRF21540_CS_PIN;
spi_config.miso_pin = NRF21540_MISO_PIN;
spi_config.mosi_pin = NRF21540_MOSI_PIN;
spi_config.sck_pin = NRF21540_CLK_PIN;
spi_config.ss_active_high = false;
ret = nrfx_spim_init(&spi, &spi_config, spim_event_handler, NULL);
if (ret != NRFX_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
return m_confreg_statics_content_update();
}
/**@brief Function enables or disables nRF21540 TX mode.
*
* @details Preparation of appropriate register content and tranfer initialization.
*
* @param[in] state NRF21540_DISABLE/NRF21540_ENABLE causes TX mode disabled/enabled.
*/
static void tx_en_drive(nrf21540_bool_state_t state)
{
uint8_t reg_val;
if (state == NRF21540_ENABLE)
{
reg_val = m_confreg_statics.CONFREG0 | NRF21540_BITS_CONFREG0_TX_EN_Enable;
}
else
{
reg_val = m_confreg_statics.CONFREG0 &(~NRF21540_BITS_CONFREG0_TX_EN_Enable);
}
spi_reg_write(NRF21540_REG_CONFREG0, reg_val, NRF21540_EXEC_MODE_NON_BLOCKING, false);
}
/**@brief Function enables or disables nRF21540 RX mode.
*
* @details Preparation of appropriate register content and tranfer initialization.
*
* @param[in] state NRF21540_DISABLE/NRF21540_ENABLE causes RX mode disabled/enabled.
*/
static void rx_en_drive(nrf21540_bool_state_t state)
{
uint8_t reg_val;
if (state == NRF21540_ENABLE)
{
reg_val = m_confreg_statics.CONFREG1 | NRF21540_BITS_CONFREG1_RX_EN_Enable;
}
else
{
reg_val = m_confreg_statics.CONFREG1 &(~NRF21540_BITS_CONFREG1_RX_EN_Disable);
}
spi_reg_write(NRF21540_REG_CONFREG1, reg_val, NRF21540_EXEC_MODE_NON_BLOCKING, false);
}
inline uint32_t nrf21540_spim_trx_task_start_address_get(void)
{
return nrfx_spim_start_task_get(&spi);
}
void nrf21540_spim_for_trx_configure(nrf21540_trx_t dir, nrf21540_bool_state_t required_state)
{
if (dir == NRF21540_TX)
{
tx_en_drive(required_state);
}
else
{
rx_en_drive(required_state);
}
if (required_state == NRF21540_ENABLE)
{
uint32_t task_start_address = nrfx_spim_start_task_get(&spi);
nrf_ppi_channel_endpoint_setup(NRF21540_TRX_PPI_CHANNEL,
(uint32_t)nrf_timer_event_address_get(NRF21540_TIMER,
NRF21540_TIMER_CC_PD_PG_EVENT),
task_start_address);
nrf_ppi_channel_enable(NRF21540_TRX_PPI_CHANNEL);
}
}
ret_code_t nrf21540_spi_pwr_mode_set(nrf21540_pwr_mode_t mode)
{
if (mode == NRF21540_PWR_MODE_A)
{
spi_reg_write(NRF21540_REG_CONFREG0, NRF21540_BITS_CONFREG0_MODE_0,
NRF21540_EXEC_MODE_BLOCKING, true);
}
else if (mode == NRF21540_PWR_MODE_B)
{
spi_reg_write(NRF21540_REG_CONFREG0, NRF21540_BITS_CONFREG0_MODE_1,
NRF21540_EXEC_MODE_BLOCKING, true);
}
else
{
return NRF_ERROR_INVALID_PARAM;
}
return NRF_SUCCESS;
}
#endif /*NRF21540_USE_SPI_MANAGEMENT*/

View File

@@ -0,0 +1,213 @@
/**
* Copyright (c) 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF21540_SPI_H_
#define NRF21540_SPI_H_
#include <stdbool.h>
#include <stdint.h>
#include "nrfx_spim.h"
#include "nrf21540_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief nRF21540 SPI interface parameters defines.
*/
#define NRF21540_SPI_LENGTH_BYTES 2 ///< SPI tx/rx buffer size in bytes.
#define NRF21540_SPI_COMMAND_ADDR_BYTE 0 ///< Position of command field in SPI frame.
#define NRF21540_SPI_DATA_BYTE 1 ///< Position of data field in SPI frame.
#define NRF21540_SPI_COMMAND_Pos 6 ///< Command code bit-position in command field.
#define NRF21540_SPI_REG_Pos 0 ///< Register address bit-position in command field.
#define NRF21540_SPI_COMMAND_NOP 0x00 ///< 'NOP' command code.
#define NRF21540_SPI_COMMAND_READ 0x02 ///< 'READ' command code.
#define NRF21540_SPI_COMMAND_WRITE 0x03 ///< 'WRITE' command code.
/**@brief CONFREG0 register bitfields.
*/
#define NRF21540_BITS_CONFREG0_TX_EN_Pos 0 ///< Position of TX_EN field.
#define NRF21540_BITS_CONFREG0_TX_EN_Msk (1 << NRF21540_BITS_CONFREG0_TX_EN_Pos) ///< Bit mask of TX_EN field.
#define NRF21540_BITS_CONFREG0_TX_EN_Disable 0 ///< Disable TX mode.
#define NRF21540_BITS_CONFREG0_TX_EN_Enable 1 ///< Enable TX mode.
#define NRF21540_BITS_CONFREG0_MODE_Pos 1 ///< Position of MODE field.
#define NRF21540_BITS_CONFREG0_MODE_Msk (1 << NRF21540_BITS_CONFREG0_MODE_Pos) ///< Bit mask of MODE field.
#define NRF21540_BITS_CONFREG0_MODE_0 0 ///< Selects MODE 0.
#define NRF21540_BITS_CONFREG0_MODE_1 1 ///< Selects MODE 1.
#define NRF21540_BITS_CONFREG0_TX_GAIN_Pos 2 ///< Position of TX_GAIN field.
#define NRF21540_BITS_CONFREG0_TX_GAIN_Msk (0x1F << NRF21540_BITS_CONFREG0_TX_GAIN_Pos) ///< Bit mask of TX_GAIN field.
#define NRF21540_BITS_CONFREG0_TX_GAIN_Min 0 ///< Minimum TX_GAIN register value
#define NRF21540_BITS_CONFREG0_TX_GAIN_Max 31 ///< Maximum TX_GAIN register value
/**@brief CONFREG1 register bitfields.
*/
#define NRF21540_BITS_CONFREG1_RX_EN_Pos 0 ///< Position of RX_EN field.
#define NRF21540_BITS_CONFREG1_RX_EN_Msk (1 << NRF21540_BITS_CONFREG1_RX_EN_Pos) ///< Bit mask of TX_EN field.
#define NRF21540_BITS_CONFREG1_RX_EN_Disable 0 ///< Disable RX mode.
#define NRF21540_BITS_CONFREG1_RX_EN_Enable 1 ///< Enable RX mode.
#define NRF21540_BITS_CONFREG1_UICR_EN_Pos 2 ///< Position of UICR_EN field.
#define NRF21540_BITS_CONFREG1_UICR_EN_Msk (1 << NRF21540_BITS_CONFREG1_UICR_EN_Pos) ///< Bit mask of UICR_EN field.
#define NRF21540_BITS_CONFREG1_UICR_EN_Disable 0 ///< Disable UICR program mode.
#define NRF21540_BITS_CONFREG1_UICR_EN_Enable 1 ///< Enable UICR program mode.
#define NRF21540_BITS_CONFREG1_KEY_Pos 4 ///< Position of KEY field.
#define NRF21540_BITS_CONFREG1_KEY_Msk (0x0F << NRF21540_BITS_CONFREG1_KEY_Pos) ///< Bit mask of KEY field.
#define NRF21540_BITS_CONFREG1_KEY_Enter 15 ///< Enter UICR program mode.
#define NRF21540_BITS_CONFREG1_KEY_Leave 0 ///< Leave UICR program mode.
/**@brief CONFREG2 register bitfields.
*/
#define NRF21540_BITS_CONFREG2_POUTA_UICR_Pos 0 ///< Position of POUTA_UICR field.
#define NRF21540_BITS_CONFREG2_POUTA_UICR_Msk (0x1F << NRF21540_BITS_CONFREG2_POUTA_UICR_Pos) ///< Bit mask of POUTA_UICR field.
#define NRF21540_BITS_CONFREG2_POUTA_UICR_Min 0 ///< Minimum POUTA_UICR register value
#define NRF21540_BITS_CONFREG2_POUTA_UICR_Max 31 ///< Maximum POUTA_UICR register value
#define NRF21540_BITS_CONFREG2_POUTA_SEL_Pos 5 ///< Position of POUTA_SEL field.
#define NRF21540_BITS_CONFREG2_POUTA_SEL_Msk (1 << NRF21540_BITS_CONFREG2_POUTA_SEL_Pos) ///< Bit mask of POUTA_SEL field.
#define NRF21540_BITS_CONFREG2_POUTA_SEL_PROD 0 ///< Initialize TX_GAIN register with 20dBm value.
#define NRF21540_BITS_CONFREG2_POUTA_SEL_UICR 1 ///< Initialize TX_GAIN register with POUTA_UICR value.
#define NRF21540_BITS_CONFREG2_WR_UICR_Pos 7 ///< Position of WR_UICR field.
#define NRF21540_BITS_CONFREG2_WR_UICR_Msk (1 << NRF21540_BITS_CONFREG2_WR_UICR_Pos) ///< Bit mask of WR_UICR field.
#define NRF21540_BITS_CONFREG2_WR_UICR_IDLE 0 ///< EFUSE idle .
#define NRF21540_BITS_CONFREG2_WR_UICR_WRITE 1 ///< EFUSE write.
/**@brief CONFREG3 register bitfields.
*/
#define NRF21540_BITS_CONFREG3_POUTB_UICR_Pos 0 ///< Position of POUTB_UICR field.
#define NRF21540_BITS_CONFREG3_POUTB_UICR_Msk (0x1F << NRF21540_BITS_CONFREG3_POUTB_SEL_Pos) ///< Bit mask of POUTB_UICR field.
#define NRF21540_BITS_CONFREG3_POUTB_UICR_Min 0 ///< Minimum POUTB_UICR register value
#define NRF21540_BITS_CONFREG3_POUTB_UICR_Max 31 ///< Maximum POUTB_UICR register value
#define NRF21540_BITS_CONFREG3_POUTB_SEL_Pos 5 ///< Position of POUTB_SEL field.
#define NRF21540_BITS_CONFREG3_POUTB_SEL_Msk (1 << NRF21540_BITS_CONFREG3_POUTB_SEL_Pos) ///< Bit mask of POUTB_SEL field.
#define NRF21540_BITS_CONFREG3_POUTB_SEL_PROD 0 ///< Initialize TX_GAIN register with 20dBm value.
#define NRF21540_BITS_CONFREG3_POUTB_SEL_UICR 1 ///< Initialize TX_GAIN register with POUTB_UICR value.
/**@brief PARTNUMBER register bitfields.
*/
#define NRF21540_PARTNUMBER_PARTNUMBER_Pos 0 ///< Position of PARTNUMBER field.
#define NRF21540_PARTNUMBER_PARTNUMBER_Msk (0xFF << NRF21540_PARTNUMBER_PARTNUMBER_Pos) ///< Bit mask of PARTNUMBER field.
/**@brief HW_REVISON register bitfields.
*/
#define NRF21540_HW_REVISON_HW_REVISION_Pos 4 ///< Position of HW_REVISON field.
#define NRF21540_HW_REVISON_HW_REVISION_Msk (0xF << NRF21540_HW_REVISON_HW_REVISION_Pos) ///< Bit mask of HW_REVISON field.
/**@brief HW_ID0 register bitfields.
*/
#define NRF21540_HW_ID0_Pos 0 ///< Position of HW_ID0 field.
#define NRF21540_HW_ID0_Msk (0xFF << NRF21540_HW_ID0_Pos) ///< Bit mask of HW_ID0 field.
/**@brief HW_ID1 register bitfields.
*/
#define NRF21540_HW_ID1_Pos 0 ///< Position of HW_ID1 field.
#define NRF21540_HW_ID1_Msk (0xFF << NRF21540_HW_ID1_Pos) ///< Bit mask of HW_ID1 field.
/**@brief nRF21540 internal registers.
*/
typedef enum
{
NRF21540_REG_CONFREG0 = 0x00, ///< CONFREG0 register address.
NRF21540_REG_CONFREG1 = 0x01, ///< CONFREG1 register address.
NRF21540_REG_CONFREG2 = 0x02, ///< CONFREG2 register address.
NRF21540_REG_CONFREG3 = 0x03, ///< CONFREG3 register address.
NRF21540_REG_PARTNUMBER = 0x14, ///< PARTNUMBER register address.
NRF21540_REG_HW_REVISION = 0x15, ///< HW_REVISION register address.
NRF21540_REG_HW_ID0 = 0x16, ///< HW_ID0 register address.
NRF21540_REG_HW_ID1 = 0x17, ///< HW_ID1 register address.
} nrf21540_reg_t;
/**@brief Function initializes SPI interface.
*
* @return NRF_ERROR_INTERNAL when SPIM driver initialization error occured.
* NRF_ERROR_INVALID_STATE when nRF21540's state isn't proper
* to perform the operation.
* NRF_SUCCESS on success.
*/
ret_code_t nrf21540_spi_init(void);
/**@brief Function returns address of task which triggers SPI transfer.
*
* @return address of appropriate task.
*/
uint32_t nrf21540_spim_trx_task_start_address_get(void);
/**@brief Function configures the chip and peripherals for TX/RX transfer purpose.
*
* @details It can enable/disable RX/TX transfers.
*
* @param[in] dir Direction of the radio transmission. See @ref nrf21540_trx_t.
* @param[in] required_state State of RX/TX transfer. See @ref nrf21540_bool_state_t.
* chosen transfer type.
*/
void nrf21540_spim_for_trx_configure(nrf21540_trx_t dir, nrf21540_bool_state_t required_state);
/**@brief Function choses one of predefined power modes in nRF21540.
*
* @details Refer to nRF21540 Objective Product Specification, section: TX power control.
*
* @param[in] mode Power mode. See @ref nrf21540_pwr_mode_t.
* @return NRF_ERROR_INVALID_PARAM when invalid argument given.
* NRF_SUCCESS on success.
*/
ret_code_t nrf21540_spi_pwr_mode_set(nrf21540_pwr_mode_t mode);
/**@brief Function sets nRF21540 power state by driving PDN pin.
*
* @param[in] state Required PDN pin state.
* @param[in] mode Execution mode. See @ref nrf21540_execution_mode_t.
* @return NRF_ERROR_INVALID_PARAM when invalid argument given.
* NRF_ERROR_INVALID_STATE when nRF21540's state isn't proper
* to perform the operation (@sa nrf21540_state_t).
* NRF_ERROR_INTERNAL when driver is in error state.
* Reinitialization is required.
* NRF_SUCCESS on success.
*/
ret_code_t nrf21540_pdn_drive(bool state, nrf21540_execution_mode_t mode);
#ifdef __cplusplus
}
#endif
#endif // NRF21540_SPI_H_

View File

@@ -0,0 +1,111 @@
/**
* Copyright (c) 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF21540_TYPES_H_
#define NRF21540_TYPES_H_
#ifdef __cplusplus
extern "C" {
#endif
/**
*
* @defgroup nrf21540_types nRF21540 front-end Bluetooth range extender types
* @{
* @ingroup nrf21540
*/
/**@brief Value used as event zero-address - for immediate function execution.
* This is useful in functions with 'user_trigger_event' input parameter.
*/
#define NRF21540_EXECUTE_NOW ((uint32_t)0)
/**@brief nRF21540 antenna outputs.
*
* @note Read more in the Product Specification.
*/
typedef enum
{
NRF21540_ANT1, ///< Antenna 1 output.
NRF21540_ANT2 ///< Antenna 2 output.
} nrf21540_antenna_t;
/**@brief nRF21540 power modes.
*
* @note Read more in the Product Specification.
*/
typedef enum
{
NRF21540_PWR_MODE_A, ///< Power mode A.
NRF21540_PWR_MODE_B ///< Power mode B.
} nrf21540_pwr_mode_t;
/**@brief nRF21540 transmission direction modes.
*/
typedef enum
{
NRF21540_TX, ///< Transmission direction mode transmit.
NRF21540_RX ///< Transmission direction mode receive.
} nrf21540_trx_t;
/**@brief State type for nRF21540 purposes.
*/
typedef enum
{
NRF21540_DISABLE, ///< State disable.
NRF21540_ENABLE ///< State enable.
} nrf21540_bool_state_t;
/**@brief Modes (blocking/non-blocking) for nRF21540 purposes.
*/
typedef enum
{
NRF21540_EXEC_MODE_NON_BLOCKING, ///< Non-blocking execution mode.
NRF21540_EXEC_MODE_BLOCKING ///< Blocking execution mode.
} nrf21540_execution_mode_t;
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF21540_TYPES_H_

View File

@@ -0,0 +1,305 @@
/**
* Copyright (c) 2008 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf6350.h"
#include "nrf_delay.h"
#include "twi_master.h"
/*lint ++flb "Enter library region" */
#define DDRAM_ADR 0x80 //!< Write to DDRAM AC
#define DDRAM_WR 0x40 //!< Write to DDRAM
#define FUNC_SET 0x00 //!< Enter LCD Function settings
#define LCD_ADDR 0x3E //!< LCD display adr
#define JS_ADDR 0x3F //!< Joystick adr
#define X 0 //!< X direction in pos 0 of joystick array
#define Y 1 //!< Y direction in pos 1 of joystick array
//static void nrf6350_nrf6350_lcd_set_instruction(uint8_t instr);
#define BUF_LEN 32 //!< LCD data buffer length
static uint8_t data_buffer[BUF_LEN]; //!< LCD data buffer
static uint8_t empty_str[18] = {DDRAM_WR, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}; //!< Blank line
static bool nrf6350_lcd_set_instruction(uint8_t instr)
{
nrf_delay_us(10000);
data_buffer[0] = FUNC_SET;
data_buffer[1] = instr;
return twi_master_transfer(LCD_ADDR << 1, data_buffer, 2, TWI_ISSUE_STOP);
}
bool nrf6350_lcd_clear(void)
{
nrf_delay_us(10000);
data_buffer[0] = FUNC_SET;
data_buffer[1] = (uint8_t)(DDRAM_ADR + LCD_UPPER_LINE);
if (!twi_master_transfer(LCD_ADDR << 1, data_buffer, 2, TWI_ISSUE_STOP))
return false;
if (!twi_master_transfer(LCD_ADDR << 1, empty_str, 18, TWI_ISSUE_STOP))
{
return false;
}
data_buffer[1] = DDRAM_ADR + LCD_LOWER_LINE;
if (!twi_master_transfer(LCD_ADDR << 1, data_buffer, 2, TWI_ISSUE_STOP))
return false;
if (!twi_master_transfer(LCD_ADDR << 1, empty_str, 18, TWI_ISSUE_STOP))
return false;
return true;
}
bool nrf6350_lcd_set_contrast(uint8_t contrast)
{
nrf_delay_us(10000);
data_buffer[0] = FUNC_SET;
data_buffer[1] = 0x70 | contrast;
return twi_master_transfer(LCD_ADDR << 1, data_buffer, 2, TWI_ISSUE_STOP);
}
bool nrf6350_lcd_on(void)
{
nrf_delay_us(10000);
data_buffer[0] = FUNC_SET;
data_buffer[1] = 0x0C;
return twi_master_transfer(LCD_ADDR << 1, data_buffer, 2, TWI_ISSUE_STOP);
}
bool nrf6350_lcd_off(void)
{
nrf_delay_us(10000);
data_buffer[0] = FUNC_SET;
data_buffer[1] = 0x08;
return twi_master_transfer(LCD_ADDR << 1, data_buffer, 2, TWI_ISSUE_STOP);
}
bool nrf6350_lcd_init(void)
{
if (!twi_master_init())
{
return false;
}
// Sometimes the first command doesn't get through, so we'll try
// sending non-important "wake up" command first and don't care if it fails.
(void)nrf6350_lcd_wake_up();
if (!nrf6350_lcd_set_instruction(0x38)) // Function set.
return false;
if (!nrf6350_lcd_set_instruction(0x39)) // Choose two-line mode.
return false;
if (!nrf6350_lcd_set_instruction(0x14)) // Internal OSC frequency.
return false;
if (!nrf6350_lcd_set_contrast(LCD_CONTRAST_HIGH)) // Contrast set (low byte).
return false;
if (!nrf6350_lcd_set_instruction(0x5F)) // Power/ICON control/.
return false;
if (!nrf6350_lcd_set_instruction(0x6A)) // Follower control.
return false;
nrf_delay_us(200000); // Need to wait 200ms here according to datasheet.
if (!nrf6350_lcd_on()) // Display ON.
return false;
if (!nrf6350_lcd_clear()) // Clear display.
return false;
return nrf6350_lcd_set_instruction(0x06); // Entry mode set.
}
bool nrf6350_lcd_write_string(const char *p_text, uint8_t size, uint8_t line, uint8_t pos)
{
uint8_t i;
data_buffer[0] = FUNC_SET;
data_buffer[1] = DDRAM_ADR + (pos + line);
if (!twi_master_transfer(LCD_ADDR << 1, data_buffer, 2, TWI_ISSUE_STOP))
return false;
if (!twi_master_transfer(LCD_ADDR << 1, empty_str, 18 - pos, TWI_ISSUE_STOP))
return false;
data_buffer[0] = FUNC_SET;
data_buffer[1] = DDRAM_ADR + (pos + line);
if (!twi_master_transfer(LCD_ADDR << 1, data_buffer, 2, TWI_ISSUE_STOP))
return false;
data_buffer[0] = DDRAM_WR;
for (i=0;i<size;i++)
{
if (i == LCD_LLEN)
break;
data_buffer[i + 1] = (uint8_t) * p_text++;
}
return twi_master_transfer(LCD_ADDR << 1, data_buffer, i + 1, TWI_ISSUE_STOP);
}
bool nrf6350_js_get_value(int8_t * val)
{
uint8_t js_data;
if (!twi_master_transfer(JS_ADDR << 1 | TWI_READ_BIT, data_buffer, 1, TWI_ISSUE_STOP))
return false;
js_data = (~data_buffer[0] & 0x1D); // Select the useful bits.
if ((js_data & 0x01) != 0) // Check joystick position.
{
val[X] = -1;
}
else if ((js_data & 0x10) != 0)
{
val[X] = 1;
}
else
{
val[X] = 0;
}
if ((js_data & 0x04) != 0)
{
val[Y] = 1;
}
else if ((js_data & 0x08) != 0)
{
val[Y] = -1;
}
else
{
val[Y] = 0;
}
return true;
}
bool nrf6350_js_get_status(uint8_t * js_state)
{
uint8_t js_data;
if (!twi_master_transfer(JS_ADDR << 1 | TWI_READ_BIT, &js_data, 1, TWI_ISSUE_STOP))
{
return false;
}
js_data = ~js_data;
*js_state = js_data & 0x1F;
return true;
}
/** @brief First time communication with the development kit nRF6350 display will fail, this
* returns false on timeout instead of attempting to recover.
*/
static bool nrf6350_lcd_write_without_recovery(uint8_t * data,
uint8_t data_length,
bool issue_stop_condition)
{
uint32_t timeout = 20000; /* max loops to wait for EVENTS_TXDSENT event*/
if (data_length == 0)
{
/* Return false for requesting data of size 0 */
return false;
}
NRF_TWI1->TXD = *data++;
NRF_TWI1->TASKS_STARTTX = 1;
/** @snippet [TWI HW master write] */
while (true)
{
while (NRF_TWI1->EVENTS_TXDSENT == 0 && (--timeout))
{
// Do nothing.
}
if (timeout == 0)
{
NRF_TWI1->EVENTS_STOPPED = 0;
NRF_TWI1->TASKS_STOP = 1;
/* Wait until stop sequence is sent */
while (NRF_TWI1->EVENTS_STOPPED == 0)
{
// Do nothing.
}
/* Timeout before receiving event*/
return false;
}
NRF_TWI1->EVENTS_TXDSENT = 0;
if (--data_length == 0)
{
break;
}
NRF_TWI1->TXD = *data++;
}
/** @snippet [TWI HW master write] */
if (issue_stop_condition)
{
NRF_TWI1->EVENTS_STOPPED = 0;
NRF_TWI1->TASKS_STOP = 1;
/* Wait until stop sequence is sent */
while (NRF_TWI1->EVENTS_STOPPED == 0)
{
// Do nothing.
}
}
return true;
}
/** @brief Function for transfer by twi_master.
*/
bool nrf6350_lcd_wake_up(void)
{
uint8_t address = (LCD_ADDR << 1);
uint8_t dummy_data[] = {0, 0, 0, 0};
uint8_t dummy_data_length = 4;
bool issue_stop_condition = 0;
bool transfer_succeeded = false;
NRF_TWI1->ADDRESS = (address >> 1);
transfer_succeeded = nrf6350_lcd_write_without_recovery(dummy_data,
dummy_data_length,
issue_stop_condition);
NRF_TWI1->EVENTS_ERROR = 0;
return transfer_succeeded;
}
/*lint --flb "Leave library region" */

View File

@@ -0,0 +1,154 @@
/**
* Copyright (c) 2012 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF6350_H_
#define NRF6350_H_
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define LCD_LLEN 16 //!< LCD Line length
#define JS_BUTTON_NONE 0x00 //!< Joystick not touched
#define JS_BUTTON_LEFT 0x01 //!< joystick pulled left
#define JS_BUTTON_PUSH 0x02 //!< joystick pushed
#define JS_BUTTON_DOWN 0x04 //!< joystick pulled down
#define JS_BUTTON_UP 0x08 //!< joystick pulled up
#define JS_BUTTON_RIGHT 0x10 //!< joystick pulled right
#define LCD_UPPER_LINE 0x00 //!< LCD upper line
#define LCD_LOWER_LINE 0x40 //!< LCD lower line
#define LCD_CONTRAST_LOW 0x00 //!< LCD Low contrast
#define LCD_CONTRAST_MEDIUM 0x02 //!< LCD Medium contrast
#define LCD_CONTRAST_HIGH 0x08 //!< LCD High contrast
/**
* @brief Function for initializing the LCD display prior to writing.
* @return
* @retval true Operation succeeded
* @retval false Operation failed
*/
bool nrf6350_lcd_init(void);
/**
* @brief Function for writing a text string on the LCD-display.
*
* @param p_text A pointer to the text string to be written
* @param size Size of the text string to be written
* @param line The line the text should be written to
* @param pos The start position of the text on the line
* @return
* @retval true Write succeeded
* @retval false Write failed
*/
bool nrf6350_lcd_write_string(const char *p_text, uint8_t size, uint8_t line, uint8_t pos);
/**
* @brief Function for clearing the contents of the LCD-display.
*
* @return
* @retval true Operation succeeded
* @retval false Operation failed
*/
bool nrf6350_lcd_clear(void);
/**
* @brief Function for adjusting the contrast of the LCD-display, select between
* LCD_CONTRAST_LOW, LCD_CONTRAST_MEDIUM and LCD_CONTRAST_HIGH.
*
* @param contrast The desired contrast of the lcd display
* @return
* @retval true Operation succeeded
* @retval false Operation failed
*/
bool nrf6350_lcd_set_contrast(uint8_t contrast);
/**
* @brief Function for turning ON the LCD-display.
*
* @return
* @retval true Operation succeeded
* @retval false Operation failed
*/
bool nrf6350_lcd_on(void);
/**
* @brief Function for turning OFF the LCD-display.
*
* @return
* @retval true Operation succeeded
* @retval false Operation failed
*/
bool nrf6350_lcd_off(void);
/**
* @brief Function for getting the position of the joystick.
*
* @param val pointer to a 2 byte array where the X,Y position is stored
* @return
* @retval true Operation succeeded
* @retval false Operation failed
*/
bool nrf6350_js_get_value(int8_t *val);
/**
* @brief Function for getting the status of the joystick.
*
* @param js_state pointer to a uint8_t that receives the status of the joystick
* @return
* @retval true Operation succeeded
* @retval false Operation failed
*/
bool nrf6350_js_get_status(uint8_t *js_state);
/** @brief Function for transferring data over TWI bus. Used the first time you want to communicate nRF6350 to bypass a fail.
*/
bool nrf6350_lcd_wake_up(void);
#ifdef __cplusplus
}
#endif
#endif // NRF6350_H_
/** @} */

View File

@@ -0,0 +1,749 @@
/**
* Copyright (c) 2018 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "pcal6408a.h"
static pcal6408a_instance_t * m_p_instances;
static uint8_t m_max_instance_count;
static uint8_t m_added_inst_count;
#define PCAL6408A_WRITE(p_instance, msg) \
nrf_twi_sensor_write(p_instance.p_sensor_data, \
p_instance.sensor_addr, \
msg, \
ARRAY_SIZE(msg), \
true)
#define PCAL6408A_REG_OUTPUT_PORT_DEFAULT_VAL 0xFF
#define PCAL6408A_REG_POLARITY_INVERSION_DEFAULT_VAL 0x00
#define PCAL6408A_REG_CONFIGURATION_DEFAULT_VAL 0xFF
#define PCAL6408A_REG_OUTPUT_DRIVE_STRENGTH_0_DEFAULT_VAL 0xFF
#define PCAL6408A_REG_OUTPUT_DRIVE_STRENGTH_1_DEFAULT_VAL 0xFF
#define PCAL6408A_REG_INPUT_LATCH_DEFAULT_VAL 0x00
#define PCAL6408A_REG_PULL_UP_DOWN_ENABLE_DEFAULT_VAL 0x00
#define PCAL6408A_REG_PULL_UP_DOWN_SELECT_DEFAULT_VAL 0xFF
#define PCAL6408A_REG_INTERRUPT_MASK_DEFAULT_VAL 0xFF
#define PCAL6408A_REG_INTERRUPT_STATUS_DEFAULT_VAL 0x00
#define PCAL6408A_REG_OUTPUT_PORT_CONFIGURATION_DEFAULT_VAL 0x00
/**
* ================================================================================================
* @brief General expander utility functions.
*/
void pcal6408a_init(pcal6408a_instance_t * p_instances, uint8_t count)
{
ASSERT(p_instances != NULL);
m_p_instances = p_instances;
m_max_instance_count = count;
m_added_inst_count = 0;
}
static void pcal6408a_default_cfg_set(uint8_t instance_num)
{
m_p_instances[instance_num].registers[1] = PCAL6408A_REG_OUTPUT_PORT_DEFAULT_VAL;
m_p_instances[instance_num].registers[2] = PCAL6408A_REG_POLARITY_INVERSION_DEFAULT_VAL;
m_p_instances[instance_num].registers[3] = PCAL6408A_REG_CONFIGURATION_DEFAULT_VAL;
m_p_instances[instance_num].registers[4] = PCAL6408A_REG_OUTPUT_DRIVE_STRENGTH_0_DEFAULT_VAL;
m_p_instances[instance_num].registers[5] = PCAL6408A_REG_OUTPUT_DRIVE_STRENGTH_1_DEFAULT_VAL;
m_p_instances[instance_num].registers[6] = PCAL6408A_REG_INPUT_LATCH_DEFAULT_VAL;
m_p_instances[instance_num].registers[7] = PCAL6408A_REG_PULL_UP_DOWN_ENABLE_DEFAULT_VAL;
m_p_instances[instance_num].registers[8] = PCAL6408A_REG_PULL_UP_DOWN_SELECT_DEFAULT_VAL;
m_p_instances[instance_num].registers[9] = PCAL6408A_REG_INTERRUPT_MASK_DEFAULT_VAL;
m_p_instances[instance_num].registers[10] = PCAL6408A_REG_INTERRUPT_STATUS_DEFAULT_VAL;
m_p_instances[instance_num].registers[11] = PCAL6408A_REG_OUTPUT_PORT_CONFIGURATION_DEFAULT_VAL;
}
ret_code_t pcal6408a_add_instance(nrf_twi_sensor_t * p_twi_sensor, uint8_t sensor_address)
{
ASSERT(p_twi_sensor != NULL);
if (m_p_instances == NULL)
{
return NRF_ERROR_MODULE_NOT_INITIALIZED;
}
if (m_added_inst_count >= m_max_instance_count)
{
return NRF_ERROR_STORAGE_FULL;
}
m_p_instances[m_added_inst_count].p_sensor_data = p_twi_sensor;
m_p_instances[m_added_inst_count].sensor_addr = sensor_address;
pcal6408a_default_cfg_set(m_added_inst_count);
m_added_inst_count++;
ret_code_t err_code = pcal6408a_cfg_write(m_added_inst_count - 1);
return err_code;
}
ret_code_t pcal6408a_cfg_write(uint8_t instance_num)
{
if (instance_num >= m_added_inst_count)
{
return NRF_ERROR_INVALID_PARAM;
}
ret_code_t err_code;
for (uint8_t i = PCAL6408A_REG_OUTPUT_PORT; i <= PCAL6408A_REG_CONFIGURATION; i++)
{
err_code = nrf_twi_sensor_reg_write(m_p_instances[instance_num].p_sensor_data,
m_p_instances[instance_num].sensor_addr,
i,
&m_p_instances[instance_num].registers[i],
1);
if (err_code != NRF_SUCCESS)
{
goto end;
}
while (nrf_twi_mngr_is_idle(m_p_instances[instance_num].p_sensor_data->p_twi_mngr) != true)
{
// Wait for transaction to finish to not overflow msg buffer
}
}
for (uint8_t i = PCAL6408A_REG_COUNT_SEQUENCE_1; i <= (PCAL6408A_REG_COUNT_ALL - 3); i++)
{
err_code = nrf_twi_sensor_reg_write(
m_p_instances[instance_num].p_sensor_data,
m_p_instances[instance_num].sensor_addr,
i - PCAL6408A_REG_COUNT_SEQUENCE_1 + PCAL6408A_REG_OUTPUT_DRIVE_STRENGTH_0,
&m_p_instances[instance_num].registers[i],
1);
if (err_code != NRF_SUCCESS)
{
goto end;
}
while (nrf_twi_mngr_is_idle(m_p_instances[instance_num].p_sensor_data->p_twi_mngr) != true)
{
// Wait for transaction to finish to not overflow msg buffer
}
}
err_code = nrf_twi_sensor_reg_write(
m_p_instances[instance_num].p_sensor_data,
m_p_instances[instance_num].sensor_addr,
PCAL6408A_REG_OUTPUT_PORT_CONFIGURATION,
&m_p_instances[instance_num].registers[PCAL6408A_REG_COUNT_ALL - 1],
1);
end:
return err_code;
}
ret_code_t pcal6408a_cfg_read(uint8_t instance_num)
{
if (instance_num >= m_added_inst_count)
{
return NRF_ERROR_INVALID_PARAM;
}
ret_code_t err_code;
for (uint8_t i = 0; i <= PCAL6408A_REG_CONFIGURATION; i++)
{
err_code = nrf_twi_sensor_reg_read(m_p_instances[instance_num].p_sensor_data,
m_p_instances[instance_num].sensor_addr,
i,
NULL,
&m_p_instances[instance_num].registers[i],
1);
if (err_code != NRF_SUCCESS)
{
goto end;
}
while (nrf_twi_mngr_is_idle(m_p_instances[instance_num].p_sensor_data->p_twi_mngr) != true)
{
// Wait for transaction to finish to not overflow msg buffer
}
}
for(uint8_t i = PCAL6408A_REG_COUNT_SEQUENCE_1; i <= (PCAL6408A_REG_COUNT_ALL - 3); i++)
{
err_code = nrf_twi_sensor_reg_read(
m_p_instances[instance_num].p_sensor_data,
m_p_instances[instance_num].sensor_addr,
i - PCAL6408A_REG_COUNT_SEQUENCE_1 + PCAL6408A_REG_OUTPUT_DRIVE_STRENGTH_0,
NULL,
&m_p_instances[instance_num].registers[i],
1);
if (err_code != NRF_SUCCESS)
{
goto end;
}
while (nrf_twi_mngr_is_idle(m_p_instances[instance_num].p_sensor_data->p_twi_mngr) != true)
{
// Wait for transaction to finish to not overflow msg buffer
}
}
err_code = nrf_twi_sensor_reg_read(
m_p_instances[instance_num].p_sensor_data,
m_p_instances[instance_num].sensor_addr,
PCAL6408A_REG_OUTPUT_PORT_CONFIGURATION,
NULL,
&m_p_instances[instance_num].registers[PCAL6408A_REG_COUNT_ALL - 1],
1);
end:
return err_code;
}
ret_code_t pcal6408a_pin_data_update(nrf_twi_sensor_reg_cb_t user_cb)
{
ret_code_t err_code;
for (uint8_t i = 0; i < m_added_inst_count - 1; i++)
{
err_code = nrf_twi_sensor_reg_read(m_p_instances[i].p_sensor_data,
m_p_instances[i].sensor_addr,
PCAL6408A_REG_INPUT_PORT,
NULL,
&m_p_instances[i].registers[PCAL6408A_REG_INPUT_PORT],
1);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
return nrf_twi_sensor_reg_read(
m_p_instances[m_added_inst_count - 1].p_sensor_data,
m_p_instances[m_added_inst_count - 1].sensor_addr,
PCAL6408A_REG_INPUT_PORT,
user_cb,
&m_p_instances[m_added_inst_count - 1].registers[PCAL6408A_REG_INPUT_PORT],
1);
}
ret_code_t pcal6408a_int_status_update(nrf_twi_sensor_reg_cb_t user_cb)
{
ret_code_t err_code;
for (uint8_t i = 0; i < m_added_inst_count - 1; i++)
{
err_code = nrf_twi_sensor_reg_read(m_p_instances[i].p_sensor_data,
m_p_instances[i].sensor_addr,
PCAL6408A_REG_INTERRUPT_STATUS,
NULL,
&m_p_instances[i].registers[10],
1);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
return nrf_twi_sensor_reg_read(
m_p_instances[m_added_inst_count - 1].p_sensor_data,
m_p_instances[m_added_inst_count - 1].sensor_addr,
PCAL6408A_REG_INTERRUPT_STATUS,
user_cb,
&m_p_instances[m_added_inst_count - 1].registers[10],
1);
}
static uint8_t * get_reg_address(pcal6408a_registers_t reg_addr, uint8_t inst_num)
{
if (reg_addr <= PCAL6408A_REG_CONFIGURATION)
{
return &m_p_instances[inst_num].registers[reg_addr];
}
else if (reg_addr == PCAL6408A_REG_OUTPUT_PORT_CONFIGURATION)
{
return &m_p_instances[inst_num].registers[PCAL6408A_REG_COUNT_ALL - 1];
}
else if (reg_addr >= PCAL6408A_REG_OUTPUT_DRIVE_STRENGTH_0
&& reg_addr <= PCAL6408A_REG_INTERRUPT_STATUS)
{
return &m_p_instances[inst_num].registers[PCAL6408A_REG_COUNT_SEQUENCE_1
+ reg_addr
- PCAL6408A_REG_OUTPUT_DRIVE_STRENGTH_0];
}
return NULL;
}
ret_code_t pcal6408a_pin_cfg_reg_set(pcal6408a_registers_t reg_addr, uint32_t pin, uint8_t value)
{
ASSERT(pin <= (PCAL6408A_INNER_PIN_COUNT * m_added_inst_count));
uint8_t * p_reg_val;
uint8_t mask;
uint8_t inst_num = pin / PCAL6408A_INNER_PIN_COUNT;
pin %= PCAL6408A_INNER_PIN_COUNT;
if (reg_addr == PCAL6408A_REG_OUTPUT_DRIVE_STRENGTH_0)
{
if (pin > PCAL6408A_DRIVE_STRENGTH_REG_0_PIN_MAX)
{
return NRF_ERROR_INVALID_PARAM;
}
mask = 3; // Current control register parameter is 2 bits long.
pin *= 2;
}
else if (reg_addr == PCAL6408A_REG_OUTPUT_DRIVE_STRENGTH_1)
{
if (pin <= PCAL6408A_DRIVE_STRENGTH_REG_0_PIN_MAX)
{
return NRF_ERROR_INVALID_PARAM;
}
mask = 3; // Current control register parameter is 2 bits long.
pin %= PCAL6408A_INNER_PIN_COUNT / 2;
pin *= 2;
}
else
{
mask = 1;
}
p_reg_val = get_reg_address(reg_addr, inst_num);
if (p_reg_val == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
NRF_TWI_SENSOR_REG_SET(*p_reg_val, (uint8_t) (mask << pin), pin, value);
uint8_t send_msg[] = {
reg_addr,
*p_reg_val
};
return PCAL6408A_WRITE(m_p_instances[inst_num], send_msg);
}
uint8_t pcal6408a_pin_cfg_reg_get(pcal6408a_registers_t reg_addr, uint32_t pin)
{
ASSERT(pin <= (PCAL6408A_INNER_PIN_COUNT * m_added_inst_count));
uint8_t * p_reg_val;
uint8_t mask = 1;
uint8_t inst_num = pin / PCAL6408A_INNER_PIN_COUNT;
pin %= PCAL6408A_INNER_PIN_COUNT;
if (reg_addr == PCAL6408A_REG_OUTPUT_DRIVE_STRENGTH_0
|| reg_addr == PCAL6408A_REG_OUTPUT_DRIVE_STRENGTH_1)
{
if (pin > PCAL6408A_DRIVE_STRENGTH_REG_0_PIN_MAX)
{
reg_addr = PCAL6408A_REG_OUTPUT_DRIVE_STRENGTH_1;
pin %= PCAL6408A_INNER_PIN_COUNT / 2;
}
else
{
reg_addr = PCAL6408A_REG_OUTPUT_DRIVE_STRENGTH_0;
}
mask = 3; //Current control register parameter is 2 bits long.
pin *= 2;
}
p_reg_val = get_reg_address(reg_addr, inst_num);
if (p_reg_val == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
return NRF_TWI_SENSOR_REG_VAL_GET(*p_reg_val, (mask << pin), pin);
}
ret_code_t pcal6408a_port_cfg_reg_set(pcal6408a_registers_t reg_addr,
uint32_t port,
uint8_t mask,
pcal6408a_port_op_t flag)
{
if (port >= m_added_inst_count)
{
return NRF_ERROR_INVALID_PARAM;
}
uint8_t * p_reg_val;
uint8_t inst_num = port;
p_reg_val = get_reg_address(reg_addr, inst_num);
if (p_reg_val == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
switch (flag)
{
case PCAL6408A_PORT_WRITE:
*p_reg_val = mask;
break;
case PCAL6408A_PORT_CLEAR:
*p_reg_val &= ~mask;
break;
case PCAL6408A_PORT_SET:
*p_reg_val |= mask;
break;
default:
break;
}
uint8_t send_msg[] = {
reg_addr,
*p_reg_val
};
return PCAL6408A_WRITE(m_p_instances[inst_num], send_msg);
}
uint8_t pcal6408a_port_cfg_reg_get(pcal6408a_registers_t reg_addr, uint32_t port)
{
ASSERT(port < m_added_inst_count);
uint8_t inst_num = port;
uint8_t * p_reg_val;
p_reg_val = get_reg_address(reg_addr, inst_num);
if (p_reg_val == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
return *p_reg_val;
}
ret_code_t pcal6408a_pin_cfg_drive_strength(uint32_t pin_number,
pcal6408a_pin_drive_strength_t drive_strength_config)
{
ret_code_t err_code;
if ((pin_number % PCAL6408A_INNER_PIN_COUNT) <= PCAL6408A_DRIVE_STRENGTH_REG_0_PIN_MAX)
{
err_code = pcal6408a_pin_cfg_reg_set(PCAL6408A_REG_OUTPUT_DRIVE_STRENGTH_0,
pin_number,
drive_strength_config);
}
else
{
err_code = pcal6408a_pin_cfg_reg_set(PCAL6408A_REG_OUTPUT_DRIVE_STRENGTH_1,
pin_number,
drive_strength_config);
}
return err_code;
}
ret_code_t pcal6408a_port_cfg_drive_strength(uint32_t port_number,
uint16_t drive_strength_mask,
pcal6408a_port_op_t flag)
{
ret_code_t err_code;
err_code = pcal6408a_port_cfg_reg_set(PCAL6408A_REG_OUTPUT_DRIVE_STRENGTH_0,
port_number,
(uint8_t)drive_strength_mask, flag);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
err_code = pcal6408a_port_cfg_reg_set(PCAL6408A_REG_OUTPUT_DRIVE_STRENGTH_1,
port_number,
(uint8_t)(drive_strength_mask >> 8), flag);
return err_code;
}
/**
* ===============================================================================================
* @brief Functions compatible with nrf_gpio
*/
ret_code_t pcal6408a_pin_cfg_input(uint32_t pin_number, pcal6408a_pin_pull_t pull_config)
{
ret_code_t err_code = pcal6408a_pin_cfg_reg_set(PCAL6408A_REG_CONFIGURATION,
pin_number,
PCAL6408A_PIN_DIR_INPUT);
if (err_code != NRF_SUCCESS)
{
goto end;
}
switch (pull_config)
{
case PCAL6408A_PIN_NOPULL:
err_code = pcal6408a_pin_cfg_reg_set(PCAL6408A_REG_PULL_UP_DOWN_ENABLE, pin_number, 0);
break;
case PCAL6408A_PIN_PULLDOWN:
err_code = pcal6408a_pin_cfg_reg_set(PCAL6408A_REG_PULL_UP_DOWN_ENABLE, pin_number, 1);
if (err_code != NRF_SUCCESS)
{
goto end;
}
err_code = pcal6408a_pin_cfg_reg_set(PCAL6408A_REG_PULL_UP_DOWN_SELECT, pin_number, 0);
break;
case PCAL6408A_PIN_PULLUP:
err_code = pcal6408a_pin_cfg_reg_set(PCAL6408A_REG_PULL_UP_DOWN_ENABLE, pin_number, 1);
if (err_code != NRF_SUCCESS)
{
goto end;
}
err_code = pcal6408a_pin_cfg_reg_set(PCAL6408A_REG_PULL_UP_DOWN_SELECT, pin_number, 1);
break;
default:
break;
}
end:
return err_code;
}
ret_code_t pcal6408a_range_cfg_output(uint32_t pin_range_start, uint32_t pin_range_end)
{
if (pin_range_start > pin_range_end)
{
return NRF_ERROR_INVALID_LENGTH;
}
uint8_t start_port = pin_range_start / PCAL6408A_INNER_PIN_COUNT;
uint8_t end_port = pin_range_end / PCAL6408A_INNER_PIN_COUNT;
uint8_t range_value;
ret_code_t err_code;
if (start_port == end_port)
{
range_value = (0xFF >> (PCAL6408A_INNER_PIN_COUNT - pin_range_end - 1)) &
(0xFF << pin_range_start);
err_code = pcal6408a_port_cfg_reg_set(PCAL6408A_REG_CONFIGURATION,
start_port,
range_value,
PCAL6408A_PORT_CLEAR);
if (err_code != NRF_SUCCESS)
{
goto end;
}
}
else
{
range_value = 0xFF << pin_range_start;
err_code = pcal6408a_port_cfg_reg_set(PCAL6408A_REG_CONFIGURATION,
start_port,
range_value,
PCAL6408A_PORT_CLEAR);
if (err_code != NRF_SUCCESS)
{
goto end;
}
range_value = 0xFF >> (PCAL6408A_INNER_PIN_COUNT - pin_range_end - 1);
err_code = pcal6408a_port_cfg_reg_set(PCAL6408A_REG_CONFIGURATION,
start_port,
range_value,
PCAL6408A_PORT_CLEAR);
if (err_code != NRF_SUCCESS)
{
goto end;
}
}
range_value = 0xFF;
for (uint8_t i = (start_port + 1); i < end_port; i++)
{
err_code = pcal6408a_port_cfg_reg_set(PCAL6408A_REG_CONFIGURATION,
i,
range_value,
PCAL6408A_PORT_CLEAR);
if (err_code != NRF_SUCCESS)
{
goto end;
}
}
end:
return err_code;
}
static ret_code_t pcal6408a_port_pull_cfg_set(uint32_t port,
uint8_t mask,
pcal6408a_pin_pull_t pull_config)
{
ret_code_t err_code = NRF_SUCCESS;
switch (pull_config)
{
case PCAL6408A_PIN_NOPULL:
err_code = pcal6408a_port_cfg_reg_set(PCAL6408A_REG_PULL_UP_DOWN_ENABLE,
port,
mask,
PCAL6408A_PORT_CLEAR);
break;
case PCAL6408A_PIN_PULLDOWN:
err_code = pcal6408a_port_cfg_reg_set(PCAL6408A_REG_PULL_UP_DOWN_ENABLE,
port,
mask,
PCAL6408A_PORT_SET);
if (err_code != NRF_SUCCESS)
{
goto end;
}
err_code = pcal6408a_port_cfg_reg_set(PCAL6408A_REG_PULL_UP_DOWN_SELECT,
port,
mask,
PCAL6408A_PORT_CLEAR);
break;
case PCAL6408A_PIN_PULLUP:
err_code = pcal6408a_port_cfg_reg_set(PCAL6408A_REG_PULL_UP_DOWN_ENABLE,
port,
mask,
PCAL6408A_PORT_SET);
if (err_code != NRF_SUCCESS)
{
goto end;
}
err_code = pcal6408a_port_cfg_reg_set(PCAL6408A_REG_PULL_UP_DOWN_SELECT,
port,
mask,
PCAL6408A_PORT_SET);
break;
default:
break;
}
end:
return err_code;
}
ret_code_t pcal6408a_range_cfg_input(uint32_t pin_range_start,
uint32_t pin_range_end,
pcal6408a_pin_pull_t pull_config)
{
if (pin_range_start > pin_range_end)
{
return NRF_ERROR_INVALID_LENGTH;
}
uint8_t start_port = pin_range_start / PCAL6408A_INNER_PIN_COUNT;
uint8_t end_port = pin_range_end / PCAL6408A_INNER_PIN_COUNT;
uint8_t range_value;
ret_code_t err_code = NRF_SUCCESS;
if (start_port == end_port)
{
range_value = (0xFF >> (PCAL6408A_INNER_PIN_COUNT - pin_range_end - 1))
& (0xFF << pin_range_start);
err_code = pcal6408a_port_cfg_reg_set(PCAL6408A_REG_CONFIGURATION,
start_port,
range_value,
PCAL6408A_PORT_SET);
if (err_code != NRF_SUCCESS)
{
goto end;
}
err_code = pcal6408a_port_pull_cfg_set(start_port, range_value, pull_config);
if (err_code != NRF_SUCCESS)
{
goto end;
}
}
else
{
range_value = 0xFF << pin_range_start;
err_code = pcal6408a_port_cfg_reg_set(PCAL6408A_REG_CONFIGURATION,
start_port,
range_value,
PCAL6408A_PORT_SET);
if (err_code != NRF_SUCCESS)
{
goto end;
}
err_code = pcal6408a_port_pull_cfg_set(start_port, range_value, pull_config);
if (err_code != NRF_SUCCESS)
{
goto end;
}
range_value = 0xFF >> (PCAL6408A_INNER_PIN_COUNT - pin_range_end - 1);
err_code = pcal6408a_port_cfg_reg_set(PCAL6408A_REG_CONFIGURATION,
end_port,
range_value,
PCAL6408A_PORT_SET);
if (err_code != NRF_SUCCESS)
{
goto end;
}
err_code = pcal6408a_port_pull_cfg_set(end_port, range_value, pull_config);
if (err_code != NRF_SUCCESS)
{
goto end;
}
}
range_value = 0xFF;
for (uint8_t i = (start_port + 1); i < end_port; i++)
{
err_code = pcal6408a_port_cfg_reg_set(PCAL6408A_REG_CONFIGURATION,
i,
range_value,
PCAL6408A_PORT_SET);
if (err_code != NRF_SUCCESS)
{
goto end;
}
err_code = pcal6408a_port_pull_cfg_set(i, range_value, pull_config);
if (err_code != NRF_SUCCESS)
{
goto end;
}
}
end:
return err_code;
}

View File

@@ -0,0 +1,745 @@
/**
* Copyright (c) 2018 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef PCAL6408A_H__
#define PCAL6408A_H__
#include "nrf_twi_sensor.h"
#include "pcal6408a_internal.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup pcal6408a_driver PCAL6408A Driver
* @ingroup ext_drivers
*
* @brief Module for configuring and using PCAL6408A GPIO expander.
*
* @{
*/
/**
* @brief First possible expander address.
*/
#define PCAL6408A_BASE_ADDRESS_FIRST 0x20u
/**
* @brief Second possible expander address.
*/
#define PCAL6408A_BASE_ADDRESS_SECOND 0x21u
/**
* @brief Device registers.
*/
typedef enum
{
PCAL6408A_REG_INPUT_PORT = 0x00,
PCAL6408A_REG_OUTPUT_PORT = 0x01,
PCAL6408A_REG_POLARITY_INVERSION = 0x02,
PCAL6408A_REG_CONFIGURATION = 0x03,
PCAL6408A_REG_OUTPUT_DRIVE_STRENGTH_0 = 0x40,
PCAL6408A_REG_OUTPUT_DRIVE_STRENGTH_1 = 0x41,
PCAL6408A_REG_INPUT_LATCH = 0x42,
PCAL6408A_REG_PULL_UP_DOWN_ENABLE = 0x43,
PCAL6408A_REG_PULL_UP_DOWN_SELECT = 0x44,
PCAL6408A_REG_INTERRUPT_MASK = 0x45,
PCAL6408A_REG_INTERRUPT_STATUS = 0x46,
PCAL6408A_REG_OUTPUT_PORT_CONFIGURATION = 0x4F
} pcal6408a_registers_t;
/**
* @brief Enumerator used for setting the direction of a pin.
*/
typedef enum
{
PCAL6408A_PIN_DIR_OUTPUT, /**< Output. */
PCAL6408A_PIN_DIR_INPUT /**< Input. */
} pcal6408a_pin_dir_t;
/**
* @brief Enumerator used for setting the direction of a port.
*/
typedef enum
{
PCAL6408A_PORT_DIR_OUTPUT = 0x00, /**< Output. */
PCAL6408A_PORT_DIR_INPUT = 0xFF /**< Input. */
} pcal6408a_port_dir_t;
/**
* @brief Enumerator used for setting the state of a pin configured as an output.
*/
typedef enum
{
PCAL6408A_PIN_CLR, /**< Clear. */
PCAL6408A_PIN_SET /**< Set. */
} pcal6408a_pin_set_t;
/**
* @brief Enumerator used for selecting the pin to be pulled down or up.
*/
typedef enum
{
PCAL6408A_PIN_NOPULL, /**< No pull. */
PCAL6408A_PIN_PULLDOWN, /**< Pin pulldown resistor enabled. */
PCAL6408A_PIN_PULLUP /**< Pin pullup resistor enabled. */
} pcal6408a_pin_pull_t;
/**
* @brief Enumerator used for selecting the operation for a port.
*/
typedef enum
{
PCAL6408A_PORT_WRITE, /**< Mask is written to the port. */
PCAL6408A_PORT_CLEAR, /**< Positive bits in mask are cleared in port. */
PCAL6408A_PORT_SET /**< Positive bits in mask are set in port. */
} pcal6408a_port_op_t;
/**
* @brief Enumerator used for setting the drive strength of a pin.
*/
typedef enum
{
PCAL6408A_PIN_25_DRIVE_STRENGTH, /**< Drive strength set to 25% of current drive capability. */
PCAL6408A_PIN_50_DRIVE_STRENGTH, /**< Drive strength set to 50% of current drive capability. */
PCAL6408A_PIN_75_DRIVE_STRENGTH, /**< Drive strength set to 75% of current drive capability. */
PCAL6408A_PIN_100_DRIVE_STRENGTH /**< Drive strength set to 100% of current drive capability. */
} pcal6408a_pin_drive_strength_t;
/**
* @brief Enumerator used for setting push-pull or open-drain I/O stage for a port.
*/
typedef enum
{
PCAL6408A_PORT_PUSH_PULL, /**< Push-pull I/O stage. */
PCAL6408A_PORT_OPEN_DRAIN /**< Open-drain I/O stage. */
} pcal6408a_port_io_stage_t;
/**
* @brief Macro that defines expander module.
*
* @param[in] pcal6408a_inst_name Name of the instance to be created.
* @param[in] instance_count Number of connected expanders.
*/
#define PCAL6408A_INSTANCES_DEF_START(pcal6408a_inst_name, instance_count) \
static pcal6408a_instance_t pcal6408a_inst_name[instance_count]
/**
* @brief Macro that converts absolute pin number to pin number dependent on number of expander.
*
* @param[in] pin_num Absolute pin number ranging from 0 to 7.
* @param[in] instance_num Number of expander, order is the same as pcal6408a_add_instance calls.
*/
#define PIN_NUM_CONVERT(pin_num, instance_num) \
(pin_num + instance_num * PCAL6408A_INNER_PIN_COUNT)
/**
* @brief Function initialising expander module.
*
* @param[in] p_instances Pointer to expander module.
* @param[in] count Number of connected expanders.
*/
void pcal6408a_init(pcal6408a_instance_t * p_instances, uint8_t count);
/**
* @brief Function adding expander instance.
*
* @note Should be called for every connected expander.
* Order of calls define order of pins and ports.
*
* @param[in] p_twi_sensor Pointer to common sensor instance. @ref NRF_TWI_SENSOR_DEF
* @param[in] sensor_address Address of expander on I2C bus.
*
* @retval NRF_ERROR_MODULE_NOT_INITIALIZED If expander module wasn't initialised
* @retval NRF_ERROR_STORAGE_FULL If trying to add more instances than defined.
* @retval other Error code from nrf_twi_sensor
* @ref nrf_twi_sensor_write
*/
ret_code_t pcal6408a_add_instance(nrf_twi_sensor_t * p_twi_sensor, uint8_t sensor_address);
/**
* @brief Function for writing current configuration to expander.
*
* @param[in] instance_num Number of expander, order is the same as pcal6408a_add_instance calls.
*
* @retval NRF_ERROR_INVALID_PARAM If there is no expander with given number.
* @retval other Error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t pcal6408a_cfg_write(uint8_t instance_num);
/**
* @brief Function for reading current configuration of expander.
*
* @param[in] instance_num Number of expander, order is the same as pcal6408a_add_instance calls.
*
* @retval NRF_ERROR_INVALID_PARAM If there is no expander with given number.
* @retval other Error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t pcal6408a_cfg_read(uint8_t instance_num);
/**
* @brief Function for setting register configuration of a single pin.
*
* @param[in] reg_addr Register address.
* @param[in] pin Pin number.
* @param[in] value Value to set.
*
* @return Error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t pcal6408a_pin_cfg_reg_set(pcal6408a_registers_t reg_addr, uint32_t pin, uint8_t value);
/**
* @brief Function for getting register configuration of a single pin.
*
* @param[in] reg_addr Register address.
* @param[in] pin Pin number.
*
* @return Pin configuration value
*/
uint8_t pcal6408a_pin_cfg_reg_get(pcal6408a_registers_t reg_addr, uint32_t pin);
/**
* @brief Function for setting register configuration of a port.
*
* @param[in] reg_addr Register address.
* @param[in] port Port number.
* @param[in] mask Mask for the operation.
* @param[in] flag Operation, whether mask should be written into register,
* values should be cleared or set @ref pcal6408a_port_op_t
*
* @retval NRF_ERROR_INVALID_PARAM If there is no port with such number or invalid flag operation.
* @retval other Error code from nrf_twi_sensor @ref nrf_twi_sensor_write
*/
ret_code_t pcal6408a_port_cfg_reg_set(pcal6408a_registers_t reg_addr,
uint32_t port,
uint8_t mask,
pcal6408a_port_op_t flag);
/**
* @brief Function for getting register configuration of a port.
*
* @note When reading input register, it should be updated prior using this function,
* with @ref pcal6408a_pin_data_update
* When reading interrupt status register, it should be updated prior using this function,
* with @ref pcal6408a_int_status_update
*
* @param[in] reg_addr Register address.
* @param[in] port Port number.
*
* @return Register value
*/
uint8_t pcal6408a_port_cfg_reg_get(pcal6408a_registers_t reg_addr, uint32_t port);
/**
* @brief Function for updating pin data.
*
* @param user_cb Function to be called after pin data update is done.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
ret_code_t pcal6408a_pin_data_update(nrf_twi_sensor_reg_cb_t user_cb);
/**
* @brief Function for updating interrupt status data.
*
* @param user_cb Function to be called after interrupt status update is done.
*
* @return Return error code from nrf_twi_sensor @ref nrf_twi_sensor_reg_read
*/
ret_code_t pcal6408a_int_status_update(nrf_twi_sensor_reg_cb_t user_cb);
/**
* @brief Function for setting polarity inversion of a given pin.
*
* @note Note that the pin must be configured as an input for this function to have any effect.
*
* @param[in] pin_number Specifies the pin number.
* @param[in] state
* @arg true Enables polarity inversion.
* @arg false Disables polarity inversion.
*
* @return Error code from pin_cfg_reg_set @ref pcal6408a_pin_cfg_reg_set
*/
__STATIC_INLINE ret_code_t pcal6408a_pin_cfg_polarity_inversion(uint32_t pin_number, bool state);
/**
* @brief Function for setting interrupt of a given pin.
*
* @note Note that the pin must be configured as an input for this function to have any effect.
*
* @param[in] pin_number Specifies the pin number.
* @param[in] state
* @arg true Disables interrupt.
* @arg false Enables interrupt.
*
* @return Error code from pin_cfg_reg_set @ref pcal6408a_pin_cfg_reg_set
*/
__STATIC_INLINE ret_code_t pcal6408a_pin_cfg_interrupt(uint32_t pin_number, bool state);
/**
* @brief Function for setting input latch of a given pin.
*
* @note Note that the pin must be configured as an input for this function to have any effect.
*
* @param[in] pin_number Specifies the pin number.
* @param[in] state
* @arg true Enables input latch.
* @arg false Disables input latch.
*
* @return Error code from pin_cfg_reg_set @ref pcal6408a_pin_cfg_reg_set
*/
__STATIC_INLINE ret_code_t pcal6408a_pin_cfg_latch(uint32_t pin_number, bool state);
/**
* @brief Function for setting drive strength for a given pin.
*
* @note Note that the pin must be configured as an output for this function to have any effect.
*
* @param[in] pin_number Specifies the pin number.
* @param[in] drive_strength_config Drive strength of current drive capability (25%, 50%, 75%
* or 100%) @ref pcal6408a_pin_drive_strength_t
*
* @return Error code from pin_cfg_reg_set @ref pcal6408a_pin_cfg_reg_set
*/
ret_code_t pcal6408a_pin_cfg_drive_strength(uint32_t pin_number,
pcal6408a_pin_drive_strength_t drive_strength_config);
/**
* @brief Function for setting polarity inversion of a given port.
*
* @note Note that this function have an effect only for pins that are configured as an input.
*
* @param[in] port_number Specifies the port number.
* @param[in] polarity_mask Specifies the mask.
* @param[in] flag Operation, whether mask should be written into register,
* values should be cleared or set @ref pcal6408a_port_op_t
*
* @return Error code from port_cfg_reg_set @ref pcal6408a_port_cfg_reg_set
*/
__STATIC_INLINE ret_code_t pcal6408a_port_cfg_polarity_inversion(uint32_t port_number,
uint8_t polarity_mask,
pcal6408a_port_op_t flag);
/**
* @brief Function for setting interrupt of a given port.
*
* @note Note that this function have an effect only for pins that are configured as an input.
*
* @param[in] port_number Specifies the port number.
* @param[in] interrupt_mask Specifies the mask.
* @param[in] flag Operation, whether mask should be written into register,
* values should be cleared or set @ref pcal6408a_port_op_t
*
* @return Error code from port_cfg_reg_set @ref pcal6408a_port_cfg_reg_set
*/
__STATIC_INLINE ret_code_t pcal6408a_port_cfg_interrupt(uint32_t port_number,
uint8_t interrupt_mask,
pcal6408a_port_op_t flag);
/**
* @brief Function for setting input latch of a given port.
*
* @note Note that this function have an effect only for pins that are configured as an input.
*
* @param[in] port_number Specifies the port number.
* @param[in] latch_mask Specifies the mask.
* @param[in] flag Operation, whether mask should be written into register,
* values should be cleared or set @ref pcal6408a_port_op_t
*
* @return Error code from port_cfg_reg_set @ref pcal6408a_port_cfg_reg_set
*/
__STATIC_INLINE ret_code_t pcal6408a_port_cfg_latch(uint32_t port_number,
uint8_t latch_mask,
pcal6408a_port_op_t flag);
/**
* @brief Function for setting drive strength for a given port.
*
* @note Note that this function have an effect only for pins that are configured as an output.
*
* @param[in] port_number Specifies the port number.
* @param[in] drive_strength_mask Specifies the mask. Note that for each pin there are dedicated
* two adjacent bits.
* @param[in] flag Operation, whether mask should be written into register,
* values should be cleared or set @ref pcal6408a_port_op_t
*
* @return Error code from port_cfg_reg_set @ref pcal6408a_port_cfg_reg_set
*/
ret_code_t pcal6408a_port_cfg_drive_strength(uint32_t port_number,
uint16_t drive_strength_mask,
pcal6408a_port_op_t flag);
/**
* @brief Function for selecting push-pull or open-drain I/O stage for the given port.
*
* @param[in] port_number Specifies the port number.
* @param[in] io_stage_config I/O stage of the port (push-pull or open-drain)
* @ref pcal6408a_port_io_stage_t
*
* @return Error code from port_cfg_reg_set @ref pcal6408a_port_cfg_reg_set
*/
__STATIC_INLINE ret_code_t pcal6408a_port_cfg_io_stage(uint32_t port_number,
pcal6408a_port_io_stage_t io_stage_config);
/**
* @brief Function for configuring the given pin number as output.
*
* @param[in] pin_number Specifies the pin number.
*
* @return Error code from pin config set @ref pcal6408a_pin_cfg_reg_set
*/
__STATIC_INLINE ret_code_t pcal6408a_pin_cfg_output(uint32_t pin_number);
/**
* @brief Function for configuring the given pin number as input.
*
* @param[in] pin_number Specifies the pin number.
* @param[in] pull_config State of the pin pull resistor (no pull, pulled down, or pulled high)
* @ref pcal6408a_pin_pull_t
*
* @return Error code from pin_cfg_reg_set @ref pcal6408a_pin_cfg_reg_set
*/
ret_code_t pcal6408a_pin_cfg_input(uint32_t pin_number, pcal6408a_pin_pull_t pull_config);
/**
* @brief Function for setting a pin.
*
* @note Note that the pin must be configured as an output for this function to have any effect.
*
* @param[in] pin_number Specifies the pin number to set.
*
* @return Error code from pin_cfg_reg_set @ref pcal6408a_pin_cfg_reg_set
*/
__STATIC_INLINE ret_code_t pcal6408a_pin_set(uint32_t pin_number);
/**
* @brief Function for clearing a pin.
*
* @note Note that the pin must be configured as an output for this function to have any effect.
*
* @param[in] pin_number Specifies the pin number to clear.
*
* @return Error code from pin_cfg_reg_set @ref pcal6408a_pin_cfg_reg_set
*/
__STATIC_INLINE ret_code_t pcal6408a_pin_clear(uint32_t pin_number);
/**
* @brief Function for configuring the pin range as outputs.
*
* @note For configuring only one pin as an output use @ref pcal6408a_pin_cfg_output.
*
* @param[in] pin_range_start Specifies the start number (inclusive) in the range of pin numbers
* to be configured.
* @param[in] pin_range_end Specifies the end number (inclusive) in the range of pin numbers
* to be configured.
*
* @retval NRF_ERROR_INVALID_LENGTH If start number is greater than end number.
* @retval other Error code from port_cfg_reg_set @ref pcal6408a_port_cfg_reg_set
*/
ret_code_t pcal6408a_range_cfg_output(uint32_t pin_range_start, uint32_t pin_range_end);
/**
* @brief Function for configuring the pin range as inputs.
*
* @note For configuring only one pin as an input use @ref pcal6408a_pin_cfg_input.
*
* @param[in] pin_range_start Specifies the start number (inclusive) in the range of pin numbers
* to be configured.
* @param[in] pin_range_end Specifies the end number (inclusive) in the range of pin numbers
* to be configured.
* @param[in] pull_config State of the pin pull resistor (no pull, pulled down, or pulled high)
* @ref pcal6408a_pin_pull_t
*
* @retval NRF_ERROR_INVALID_LENGTH If start number is greater than end number.
* @retval other Error code from port_cfg_reg_set @ref pcal6408a_port_cfg_reg_set
*/
ret_code_t pcal6408a_range_cfg_input(uint32_t pin_range_start,
uint32_t pin_range_end,
pcal6408a_pin_pull_t pull_config);
/**
* @brief Function for setting the direction for a given pin.
*
* @param[in] pin_number Specifies the pin number.
* @param[in] direction Specifies the direction.
*
* @return Error code from pin_cfg_reg_set @ref pcal6408a_pin_cfg_reg_set
*/
__STATIC_INLINE ret_code_t pcal6408a_pin_dir_set(uint32_t pin_number,
pcal6408a_pin_dir_t direction);
/**
* @brief Function for toggling a given pin.
*
* @note Note that the pin must be configured as an output for this function to have any effect.
*
* @param[in] pin_number Specifies the pin number.
*
* @return Error code from pin_cfg_reg_set @ref pcal6408a_pin_cfg_reg_set
*/
__STATIC_INLINE ret_code_t pcal6408a_pin_toggle(uint32_t pin_number);
/**
* @brief Function for writing a value to a given pin.
*
* @note Note that the pin must be configured as an output for this function to have any effect.
*
* @param[in] pin_number Specifies the pin number.
* @param[in] value Specifies the value to be written to the pin.
* @arg 0 Clears the pin.
* @arg 1 Sets the pin.
*
* @return Error code from pin_cfg_reg_set @ref pcal6408a_pin_cfg_reg_set
*/
__STATIC_INLINE ret_code_t pcal6408a_pin_write(uint32_t pin_number, uint8_t value);
/**
* @brief Function for reading the input level of a given pin.
*
* @note Input data should be updated prior using this function, with @ref pcal6408a_pin_data_update
*
* @param[in] pin_number Specifies the pin number.
*
* @return Error code from pin_cfg_reg_set @ref pcal6408a_pin_cfg_reg_set
*/
__STATIC_INLINE uint32_t pcal6408a_pin_read(uint32_t pin_number);
/**
* @brief Function for setting the direction of a port.
*
* @param[in] port_number Specifies the port number.
* @param[in] direction Specifies the direction.
*
* @return Error code from port_cfg_reg_set @ref pcal6408a_port_cfg_reg_set
*/
__STATIC_INLINE ret_code_t pcal6408a_port_dir_set(uint32_t port_number,
pcal6408a_port_dir_t direction);
/**
* @brief Function for reading a given port.
*
* @note Input data should be updated prior using this function, with @ref pcal6408a_pin_data_update
*
* @param[in] port_number Specifies the port number.
*
* @return Error code from port_cfg_reg_set @ref pcal6408a_port_cfg_reg_set
*/
__STATIC_INLINE uint32_t pcal6408a_port_read(uint32_t port_number);
/**
* @brief Function for writing to a given port.
*
* @note Note that this function have an effect only for pins that are configured as an output.
*
* @param[in] port_number Specifies the port number.
* @param[in] value Specifies the value to be written to the port.
*
* @return Error code from port_cfg_reg_set @ref pcal6408a_port_cfg_reg_set
*/
__STATIC_INLINE ret_code_t pcal6408a_port_write(uint32_t port_number, uint8_t value);
/**
* @brief Function for setting individual pins on given port.
*
* @note Note that this function have an effect only for pins that are configured as an output.
*
* @param[in] port_number Specifies the port number.
* @param[in] set_mask Mask specifying which pins to set. A bit set to 1 indicates that
* the corresponding port pin shall be set.
*
* @return Error code from port_cfg_reg_set @ref pcal6408a_port_cfg_reg_set
*/
__STATIC_INLINE ret_code_t pcal6408a_port_set(uint32_t port_number, uint8_t set_mask);
/**
* @brief Function for clearing individual pins on given port.
*
* @note Note that this function have an effect only for pins that are configured as an output.
*
* @param[in] port_number Specifies the port number.
* @param[in] clr_mask Mask specifying which pins to clear. A bit set to 1 indicates that
* the corresponding port pin shall be cleared.
*
* @return Error code from port_cfg_reg_set @ref pcal6408a_port_cfg_reg_set
*/
__STATIC_INLINE ret_code_t pcal6408a_port_clear(uint32_t port_number, uint8_t clr_mask);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE ret_code_t pcal6408a_pin_cfg_polarity_inversion(uint32_t pin_number, bool state)
{
return pcal6408a_pin_cfg_reg_set(PCAL6408A_REG_POLARITY_INVERSION, pin_number, state);
}
__STATIC_INLINE ret_code_t pcal6408a_pin_cfg_interrupt(uint32_t pin_number, bool state)
{
return pcal6408a_pin_cfg_reg_set(PCAL6408A_REG_INTERRUPT_MASK, pin_number, state);
}
__STATIC_INLINE ret_code_t pcal6408a_pin_cfg_latch(uint32_t pin_number, bool state)
{
return pcal6408a_pin_cfg_reg_set(PCAL6408A_REG_INPUT_LATCH, pin_number, state);
}
__STATIC_INLINE ret_code_t pcal6408a_port_cfg_polarity_inversion(uint32_t port_number,
uint8_t polarity_mask,
pcal6408a_port_op_t flag)
{
return pcal6408a_port_cfg_reg_set(PCAL6408A_REG_POLARITY_INVERSION,
port_number,
polarity_mask,
flag);
}
__STATIC_INLINE ret_code_t pcal6408a_port_cfg_interrupt(uint32_t port_number,
uint8_t interrupt_mask,
pcal6408a_port_op_t flag)
{
return pcal6408a_port_cfg_reg_set(PCAL6408A_REG_INTERRUPT_MASK,
port_number,
interrupt_mask,
flag);
}
__STATIC_INLINE ret_code_t pcal6408a_port_cfg_latch(uint32_t port_number,
uint8_t latch_mask,
pcal6408a_port_op_t flag)
{
return pcal6408a_port_cfg_reg_set(PCAL6408A_REG_INPUT_LATCH,
port_number,
latch_mask,
flag);
}
__STATIC_INLINE ret_code_t pcal6408a_port_cfg_io_stage(uint32_t port_number,
pcal6408a_port_io_stage_t io_stage_config)
{
return pcal6408a_pin_cfg_reg_set(PCAL6408A_REG_OUTPUT_PORT_CONFIGURATION,
port_number * PCAL6408A_INNER_PIN_COUNT,
io_stage_config);
}
__STATIC_INLINE ret_code_t pcal6408a_pin_cfg_output(uint32_t pin_number)
{
return pcal6408a_pin_cfg_reg_set(PCAL6408A_REG_CONFIGURATION,
pin_number,
PCAL6408A_PIN_DIR_OUTPUT);
}
__STATIC_INLINE ret_code_t pcal6408a_pin_set(uint32_t pin_number)
{
return pcal6408a_pin_cfg_reg_set(PCAL6408A_REG_OUTPUT_PORT, pin_number, PCAL6408A_PIN_SET);
}
__STATIC_INLINE ret_code_t pcal6408a_pin_clear(uint32_t pin_number)
{
return pcal6408a_pin_cfg_reg_set(PCAL6408A_REG_OUTPUT_PORT, pin_number, PCAL6408A_PIN_CLR);
}
__STATIC_INLINE ret_code_t pcal6408a_pin_dir_set(uint32_t pin_number, pcal6408a_pin_dir_t direction)
{
return pcal6408a_pin_cfg_reg_set(PCAL6408A_REG_CONFIGURATION, pin_number, direction);
}
__STATIC_INLINE ret_code_t pcal6408a_pin_toggle(uint32_t pin_number)
{
return pcal6408a_pin_cfg_reg_set(
PCAL6408A_REG_OUTPUT_PORT,
pin_number,
!pcal6408a_pin_cfg_reg_get(PCAL6408A_REG_OUTPUT_PORT, pin_number));
}
__STATIC_INLINE ret_code_t pcal6408a_pin_write(uint32_t pin_number, uint8_t value)
{
return pcal6408a_pin_cfg_reg_set(PCAL6408A_REG_OUTPUT_PORT, pin_number, value);
}
__STATIC_INLINE uint32_t pcal6408a_pin_read(uint32_t pin_number)
{
return pcal6408a_pin_cfg_reg_get(PCAL6408A_REG_INPUT_PORT, pin_number);
}
__STATIC_INLINE ret_code_t pcal6408a_port_dir_set(uint32_t port_number,
pcal6408a_port_dir_t direction)
{
return pcal6408a_port_cfg_reg_set(PCAL6408A_REG_CONFIGURATION,
port_number,
direction,
PCAL6408A_PORT_WRITE);
}
__STATIC_INLINE uint32_t pcal6408a_port_read(uint32_t port_number)
{
return pcal6408a_port_cfg_reg_get(PCAL6408A_REG_INPUT_PORT, port_number);
}
__STATIC_INLINE ret_code_t pcal6408a_port_write(uint32_t port_number, uint8_t value)
{
return pcal6408a_port_cfg_reg_set(PCAL6408A_REG_OUTPUT_PORT,
port_number,
value,
PCAL6408A_PORT_WRITE);
}
__STATIC_INLINE ret_code_t pcal6408a_port_set(uint32_t port_number, uint8_t set_mask)
{
return pcal6408a_port_cfg_reg_set(PCAL6408A_REG_OUTPUT_PORT,
port_number,
set_mask,
PCAL6408A_PORT_SET);
}
__STATIC_INLINE ret_code_t pcal6408a_port_clear(uint32_t port_number, uint8_t clr_mask)
{
return pcal6408a_port_cfg_reg_set(PCAL6408A_REG_OUTPUT_PORT,
port_number,
clr_mask,
PCAL6408A_PORT_CLEAR);
}
#endif //SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // PCAL6408A_H__

View File

@@ -0,0 +1,59 @@
/**
* Copyright (c) 2018 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef PCAL6408A_INTERNAL_H__
#define PCAL6408A_INTERNAL_H__
#define PCAL6408A_REG_COUNT_SEQUENCE_1 4
#define PCAL6408A_REG_COUNT_SEQUENCE_2 7
#define PCAL6408A_REG_COUNT_ALL 12
#define PCAL6408A_INNER_PIN_COUNT 8
#define PCAL6408A_DRIVE_STRENGTH_REG_0_PIN_MAX 3
/**
* @brief Structure containing expander instance.
*/
typedef struct {
nrf_twi_sensor_t * p_sensor_data;
uint8_t sensor_addr;
uint8_t registers[PCAL6408A_REG_COUNT_ALL];
} pcal6408a_instance_t;
#endif // PCAL6408A_INTERNAL_H__

View File

@@ -0,0 +1,474 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(ST7735)
#include "nrf_lcd.h"
#include "nrf_drv_spi.h"
#include "nrf_delay.h"
#include "nrf_gpio.h"
#include "boards.h"
// Set of commands described in ST7735 data sheet.
#define ST7735_NOP 0x00
#define ST7735_SWRESET 0x01
#define ST7735_RDDID 0x04
#define ST7735_RDDST 0x09
#define ST7735_SLPIN 0x10
#define ST7735_SLPOUT 0x11
#define ST7735_PTLON 0x12
#define ST7735_NORON 0x13
#define ST7735_INVOFF 0x20
#define ST7735_INVON 0x21
#define ST7735_DISPOFF 0x28
#define ST7735_DISPON 0x29
#define ST7735_CASET 0x2A
#define ST7735_RASET 0x2B
#define ST7735_RAMWR 0x2C
#define ST7735_RAMRD 0x2E
#define ST7735_PTLAR 0x30
#define ST7735_COLMOD 0x3A
#define ST7735_MADCTL 0x36
#define ST7735_FRMCTR1 0xB1
#define ST7735_FRMCTR2 0xB2
#define ST7735_FRMCTR3 0xB3
#define ST7735_INVCTR 0xB4
#define ST7735_DISSET5 0xB6
#define ST7735_PWCTR1 0xC0
#define ST7735_PWCTR2 0xC1
#define ST7735_PWCTR3 0xC2
#define ST7735_PWCTR4 0xC3
#define ST7735_PWCTR5 0xC4
#define ST7735_VMCTR1 0xC5
#define ST7735_RDID1 0xDA
#define ST7735_RDID2 0xDB
#define ST7735_RDID3 0xDC
#define ST7735_RDID4 0xDD
#define ST7735_PWCTR6 0xFC
#define ST7735_GMCTRP1 0xE0
#define ST7735_GMCTRN1 0xE1
#define ST7735_MADCTL_MY 0x80
#define ST7735_MADCTL_MX 0x40
#define ST7735_MADCTL_MV 0x20
#define ST7735_MADCTL_ML 0x10
#define ST7735_MADCTL_RGB 0x00
#define ST7735_MADCTL_BGR 0x08
#define ST7735_MADCTL_MH 0x04
/* @} */
#define RGB2BGR(x) (x << 11) | (x & 0x07E0) | (x >> 11)
static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(ST7735_SPI_INSTANCE); /**< SPI instance. */
/**
* @brief Structure holding ST7735 controller basic parameters.
*/
typedef struct
{
uint8_t tab_color; /**< Color of tab attached to the used screen. */
}st7735_t;
/**
* @brief Enumerator with TFT tab colors.
*/
typedef enum{
INITR_GREENTAB = 0, /**< Green tab. */
INITR_REDTAB, /**< Red tab. */
INITR_BLACKTAB, /**< Black tab. */
INITR_144GREENTAB /**< Green tab, 1.44" display. */
}st7735_tab_t;
static st7735_t m_st7735;
static inline void spi_write(const void * data, size_t size)
{
APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, data, size, NULL, 0));
}
static inline void write_command(uint8_t c)
{
nrf_gpio_pin_clear(ST7735_DC_PIN);
spi_write(&c, sizeof(c));
}
static inline void write_data(uint8_t c)
{
nrf_gpio_pin_set(ST7735_DC_PIN);
spi_write(&c, sizeof(c));
}
static void set_addr_window(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1)
{
ASSERT(x0 <= x1);
ASSERT(y0 <= y1);
write_command(ST7735_CASET);
write_data(0x00); // For a 128x160 display, it is always 0.
write_data(x0);
write_data(0x00); // For a 128x160 display, it is always 0.
write_data(x1);
write_command(ST7735_RASET);
write_data(0x00); // For a 128x160 display, it is always 0.
write_data(y0);
write_data(0x00); // For a 128x160 display, it is always 0.
write_data(y1);
write_command(ST7735_RAMWR);
}
static void command_list(void)
{
write_command(ST7735_SWRESET);
nrf_delay_ms(150);
write_command(ST7735_SLPOUT);
nrf_delay_ms(500);
write_command(ST7735_FRMCTR1);
write_data(0x01);
write_data(0x2C);
write_data(0x2D);
write_command(ST7735_FRMCTR2);
write_data(0x01);
write_data(0x2C);
write_data(0x2D);
write_command(ST7735_FRMCTR3);
write_data(0x01);
write_data(0x2C);
write_data(0x2D);
write_data(0x01);
write_data(0x2C);
write_data(0x2D);
write_command(ST7735_INVCTR);
write_data(0x07);
write_command(ST7735_PWCTR1);
write_data(0xA2);
write_data(0x02);
write_data(0x84);
write_command(ST7735_PWCTR2);
write_data(0xC5);
write_command(ST7735_PWCTR3);
write_data(0x0A);
write_data(0x00);
write_command(ST7735_PWCTR3);
write_data(0x8A);
write_data(0x2A);
write_command(ST7735_PWCTR5);
write_data(0x8A);
write_data(0xEE);
write_data(0x0E);
write_command(ST7735_INVOFF);
write_command(ST7735_MADCTL);
write_data(0xC8);
write_command(ST7735_COLMOD);
write_data(0x05);
if (m_st7735.tab_color == INITR_GREENTAB)
{
write_command(ST7735_CASET);
write_data(0x00);
write_data(0x02);
write_data(0x00);
write_data(0x81);
write_command(ST7735_RASET);
write_data(0x00);
write_data(0x01);
write_data(0x00);
write_data(0xA0);
}
else if (m_st7735.tab_color == INITR_144GREENTAB)
{
write_command(ST7735_CASET);
write_data(0x00);
write_data(0x00);
write_data(0x00);
write_data(0x7F);
write_command(ST7735_RASET);
write_data(0x00);
write_data(0x00);
write_data(0x00);
write_data(0x7F);
}
else if (m_st7735.tab_color == INITR_REDTAB)
{
write_command(ST7735_CASET);
write_data(0x00);
write_data(0x00);
write_data(0x00);
write_data(0x7F);
write_command(ST7735_RASET);
write_data(0x00);
write_data(0x00);
write_data(0x00);
write_data(0x9F);
}
write_command(ST7735_GMCTRP1);
write_data(0x02);
write_data(0x1c);
write_data(0x07);
write_data(0x12);
write_data(0x37);
write_data(0x32);
write_data(0x29);
write_data(0x2d);
write_data(0x29);
write_data(0x25);
write_data(0x2b);
write_data(0x39);
write_data(0x00);
write_data(0x01);
write_data(0x03);
write_data(0x10);
write_command(ST7735_GMCTRN1);
write_data(0x03);
write_data(0x1d);
write_data(0x07);
write_data(0x06);
write_data(0x2e);
write_data(0x2c);
write_data(0x29);
write_data(0x2d);
write_data(0x2e);
write_data(0x2e);
write_data(0x37);
write_data(0x3f);
write_data(0x00);
write_data(0x00);
write_data(0x02);
write_data(0x10);
write_command(ST7735_NORON);
nrf_delay_ms(10);
write_command(ST7735_DISPON);
nrf_delay_ms(100);
if (m_st7735.tab_color == INITR_BLACKTAB)
{
write_command(ST7735_MADCTL);
write_data(0xC0);
}
}
static ret_code_t hardware_init(void)
{
ret_code_t err_code;
nrf_gpio_cfg_output(ST7735_DC_PIN);
nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
spi_config.sck_pin = ST7735_SCK_PIN;
spi_config.miso_pin = ST7735_MISO_PIN;
spi_config.mosi_pin = ST7735_MOSI_PIN;
spi_config.ss_pin = ST7735_SS_PIN;
err_code = nrf_drv_spi_init(&spi, &spi_config, NULL, NULL);
return err_code;
}
static ret_code_t st7735_init(void)
{
ret_code_t err_code;
m_st7735.tab_color = ST7735_TAB_COLOR;
err_code = hardware_init();
if (err_code != NRF_SUCCESS)
{
return err_code;
}
command_list();
return err_code;
}
static void st7735_uninit(void)
{
nrf_drv_spi_uninit(&spi);
}
static void st7735_pixel_draw(uint16_t x, uint16_t y, uint32_t color)
{
set_addr_window(x, y, x, y);
color = RGB2BGR(color);
const uint8_t data[2] = {color >> 8, color};
nrf_gpio_pin_set(ST7735_DC_PIN);
spi_write(data, sizeof(data));
nrf_gpio_pin_clear(ST7735_DC_PIN);
}
static void st7735_rect_draw(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t color)
{
set_addr_window(x, y, x + width - 1, y + height - 1);
color = RGB2BGR(color);
const uint8_t data[2] = {color >> 8, color};
nrf_gpio_pin_set(ST7735_DC_PIN);
// Duff's device algorithm for optimizing loop.
uint32_t i = (height * width + 7) / 8;
/*lint -save -e525 -e616 -e646 */
switch ((height * width) % 8) {
case 0:
do {
spi_write(data, sizeof(data));
case 7:
spi_write(data, sizeof(data));
case 6:
spi_write(data, sizeof(data));
case 5:
spi_write(data, sizeof(data));
case 4:
spi_write(data, sizeof(data));
case 3:
spi_write(data, sizeof(data));
case 2:
spi_write(data, sizeof(data));
case 1:
spi_write(data, sizeof(data));
} while (--i > 0);
default:
break;
}
/*lint -restore */
nrf_gpio_pin_clear(ST7735_DC_PIN);
}
static void st7735_dummy_display(void)
{
/* No implementation needed. */
}
static void st7735_rotation_set(nrf_lcd_rotation_t rotation)
{
write_command(ST7735_MADCTL);
switch (rotation) {
case NRF_LCD_ROTATE_0:
if (m_st7735.tab_color == INITR_BLACKTAB)
{
write_data(ST7735_MADCTL_MX | ST7735_MADCTL_MY | ST7735_MADCTL_RGB);
}
else
{
write_data(ST7735_MADCTL_MX | ST7735_MADCTL_MY | ST7735_MADCTL_BGR);
}
break;
case NRF_LCD_ROTATE_90:
if (m_st7735.tab_color == INITR_BLACKTAB)
{
write_data(ST7735_MADCTL_MY | ST7735_MADCTL_MV | ST7735_MADCTL_RGB);
}
else
{
write_data(ST7735_MADCTL_MY | ST7735_MADCTL_MV | ST7735_MADCTL_BGR);
}
break;
case NRF_LCD_ROTATE_180:
if (m_st7735.tab_color == INITR_BLACKTAB)
{
write_data(ST7735_MADCTL_RGB);
}
else
{
write_data(ST7735_MADCTL_BGR);
}
break;
case NRF_LCD_ROTATE_270:
if (m_st7735.tab_color == INITR_BLACKTAB)
{
write_data(ST7735_MADCTL_MX | ST7735_MADCTL_MV | ST7735_MADCTL_RGB);
}
else
{
write_data(ST7735_MADCTL_MX | ST7735_MADCTL_MV | ST7735_MADCTL_BGR);
}
break;
default:
break;
}
}
static void st7735_display_invert(bool invert)
{
write_command(invert ? ST7735_INVON : ST7735_INVOFF);
}
static lcd_cb_t st7735_cb = {
.height = ST7735_HEIGHT,
.width = ST7735_WIDTH
};
const nrf_lcd_t nrf_lcd_st7735 = {
.lcd_init = st7735_init,
.lcd_uninit = st7735_uninit,
.lcd_pixel_draw = st7735_pixel_draw,
.lcd_rect_draw = st7735_rect_draw,
.lcd_display = st7735_dummy_display,
.lcd_rotation_set = st7735_rotation_set,
.lcd_display_invert = st7735_display_invert,
.p_lcd_cb = &st7735_cb
};
#endif // NRF_MODULE_ENABLED(ST7735)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,232 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef SX1509B_INTERNAL_H
#define SX1509B_INTERNAL_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Device and IO banks registers.
*/
typedef enum
{
SX1509B_REG_INPUT_DISABLE_B,
SX1509B_REG_INPUT_DISABLE_A,
SX1509B_REG_LONG_SLEW_B,
SX1509B_REG_LONG_SLEW_A,
SX1509B_REG_LOW_DRIVE_B,
SX1509B_REG_LOW_DRIVE_A,
SX1509B_REG_PULL_UP_B,
SX1509B_REG_PULL_UP_A,
SX1509B_REG_PULL_DOWN_B,
SX1509B_REG_PULL_DOWN_A,
SX1509B_REG_OPEN_DRAIN_B,
SX1509B_REG_OPEN_DRAIN_A,
SX1509B_REG_POLARITY_B,
SX1509B_REG_POLARITY_A,
SX1509B_REG_DIR_B,
SX1509B_REG_DIR_A,
SX1509B_REG_DATA_B,
SX1509B_REG_DATA_A,
SX1509B_REG_INT_MASK_B,
SX1509B_REG_INT_MASK_A,
SX1509B_REG_SENSE_H_B,
SX1509B_REG_SENSE_L_B,
SX1509B_REG_SENSE_H_A,
SX1509B_REG_SENSE_L_A,
SX1509B_REG_INT_SRC_B,
SX1509B_REG_INT_SRC_A,
SX1509B_REG_EVENT_STATUS_B,
SX1509B_REG_EVENT_STATUS_A,
SX1509B_REG_LEVEL_SHIFTER_1,
SX1509B_REG_LEVEL_SHIFTER_2,
SX1509B_REG_CLOCK,
SX1509B_REG_MISC,
SX1509B_REG_LED_DRV_ENABLE_B,
SX1509B_REG_LED_DRV_ENABLE_A,
SX1509B_REG_DEBOUNCE_CONFIG,
SX1509B_REG_DEBOUNCE_EN_B,
SX1509B_REG_DEBOUNCE_EN_A,
SX1509B_REG_KEY_CONFIG_1,
SX1509B_REG_KEY_CONFIG_2,
SX1509B_REG_KEY_DATA_1,
SX1509B_REG_KEY_DATA_2,
SX1509B_REG_COUNT
} sx1509b_registers_t;
#define SX1509B_INNER_PIN_COUNT 16
#define SX1509B_INNER_NEXT_BANK 8
#define SX1509B_INNER_PORT_COUNT 2
#define SX1509B_INNER_SENSE_REG_NUM 4
#define SX1509B_INNER_RESET_BYTE1 0x12
#define SX1509B_INNER_RESET_BYTE2 0x34
/**
* @brief LED Driver registers.
*/
#define SX1509B_REG_LED_BANK_A_START 0x29
#define SX1509B_REG_LED_FADE_A_START 0x35
#define SX1509B_REG_LED_BANK_B_START 0x49
#define SX1509B_REG_LED_FADE_B_START 0x55
#define SX1509B_LED_DRIVER_TIME_REG_LEN 3
#define SX1509B_LED_DRIVER_FADE_REG_LEN 5
#define SX1509B_LED_DRIVER_TIME_REG_NUM ((SX1509B_REG_LED_FADE_A_START \
- SX1509B_REG_LED_BANK_A_START) \
/ SX1509B_LED_DRIVER_TIME_REG_LEN)
#define SX1509B_LED_DRIVER_FADE_REG_NUM ((SX1509B_REG_LED_BANK_B_START \
- SX1509B_REG_LED_FADE_A_START) \
/ SX1509B_LED_DRIVER_FADE_REG_LEN)
/**
* @brief Clock register bitmasks.
*/
// Bitmasks for osc src.
#define SX1509B_OSC_SRC_POS 5
#define SX1509B_OSC_SRC_MASK (3 << SX1509B_OSC_SRC_POS)
// Bitmasks for oscio pin.
#define SX1509B_OSCIO_PIN_POS 4
#define SX1509B_OSCIO_PIN_MASK (1 << SX1509B_OSCIO_PIN_POS)
// Bitmasks for oscout freq.
#define SX1509B_OSCOUT_FREQ_POS 0
#define SX1509B_OSCOUT_FREQ_MASK (0x0F << SX1509B_OSCOUT_FREQ_POS)
/**
* @brief Miscellaneous register bitmasks.
*/
// Bitmasks for led mode b.
#define SX1509B_LED_MODE_B_POS 7
#define SX1509B_LED_MODE_B_MASK (1 << SX1509B_LED_MODE_B_POS)
// Bitmasks for led freq.
#define SX1509B_LED_FREQ_POS 4
#define SX1509B_LED_FREQ_MASK (7 << SX1509B_LED_FREQ_POS)
// Bitmasks for led mode a.
#define SX1509B_LED_MODE_A_POS 3
#define SX1509B_LED_MODE_A_MASK (1 << SX1509B_LED_MODE_A_POS)
// Bitmasks for nreset pin.
#define SX1509B_NRESET_PIN_POS 2
#define SX1509B_NRESET_PIN_MASK (1 << SX1509B_NRESET_PIN_POS)
// Bitmasks for auto incr.
#define SX1509B_AUTO_INCR_POS 1
#define SX1509B_AUTO_INCR_MASK (1 << SX1509B_AUTO_INCR_POS)
// Bitmasks for auto clear nint.
#define SX1509B_AUTO_CLEAR_NINT_POS 0
#define SX1509B_AUTO_CLEAR_NINT_MASK (1 << SX1509B_AUTO_CLEAR_NINT_POS)
/**
* @brief Key config 1 register bitmasks.
*/
// Bitmasks for sleep time.
#define SX1509B_SLEEP_TIME_POS 4
#define SX1509B_SLEEP_TIME_MASK (7 << SX1509B_SLEEP_TIME_POS)
// Bitmasks for scan time.
#define SX1509B_SCAN_TIME_POS 0
#define SX1509B_SCAN_TIME_MASK (7 << SX1509B_SCAN_TIME_POS)
/**
* @brief Key config 2 register bitmasks.
*/
// Bitmasks for row num.
#define SX1509B_ROW_NUM_POS 3
#define SX1509B_ROW_NUM_MASK (7 << SX1509B_ROW_NUM_POS)
// Bitmasks for col num.
#define SX1509B_COL_NUM_POS 0
#define SX1509B_COL_NUM_MASK (7 << SX1509B_COL_NUM_POS)
/**
* @brief Led driver off register bitmasks.
*/
// Bitmasks for OFF_TIME.
#define SX1509B_OFF_TIME_POS 3
#define SX1509B_OFF_TIME_MASK (0x1F << SX1509B_OFF_TIME_POS)
// Bitmasks for off intensity.
#define SX1509B_OFF_INTENSITY_POS 0
#define SX1509B_OFF_INTENSITY_MASK (7 << SX1509B_OFF_INTENSITY_POS)
/**
* @brief Miscellaneous registers.
*/
#define SX1509B_REG_HIGH_INPUT_B 0x69
#define SX1509B_REG_HIGH_INPUT_A 0x6A
#define SX1509B_REG_SW_RESET 0x7D
#define SX1509B_REG_TEST_1 0x7E
#define SX1509B_REG_TEST_2 0x7F
/**
* @brief Structure containing expander instance.
*/
typedef struct
{
nrf_twi_sensor_t * p_sensor_data;
uint8_t sensor_addr;
uint8_t start_addr;
uint8_t registers[SX1509B_REG_COUNT];
uint8_t high_input[2];
} sx1509b_instance_t;
#ifdef __cplusplus
}
#endif
#endif // SX1509B_INTERNAL_H

View File

@@ -0,0 +1,142 @@
/**
* Copyright (c) 2009 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <stdbool.h>
#include <stdint.h>
#include "twi_master.h"
#include "synaptics_touchpad.h"
/*lint ++flb "Enter library region" */
#define PRODUCT_ID_BYTES 10U //!< Number of bytes to expect to be in product ID
static uint8_t m_device_address; // !< Device address in bits [7:1]
static const uint8_t expected_product_id[PRODUCT_ID_BYTES] = {'T', 'M', '1', '9', '4', '4', '-', '0', '0', '2'}; //!< Product ID expected to get from product ID query
bool touchpad_init(uint8_t device_address)
{
bool transfer_succeeded = true;
m_device_address = (uint8_t)(device_address << 1);
// Do a soft reset
uint8_t reset_command = 0x01;
transfer_succeeded &= touchpad_write_register(TOUCHPAD_RESET, reset_command);
// Page select 0
uint8_t page_to_select = 0x00;
transfer_succeeded &= touchpad_write_register(TOUCHPAD_PAGESELECT, page_to_select);
// Read and verify product ID
transfer_succeeded &= touchpad_product_id_verify();
return transfer_succeeded;
}
bool touchpad_product_id_verify(void)
{
bool transfer_succeeded = true;
uint8_t product_id[PRODUCT_ID_BYTES];
transfer_succeeded &= touchpad_product_id_read(product_id, PRODUCT_ID_BYTES);
for (uint8_t i = 0; i < 10; i++)
{
if (product_id[i] != expected_product_id[i])
{
transfer_succeeded = false;
}
}
return transfer_succeeded;
}
bool touchpad_reset(void)
{
uint8_t w2_data[2] = {TOUCHPAD_COMMAND, 0x01};
return twi_master_transfer(m_device_address, w2_data, 2, TWI_ISSUE_STOP);
}
bool touchpad_interrupt_status_read(uint8_t *interrupt_status)
{
return touchpad_read_register(TOUCHPAD_INT_STATUS, interrupt_status);
}
bool touchpad_set_sleep_mode(TouchpadSleepMode_t mode)
{
return touchpad_write_register(TOUCHPAD_CONTROL, (uint8_t)mode);
}
bool touchpad_read_register(uint8_t register_address, uint8_t *value)
{
bool transfer_succeeded = true;
transfer_succeeded &= twi_master_transfer(m_device_address, &register_address, 1, TWI_DONT_ISSUE_STOP);
if (transfer_succeeded)
{
transfer_succeeded &= twi_master_transfer(m_device_address | TWI_READ_BIT, value, 1, TWI_ISSUE_STOP);
}
return transfer_succeeded;
}
bool touchpad_write_register(uint8_t register_address, const uint8_t value)
{
uint8_t w2_data[2];
w2_data[0] = register_address;
w2_data[1] = value;
return twi_master_transfer(m_device_address, w2_data, 2, TWI_ISSUE_STOP);
}
bool touchpad_product_id_read(uint8_t * product_id, uint8_t product_id_bytes)
{
uint8_t w2_data[1];
bool transfer_succeeded = true;
w2_data[0] = TOUCHPAD_PRODUCT_ID;
transfer_succeeded &= twi_master_transfer(m_device_address, w2_data, 1, TWI_DONT_ISSUE_STOP);
if (transfer_succeeded)
{
transfer_succeeded &= twi_master_transfer(m_device_address | TWI_READ_BIT, product_id, product_id_bytes, TWI_ISSUE_STOP);
}
return transfer_succeeded;
}
/*lint --flb "Leave library region" */

View File

@@ -0,0 +1,164 @@
/**
* Copyright (c) 2009 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef SYNAPTICS_TOUCHPAD_H
#define SYNAPTICS_TOUCHPAD_H
/*lint ++flb "Enter library region" */
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @file
* @brief Synaptics Touchpad driver
*
*
* @defgroup nrf_drivers_synaptics_touchpad Synaptics Touchpad driver
* @{
* @ingroup ext_drivers
* @brief Synaptics Touchpad driver.
*/
/**
Touchpad register addresses.
*/
#define TOUCHPAD_INT_STATUS 0x14 //!< Interrupt status register
#define TOUCHPAD_BUTTON_STATUS 0x41 //!< Button status register
#define TOUCHPAD_FINGER0_REL 0x30 //!< First register in finger delta block
#define TOUCHPAD_GESTURE_FLAGS 0x3A //!< Gesture flags 0
#define TOUCHPAD_SCROLL 0x3F //!< Scroll zone X / horizontal multifinger scroll
#define TOUCHPAD_CONTROL 0x42 //!< Device control register
#define TOUCHPAD_COMMAND 0x8F //!< Device command register
#define TOUCHPAD_RESET 0x54 //!< Address of reset
#define TOUCHPAD_PAGESELECT 0xFF //!< Address of page select (can be found in every page at the same address)
#define TOUCHPAD_PRODUCT_ID 0xA2 //!< Address of product ID string
/**
Operational states
*/
typedef enum
{
SleepmodeNormal = 0x00, //!< Normal operation
SleepmodeSensorSleep = 0x01 //!< Low power operation
} TouchpadSleepMode_t;
/**
@brief Function for Touchpad initialization.
@param device_address TWI address of the device in bits [6:0]
@retval true Touchpad was successfully identified and initialized
@retval false Unexpected product ID or communication failure
*/
bool touchpad_init(uint8_t device_address);
/**
@brief Function for attempting to soft-reset the device.
@retval true Reset succeeded
@retval false Reset failed
*/
bool touchpad_reset(void);
/**
@brief Function for reading the interrupt status register of the device. This clears all interrupts.
@param interrupt_status Address to store interrupt status to.
@retval true Register contents read successfully to interrupt_status
@retval false Reading failed
*/
bool touchpad_interrupt_status_read(uint8_t *interrupt_status);
/**
@brief Function for sleep mode configuration.
@note In low power mode the touchpad do not generate interrupts from touch sensing.
@param[in] mode Operational mode
@retval true Sleep mode set successfully
@retval false Sleep mode setting failed
*/
bool touchpad_set_sleep_mode(TouchpadSleepMode_t mode);
/**
@brief Function for reading a touchpad register contents over TWI.
@param[in] register_address Register address
@param[out] value Pointer to a data buffer where read data will be stored
@retval true Register read succeeded
@retval false Register read failed
*/
bool touchpad_read_register(uint8_t register_address, uint8_t *value);
/**
@brief Function for writing a touchpad register contents over TWI.
@param[in] register_address Register address
@param[in] value Value to write to register
@retval true Register write succeeded
@retval false Register write failed
*/
bool touchpad_write_register(uint8_t register_address, uint8_t value);
/**
@brief Function for writing touchpad register contents over TWI.
Writes one or more consecutive registers.
@param[out] product_id Pointer to a address to store product ID. Memory must be allocated for product_id_bytes number of bytes.
@param[in] product_id_bytes Number of bytes to read
@retval true Product ID read succeeded
@retval false Product ID read failed
*/
bool touchpad_product_id_read(uint8_t *product_id, uint8_t product_id_bytes);
/**
@brief Function for reading and verifying touchpad's product ID.
@retval true Product ID is what was expected
@retval false Product ID was not what was expected
*/
bool touchpad_product_id_verify(void);
/**
*@}
**/
/*lint --flb "Leave library region" */
#ifdef __cplusplus
}
#endif
#endif /* __TOUCHPAD_H__ */

View File

@@ -0,0 +1,124 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "uda1380.h"
#include <string.h>
ret_code_t uda1380_init(uda1380_iface_t const * p_iface,
uda1380_reg_t const * p_reg_config,
size_t reg_size)
{
ret_code_t ret = NRF_SUCCESS;
ret = nrf_drv_twi_init(&p_iface->twi, &p_iface->twi_cfg, NULL, NULL);
if (ret != NRF_SUCCESS)
{
return ret;
}
nrf_drv_twi_enable(&p_iface->twi);
/*Probe device*/
uint8_t rx[] = {0};
ret = nrf_drv_twi_rx(&p_iface->twi, p_iface->twi_addr, rx, sizeof(rx));
if (ret != NRF_SUCCESS)
{
return ret;
}
for (size_t i = 0; i < reg_size; ++i)
{
uint8_t p_dat[sizeof(uda1380_reg_t)];
memcpy(p_dat, &p_reg_config[i], sizeof(uda1380_reg_t));
ret = nrf_drv_twi_tx(&p_iface->twi, p_iface->twi_addr, p_dat, sizeof(uda1380_reg_t), false);
if (ret != NRF_SUCCESS)
{
break;
}
}
return ret;
}
ret_code_t uda1380_enable(uda1380_iface_t const * p_iface)
{
ret_code_t ret = NRF_SUCCESS;
static const uda1380_reg_t enable[] = {
UDA1380_REG_INIT(UDA1380_REG_PWR, 0xA500),
UDA1380_REG_INIT(UDA1380_REG_CLK, 0x0332),
};
for (size_t i = 0; i < ARRAY_SIZE(enable); ++i)
{
uint8_t p_dat[sizeof(uda1380_reg_t)];
memcpy(p_dat, &enable[i], sizeof(uda1380_reg_t));
ret = nrf_drv_twi_tx(&p_iface->twi, p_iface->twi_addr, p_dat, sizeof(uda1380_reg_t), false);
if (ret != NRF_SUCCESS)
{
break;
}
}
return ret;
}
ret_code_t uda1380_disable(uda1380_iface_t const * p_iface)
{
ret_code_t ret = NRF_SUCCESS;
static const uda1380_reg_t disable[] = {
UDA1380_REG_INIT(UDA1380_REG_PWR, 0x0000),
UDA1380_REG_INIT(UDA1380_REG_CLK, 0x0000),
};
for (size_t i = 0; i < ARRAY_SIZE(disable); ++i)
{
const uint8_t * p_dat = (const uint8_t *)&disable[i];
ret = nrf_drv_twi_tx(&p_iface->twi, p_iface->twi_addr, p_dat, sizeof(uda1380_reg_t), false);
if (ret != NRF_SUCCESS)
{
break;
}
}
return ret;
}

View File

@@ -0,0 +1,140 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef UDA1380_H__
#define UDA1380_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "nrf_drv_twi.h"
#define UDA1380_REG_CLK 0x00
#define UDA1380_REG_I2S 0x01
#define UDA1380_REG_PWR 0x02
#define UDA1380_REG_AMIX 0x03
#define UDA1380_REG_HPA 0x04
#define UDA1380_REG_VOL 0x10
#define UDA1380_REG_MIX_VOL 0x11
#define UDA1380_REG_PPROC 0x12
#define UDA1380_REG_DEEMP 0x13
#define UDA1380_REG_MIXER 0x14
#define UDA1380_REG_RESET 0x7F
/**
* @brief Default UDA1380 TWI configuration
*
* @param scl_pin SCL pin number
* @param sda_pin SDA pin number
*/
#define UDA1380_DEFAULT_TWI_CONFIG(scl_pin, sda_pin) { \
.scl = scl_pin, \
.sda = sda_pin, \
.frequency = NRF_DRV_TWI_FREQ_100K, \
.interrupt_priority = APP_IRQ_PRIORITY_HIGH, \
.clear_bus_init = false, \
.hold_bus_uninit = false \
}
/**
* @brief UDA1380 register descriptor
* */
typedef struct {
uint8_t addr; //!< Internal register address
uint8_t val[2]; //!< Internal register value
} uda1380_reg_t;
#define UDA1380_REG_INIT(address, value) { \
.addr = address, \
.val = {(value) / 256, (value) & 0xFF}, \
}
/**
* @brief UDA1380 TWI bus address*/
#define UDA1380_TWI_ADDRESS (0x18)
/**
* @brief UDA1380 interface
* */
typedef struct {
nrf_drv_twi_t twi; //!< TWI instance
nrf_drv_twi_config_t twi_cfg; //!< TWI configuration
uint8_t twi_addr; //!< UDA1380 TWI address
} uda1380_iface_t;
/**
* @brief Initializes UDA1380 codec IC
*
* @param p_iface Communication interface
* @param p_reg_config Configuration registers
* @param reg_size Number of configuration registers
*
* @return Standard error code
* */
ret_code_t uda1380_init(uda1380_iface_t const * p_iface,
uda1380_reg_t const * p_reg_config,
size_t reg_size);
/**
* @brief Enable UDA1380 codec
*
* @return Standard error code
* */
ret_code_t uda1380_enable(uda1380_iface_t const * p_iface);
/**
* @brief Disable UDA1380 codec
*
* @return Standard error code
* */
ret_code_t uda1380_disable(uda1380_iface_t const * p_iface);
#ifdef __cplusplus
}
#endif
#endif /* UDA1380_H__ */