move components to SDK dir

This commit is contained in:
Shuanglei Tao
2025-03-03 09:06:26 +08:00
parent 20d1297e57
commit f4f4c9e60d
1021 changed files with 58 additions and 35059 deletions

View File

@@ -0,0 +1,55 @@
/**
* Copyright (c) 2012 - 2017, 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 TWI_MASTER_CONFIG
#define TWI_MASTER_CONFIG
#ifdef __cplusplus
extern "C" {
#endif
#define TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER (24U)
#define TWI_MASTER_CONFIG_DATA_PIN_NUMBER (25U)
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,332 @@
/**
* Copyright (c) 2009 - 2017, 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 "twi_master.h"
#include "twi_master_config.h"
#include <stdbool.h>
#include <stdint.h>
#include "nrf.h"
#include "nrf_delay.h"
#include "nrf_gpio.h"
/* Max cycles approximately to wait on RXDREADY and TXDREADY event,
* This is optimized way instead of using timers, this is not power aware. */
#define MAX_TIMEOUT_LOOPS (20000UL) /**< MAX while loops to wait for RXD/TXD event */
static bool twi_master_write(uint8_t * data, uint8_t data_length, bool issue_stop_condition)
{
uint32_t timeout = MAX_TIMEOUT_LOOPS; /* 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 && NRF_TWI1->EVENTS_ERROR == 0 && (--timeout))
{
// Do nothing.
}
if (timeout == 0 || NRF_TWI1->EVENTS_ERROR != 0)
{
// Recover the peripheral as indicated by PAN 56: "TWI: TWI module lock-up." found at
// Product Anomaly Notification document found at
// https://www.nordicsemi.com/eng/Products/Bluetooth-R-low-energy/nRF51822/#Downloads
NRF_TWI1->EVENTS_ERROR = 0;
NRF_TWI1->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
NRF_TWI1->POWER = 0;
nrf_delay_us(5);
NRF_TWI1->POWER = 1;
NRF_TWI1->ENABLE = TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos;
(void)twi_master_init();
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 read by twi_master.
*/
static bool twi_master_read(uint8_t * data, uint8_t data_length, bool issue_stop_condition)
{
uint32_t timeout = MAX_TIMEOUT_LOOPS; /* max loops to wait for RXDREADY event*/
if (data_length == 0)
{
/* Return false for requesting data of size 0 */
return false;
}
else if (data_length == 1)
{
NRF_PPI->CH[0].TEP = (uint32_t)&NRF_TWI1->TASKS_STOP;
}
else
{
NRF_PPI->CH[0].TEP = (uint32_t)&NRF_TWI1->TASKS_SUSPEND;
}
NRF_PPI->CHENSET = PPI_CHENSET_CH0_Msk;
NRF_TWI1->EVENTS_RXDREADY = 0;
NRF_TWI1->TASKS_STARTRX = 1;
/** @snippet [TWI HW master read] */
while (true)
{
while (NRF_TWI1->EVENTS_RXDREADY == 0 && NRF_TWI1->EVENTS_ERROR == 0 && (--timeout))
{
// Do nothing.
}
NRF_TWI1->EVENTS_RXDREADY = 0;
if (timeout == 0 || NRF_TWI1->EVENTS_ERROR != 0)
{
// Recover the peripheral as indicated by PAN 56: "TWI: TWI module lock-up." found at
// Product Anomaly Notification document found at
// https://www.nordicsemi.com/eng/Products/Bluetooth-R-low-energy/nRF51822/#Downloads
NRF_TWI1->EVENTS_ERROR = 0;
NRF_TWI1->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
NRF_TWI1->POWER = 0;
nrf_delay_us(5);
NRF_TWI1->POWER = 1;
NRF_TWI1->ENABLE = TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos;
(void)twi_master_init();
return false;
}
*data++ = NRF_TWI1->RXD;
/* Configure PPI to stop TWI master before we get last BB event */
if (--data_length == 1)
{
NRF_PPI->CH[0].TEP = (uint32_t)&NRF_TWI1->TASKS_STOP;
}
if (data_length == 0)
{
break;
}
// Recover the peripheral as indicated by PAN 56: "TWI: TWI module lock-up." found at
// Product Anomaly Notification document found at
// https://www.nordicsemi.com/eng/Products/Bluetooth-R-low-energy/nRF51822/#Downloads
nrf_delay_us(20);
NRF_TWI1->TASKS_RESUME = 1;
}
/** @snippet [TWI HW master read] */
/* Wait until stop sequence is sent */
while (NRF_TWI1->EVENTS_STOPPED == 0)
{
// Do nothing.
}
NRF_TWI1->EVENTS_STOPPED = 0;
NRF_PPI->CHENCLR = PPI_CHENCLR_CH0_Msk;
return true;
}
/**
* @brief Function for detecting stuck slaves (SDA = 0 and SCL = 1) and tries to clear the bus.
*
* @return
* @retval false Bus is stuck.
* @retval true Bus is clear.
*/
static bool twi_master_clear_bus(void)
{
uint32_t twi_state;
bool bus_clear;
uint32_t clk_pin_config;
uint32_t data_pin_config;
// Save and disable TWI hardware so software can take control over the pins.
twi_state = NRF_TWI1->ENABLE;
NRF_TWI1->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
clk_pin_config = \
NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER];
NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER] = \
(GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \
| (GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) \
| (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) \
| (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) \
| (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
data_pin_config = \
NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_DATA_PIN_NUMBER];
NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_DATA_PIN_NUMBER] = \
(GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \
| (GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) \
| (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) \
| (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) \
| (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
TWI_SDA_HIGH();
TWI_SCL_HIGH();
TWI_DELAY();
if ((TWI_SDA_READ() == 1) && (TWI_SCL_READ() == 1))
{
bus_clear = true;
}
else
{
uint_fast8_t i;
bus_clear = false;
// Clock max 18 pulses worst case scenario(9 for master to send the rest of command and 9
// for slave to respond) to SCL line and wait for SDA come high.
for (i=18; i--;)
{
TWI_SCL_LOW();
TWI_DELAY();
TWI_SCL_HIGH();
TWI_DELAY();
if (TWI_SDA_READ() == 1)
{
bus_clear = true;
break;
}
}
}
NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER] = clk_pin_config;
NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_DATA_PIN_NUMBER] = data_pin_config;
NRF_TWI1->ENABLE = twi_state;
return bus_clear;
}
/** @brief Function for initializing the twi_master.
*/
bool twi_master_init(void)
{
/* To secure correct signal levels on the pins used by the TWI
master when the system is in OFF mode, and when the TWI master is
disabled, these pins must be configured in the GPIO peripheral.
*/
NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER] = \
(GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \
| (GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) \
| (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) \
| (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) \
| (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos);
NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_DATA_PIN_NUMBER] = \
(GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \
| (GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) \
| (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) \
| (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) \
| (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos);
NRF_TWI1->EVENTS_RXDREADY = 0;
NRF_TWI1->EVENTS_TXDSENT = 0;
NRF_TWI1->PSELSCL = TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER;
NRF_TWI1->PSELSDA = TWI_MASTER_CONFIG_DATA_PIN_NUMBER;
NRF_TWI1->FREQUENCY = TWI_FREQUENCY_FREQUENCY_K100 << TWI_FREQUENCY_FREQUENCY_Pos;
NRF_PPI->CH[0].EEP = (uint32_t)&NRF_TWI1->EVENTS_BB;
NRF_PPI->CH[0].TEP = (uint32_t)&NRF_TWI1->TASKS_SUSPEND;
NRF_PPI->CHENCLR = PPI_CHENCLR_CH0_Msk;
NRF_TWI1->ENABLE = TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos;
return twi_master_clear_bus();
}
/** @brief Function for transfer by twi_master.
*/
bool twi_master_transfer(uint8_t address,
uint8_t * data,
uint8_t data_length,
bool issue_stop_condition)
{
bool transfer_succeeded = false;
if (data_length > 0 && twi_master_clear_bus())
{
NRF_TWI1->ADDRESS = (address >> 1);
if ((address & TWI_READ_BIT))
{
transfer_succeeded = twi_master_read(data, data_length, issue_stop_condition);
}
else
{
transfer_succeeded = twi_master_write(data, data_length, issue_stop_condition);
}
}
return transfer_succeeded;
}
/*lint --flb "Leave library region" */

View File

@@ -0,0 +1,138 @@
/**
* Copyright (c) 2009 - 2017, 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 TWI_MASTER_H
#define TWI_MASTER_H
/*lint ++flb "Enter library region" */
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @file
* @brief Software controlled TWI Master driver.
*
*
* @defgroup lib_driver_twi_master Software controlled TWI Master driver
* @{
* @ingroup nrf_twi
* @brief Software controlled TWI Master driver (deprecated).
*
* @warning This module is deprecated.
*
* Supported features:
* - Repeated start
* - No multi-master
* - Only 7-bit addressing
* - Supports clock stretching (with optional SMBus style slave timeout)
* - Tries to handle slaves stuck in the middle of transfer
*/
#define TWI_READ_BIT (0x01) //!< If this bit is set in the address field, transfer direction is from slave to master.
#define TWI_ISSUE_STOP ((bool)true) //!< Parameter for @ref twi_master_transfer
#define TWI_DONT_ISSUE_STOP ((bool)false) //!< Parameter for @ref twi_master_transfer
/* These macros are needed to see if the slave is stuck and we as master send dummy clock cycles to end its wait */
/*lint -e717 -save "Suppress do {} while (0) for these macros" */
/*lint ++flb "Enter library region" */
#define TWI_SCL_HIGH() do { NRF_GPIO->OUTSET = (1UL << TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER); } while (0) /*!< Pulls SCL line high */
#define TWI_SCL_LOW() do { NRF_GPIO->OUTCLR = (1UL << TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER); } while (0) /*!< Pulls SCL line low */
#define TWI_SDA_HIGH() do { NRF_GPIO->OUTSET = (1UL << TWI_MASTER_CONFIG_DATA_PIN_NUMBER); } while (0) /*!< Pulls SDA line high */
#define TWI_SDA_LOW() do { NRF_GPIO->OUTCLR = (1UL << TWI_MASTER_CONFIG_DATA_PIN_NUMBER); } while (0) /*!< Pulls SDA line low */
#define TWI_SDA_INPUT() do { NRF_GPIO->DIRCLR = (1UL << TWI_MASTER_CONFIG_DATA_PIN_NUMBER); } while (0) /*!< Configures SDA pin as input */
#define TWI_SDA_OUTPUT() do { NRF_GPIO->DIRSET = (1UL << TWI_MASTER_CONFIG_DATA_PIN_NUMBER); } while (0) /*!< Configures SDA pin as output */
#define TWI_SCL_OUTPUT() do { NRF_GPIO->DIRSET = (1UL << TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER); } while (0) /*!< Configures SCL pin as output */
/*lint -restore */
#define TWI_SDA_READ() ((NRF_GPIO->IN >> TWI_MASTER_CONFIG_DATA_PIN_NUMBER) & 0x1UL) /*!< Reads current state of SDA */
#define TWI_SCL_READ() ((NRF_GPIO->IN >> TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER) & 0x1UL) /*!< Reads current state of SCL */
#define TWI_DELAY() nrf_delay_us(4) /*!< Time to wait when pin states are changed. For fast-mode the delay can be zero and for standard-mode 4 us delay is sufficient. */
/**
* @brief Function for initializing TWI bus IO pins and checks if the bus is operational.
*
* Both pins are configured as Standard-0, No-drive-1 (open drain).
*
* @return
* @retval true TWI bus is clear for transfers.
* @retval false TWI bus is stuck.
*/
bool twi_master_init(void);
/**
* @brief Function for transferring data over TWI bus.
*
* If TWI master detects even one NACK from the slave or timeout occurs, STOP condition is issued
* and the function returns false.
* Bit 0 (@ref TWI_READ_BIT) in the address parameter controls transfer direction;
* - If 1, master reads data_length number of bytes from the slave
* - If 0, master writes data_length number of bytes to the slave.
*
* @note Make sure at least data_length number of bytes is allocated in data if TWI_READ_BIT is set.
* @note @ref TWI_ISSUE_STOP
*
* @param address Data transfer direction (LSB) / Slave address (7 MSBs).
* @param data Pointer to data.
* @param data_length Number of bytes to transfer.
* @param issue_stop_condition If @ref TWI_ISSUE_STOP, STOP condition is issued before exiting function. If @ref TWI_DONT_ISSUE_STOP, STOP condition is not issued before exiting function. If transfer failed for any reason, STOP condition will be issued in any case.
* @return
* @retval true Data transfer succeeded without errors.
* @retval false Data transfer failed.
*/
bool twi_master_transfer(uint8_t address, uint8_t *data, uint8_t data_length, bool issue_stop_condition);
/**
*@}
**/
/*lint --flb "Leave library region" */
#ifdef __cplusplus
}
#endif
#endif //TWI_MASTER_H

View File

@@ -0,0 +1,520 @@
/**
* Copyright (c) 2009 - 2017, 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 "nrf_delay.h"
#include "twi_master_config.h"
/*lint -e415 -e845 -save "Out of bounds access" */
#define TWI_SDA_STANDARD0_NODRIVE1() do { \
NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_DATA_PIN_NUMBER] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \
|(GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) \
|(GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) \
|(GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) \
|(GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos); \
} while (0) /*!< Configures SDA pin to Standard-0, No-drive 1 */
#define TWI_SCL_STANDARD0_NODRIVE1() do { \
NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \
|(GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) \
|(GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) \
|(GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) \
|(GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos); \
} while (0) /*!< Configures SCL pin to Standard-0, No-drive 1 */
/*lint -restore */
#ifndef TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE
#define TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE (0UL) //!< Unit is number of empty loops. Timeout for SMBus devices is 35 ms. Set to zero to disable slave timeout altogether.
#endif
static bool twi_master_clear_bus(void);
static bool twi_master_issue_startcondition(void);
static bool twi_master_issue_stopcondition(void);
static bool twi_master_clock_byte(uint_fast8_t databyte);
static bool twi_master_clock_byte_in(uint8_t * databyte, bool ack);
static bool twi_master_wait_while_scl_low(void);
bool twi_master_init(void)
{
// Configure both pins to output Standard 0, No-drive (open-drain) 1
TWI_SDA_STANDARD0_NODRIVE1(); /*lint !e416 "Creation of out of bounds pointer" */
TWI_SCL_STANDARD0_NODRIVE1(); /*lint !e416 "Creation of out of bounds pointer" */
// Configure SCL as output
TWI_SCL_HIGH();
TWI_SCL_OUTPUT();
// Configure SDA as output
TWI_SDA_HIGH();
TWI_SDA_OUTPUT();
return twi_master_clear_bus();
}
bool twi_master_transfer(uint8_t address, uint8_t * data, uint8_t data_length, bool issue_stop_condition)
{
bool transfer_succeeded = true;
transfer_succeeded &= twi_master_issue_startcondition();
transfer_succeeded &= twi_master_clock_byte(address);
if (address & TWI_READ_BIT)
{
/* Transfer direction is from Slave to Master */
while (data_length-- && transfer_succeeded)
{
// To indicate to slave that we've finished transferring last data byte
// we need to NACK the last transfer.
if (data_length == 0)
{
transfer_succeeded &= twi_master_clock_byte_in(data, (bool)false);
}
else
{
transfer_succeeded &= twi_master_clock_byte_in(data, (bool)true);
}
data++;
}
}
else
{
/* Transfer direction is from Master to Slave */
while (data_length-- && transfer_succeeded)
{
transfer_succeeded &= twi_master_clock_byte(*data);
data++;
}
}
if (issue_stop_condition || !transfer_succeeded)
{
transfer_succeeded &= twi_master_issue_stopcondition();
}
return transfer_succeeded;
}
/**
* @brief Function for detecting stuck slaves and tries to clear the bus.
*
* @return
* @retval false Bus is stuck.
* @retval true Bus is clear.
*/
static bool twi_master_clear_bus(void)
{
bool bus_clear;
TWI_SDA_HIGH();
TWI_SCL_HIGH();
TWI_DELAY();
if (TWI_SDA_READ() == 1 && TWI_SCL_READ() == 1)
{
bus_clear = true;
}
else if (TWI_SCL_READ() == 1)
{
bus_clear = false;
// Clock max 18 pulses worst case scenario(9 for master to send the rest of command and 9 for slave to respond) to SCL line and wait for SDA come high
for (uint_fast8_t i = 18; i--;)
{
TWI_SCL_LOW();
TWI_DELAY();
TWI_SCL_HIGH();
TWI_DELAY();
if (TWI_SDA_READ() == 1)
{
bus_clear = true;
break;
}
}
}
else
{
bus_clear = false;
}
return bus_clear;
}
/**
* @brief Function for issuing TWI START condition to the bus.
*
* START condition is signaled by pulling SDA low while SCL is high. After this function SCL and SDA will be low.
*
* @return
* @retval false Timeout detected
* @retval true Clocking succeeded
*/
static bool twi_master_issue_startcondition(void)
{
#if 0
if (TWI_SCL_READ() == 1 && TWI_SDA_READ() == 1)
{
// Pull SDA low
TWI_SDA_LOW();
}
else if (TWI_SCL_READ() == 1 && TWI_SDA_READ() == 0)
{
// Issue Stop by pulling SDA high
TWI_SDA_HIGH();
TWI_DELAY();
// Then Start by pulling SDA low
TWI_SDA_LOW();
}
else if (TWI_SCL_READ() == 0 && TWI_SDA_READ() == 0)
{
// First pull SDA high
TWI_SDA_HIGH();
// Then SCL high
if (!twi_master_wait_while_scl_low())
{
return false;
}
// Then SDA low
TWI_SDA_LOW();
}
else if (TWI_SCL_READ() == 0 && TWI_SDA_READ() == 1)
{
// SCL high
if (!twi_master_wait_while_scl_low())
{
return false;
}
// Then SDA low
TWI_SDA_LOW();
}
TWI_DELAY();
TWI_SCL_LOW();
#endif
// Make sure both SDA and SCL are high before pulling SDA low.
TWI_SDA_HIGH();
TWI_DELAY();
if (!twi_master_wait_while_scl_low())
{
return false;
}
TWI_SDA_LOW();
TWI_DELAY();
// Other module function expect SCL to be low
TWI_SCL_LOW();
TWI_DELAY();
return true;
}
/**
* @brief Function for issuing TWI STOP condition to the bus.
*
* STOP condition is signaled by pulling SDA high while SCL is high. After this function SDA and SCL will be high.
*
* @return
* @retval false Timeout detected
* @retval true Clocking succeeded
*/
static bool twi_master_issue_stopcondition(void)
{
#if 0
if (TWI_SCL_READ() == 1 && TWI_SDA_READ() == 1)
{
// Issue start, then issue stop
// Pull SDA low to issue START
TWI_SDA_LOW();
TWI_DELAY();
// Pull SDA high while SCL is high to issue STOP
TWI_SDA_HIGH();
}
else if (TWI_SCL_READ() == 1 && TWI_SDA_READ() == 0)
{
// Pull SDA high while SCL is high to issue STOP
TWI_SDA_HIGH();
}
else if (TWI_SCL_READ() == 0 && TWI_SDA_READ() == 0)
{
if (!twi_master_wait_while_scl_low())
{
return false;
}
// Pull SDA high while SCL is high to issue STOP
TWI_SDA_HIGH();
}
else if (TWI_SCL_READ() == 0 && TWI_SDA_READ() == 1)
{
TWI_SDA_LOW();
TWI_DELAY();
// SCL high
if (!twi_master_wait_while_scl_low())
{
return false;
}
// Pull SDA high while SCL is high to issue STOP
TWI_SDA_HIGH();
}
TWI_DELAY();
#endif
TWI_SDA_LOW();
TWI_DELAY();
if (!twi_master_wait_while_scl_low())
{
return false;
}
TWI_SDA_HIGH();
TWI_DELAY();
return true;
}
/**
* @brief Function for clocking one data byte out and reads slave acknowledgment.
*
* Can handle clock stretching.
* After calling this function SCL is low and SDA low/high depending on the
* value of LSB of the data byte.
* SCL is expected to be output and low when entering this function.
*
* @param databyte Data byte to clock out.
* @return
* @retval true Slave acknowledged byte.
* @retval false Timeout or slave didn't acknowledge byte.
*/
static bool twi_master_clock_byte(uint_fast8_t databyte)
{
bool transfer_succeeded = true;
/** @snippet [TWI SW master write] */
// Make sure SDA is an output
TWI_SDA_OUTPUT();
// MSB first
for (uint_fast8_t i = 0x80; i != 0; i >>= 1)
{
TWI_SCL_LOW();
TWI_DELAY();
if (databyte & i)
{
TWI_SDA_HIGH();
}
else
{
TWI_SDA_LOW();
}
if (!twi_master_wait_while_scl_low())
{
transfer_succeeded = false; // Timeout
break;
}
}
// Finish last data bit by pulling SCL low
TWI_SCL_LOW();
TWI_DELAY();
/** @snippet [TWI SW master write] */
// Configure TWI_SDA pin as input for receiving the ACK bit
TWI_SDA_INPUT();
// Give some time for the slave to load the ACK bit on the line
TWI_DELAY();
// Pull SCL high and wait a moment for SDA line to settle
// Make sure slave is not stretching the clock
transfer_succeeded &= twi_master_wait_while_scl_low();
// Read ACK/NACK. NACK == 1, ACK == 0
transfer_succeeded &= !(TWI_SDA_READ());
// Finish ACK/NACK bit clock cycle and give slave a moment to release control
// of the SDA line
TWI_SCL_LOW();
TWI_DELAY();
// Configure TWI_SDA pin as output as other module functions expect that
TWI_SDA_OUTPUT();
return transfer_succeeded;
}
/**
* @brief Function for clocking one data byte in and sends ACK/NACK bit.
*
* Can handle clock stretching.
* SCL is expected to be output and low when entering this function.
* After calling this function, SCL is high and SDA low/high depending if ACK/NACK was sent.
*
* @param databyte Data byte to clock out.
* @param ack If true, send ACK. Otherwise send NACK.
* @return
* @retval true Byte read succesfully
* @retval false Timeout detected
*/
static bool twi_master_clock_byte_in(uint8_t *databyte, bool ack)
{
uint_fast8_t byte_read = 0;
bool transfer_succeeded = true;
/** @snippet [TWI SW master read] */
// Make sure SDA is an input
TWI_SDA_INPUT();
// SCL state is guaranteed to be high here
// MSB first
for (uint_fast8_t i = 0x80; i != 0; i >>= 1)
{
if (!twi_master_wait_while_scl_low())
{
transfer_succeeded = false;
break;
}
if (TWI_SDA_READ())
{
byte_read |= i;
}
else
{
// No need to do anything
}
TWI_SCL_LOW();
TWI_DELAY();
}
// Make sure SDA is an output before we exit the function
TWI_SDA_OUTPUT();
/** @snippet [TWI SW master read] */
*databyte = (uint8_t)byte_read;
// Send ACK bit
// SDA high == NACK, SDA low == ACK
if (ack)
{
TWI_SDA_LOW();
}
else
{
TWI_SDA_HIGH();
}
// Let SDA line settle for a moment
TWI_DELAY();
// Drive SCL high to start ACK/NACK bit transfer
// Wait until SCL is high, or timeout occurs
if (!twi_master_wait_while_scl_low())
{
transfer_succeeded = false; // Timeout
}
// Finish ACK/NACK bit clock cycle and give slave a moment to react
TWI_SCL_LOW();
TWI_DELAY();
return transfer_succeeded;
}
/**
* @brief Function for pulling SCL high and waits until it is high or timeout occurs.
*
* SCL is expected to be output before entering this function.
* @note If TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE is set to zero, timeout functionality is not compiled in.
* @return
* @retval true SCL is now high.
* @retval false Timeout occurred and SCL is still low.
*/
static bool twi_master_wait_while_scl_low(void)
{
#if TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE != 0
uint32_t volatile timeout_counter = TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE;
#endif
// Pull SCL high just in case if something left it low
TWI_SCL_HIGH();
TWI_DELAY();
while (TWI_SCL_READ() == 0)
{
// If SCL is low, one of the slaves is busy and we must wait
#if TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE != 0
if (timeout_counter-- == 0)
{
// If timeout_detected, return false
return false;
}
#endif
}
return true;
}
/*lint --flb "Leave library region" */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,429 @@
/**
* Copyright (c) 2015 - 2017, 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.
*
*/
/**@file
* @addtogroup nrf_twi Two Wire master interface (TWI/TWIM)
* @ingroup nrf_drivers
* @brief Two Wire master interface (TWI/TWIM) APIs.
*
*
* @defgroup nrf_drv_twi TWIS driver
* @{
* @ingroup nrf_twi
* @brief TWI master APIs.
*/
#ifndef NRF_DRV_TWI_H__
#define NRF_DRV_TWI_H__
#include "nordic_common.h"
#include "sdk_config.h"
// This set of macros makes it possible to exclude parts of code when one type
// of supported peripherals is not used.
#if ((TWI0_ENABLED == 1 && TWI0_USE_EASY_DMA == 1) || \
(TWI1_ENABLED == 1 && TWI1_USE_EASY_DMA == 1))
#define TWIM_IN_USE
#endif
#if ((TWI0_ENABLED == 1 && TWI0_USE_EASY_DMA != 1) || \
(TWI1_ENABLED == 1 && TWI1_USE_EASY_DMA != 1))
#define TWI_IN_USE
#endif
#include "nrf_twi.h"
#ifdef TWIM_IN_USE
#include "nrf_twim.h"
#endif
#include "sdk_errors.h"
#ifdef __cplusplus
extern "C" {
#endif
#if defined(TWIM_IN_USE)
#define NRF_DRV_TWI_PERIPHERAL(id) \
(CONCAT_3(TWI, id, _USE_EASY_DMA) == 1 ? \
(void *)CONCAT_2(NRF_TWIM, id) \
: (void *)CONCAT_2(NRF_TWI, id))
#else
#define NRF_DRV_TWI_PERIPHERAL(id) (void *)CONCAT_2(NRF_TWI, id)
#endif
/**
* @brief Structure for the TWI master driver instance.
*/
typedef struct
{
union
{
#ifdef TWIM_IN_USE
NRF_TWIM_Type * p_twim; ///< Pointer to a structure with TWIM registers.
#endif
NRF_TWI_Type * p_twi; ///< Pointer to a structure with TWI registers.
} reg;
uint8_t drv_inst_idx; ///< Driver instance index.
bool use_easy_dma; ///< True if the peripheral with EasyDMA (TWIM) shall be used.
} nrf_drv_twi_t;
#define TWI0_INSTANCE_INDEX 0
#define TWI1_INSTANCE_INDEX TWI0_INSTANCE_INDEX+TWI0_ENABLED
/**
* @brief Macro for creating a TWI master driver instance.
*/
#define NRF_DRV_TWI_INSTANCE(id) \
{ \
.reg = {NRF_DRV_TWI_PERIPHERAL(id)}, \
.drv_inst_idx = CONCAT_3(TWI, id, _INSTANCE_INDEX), \
.use_easy_dma = CONCAT_3(TWI, id, _USE_EASY_DMA) \
}
/**
* @brief Structure for the TWI master driver instance configuration.
*/
typedef struct
{
uint32_t scl; ///< SCL pin number.
uint32_t sda; ///< SDA pin number.
nrf_twi_frequency_t frequency; ///< TWI frequency.
uint8_t interrupt_priority; ///< Interrupt priority.
bool clear_bus_init; ///< Clear bus during init.
bool hold_bus_uninit; ///< Hold pull up state on gpio pins after uninit.
} nrf_drv_twi_config_t;
/**
* @brief TWI master driver instance default configuration.
*/
#define NRF_DRV_TWI_DEFAULT_CONFIG \
{ \
.frequency = (nrf_twi_frequency_t)TWI_DEFAULT_CONFIG_FREQUENCY, \
.scl = 31, \
.sda = 31, \
.interrupt_priority = TWI_DEFAULT_CONFIG_IRQ_PRIORITY, \
.clear_bus_init = TWI_DEFAULT_CONFIG_CLR_BUS_INIT, \
.hold_bus_uninit = TWI_DEFAULT_CONFIG_HOLD_BUS_UNINIT, \
}
#define NRF_DRV_TWI_FLAG_TX_POSTINC (1UL << 0) /**< TX buffer address incremented after transfer. */
#define NRF_DRV_TWI_FLAG_RX_POSTINC (1UL << 1) /**< RX buffer address incremented after transfer. */
#define NRF_DRV_TWI_FLAG_NO_XFER_EVT_HANDLER (1UL << 2) /**< Interrupt after each transfer is suppressed, and the event handler is not called. */
#define NRF_DRV_TWI_FLAG_HOLD_XFER (1UL << 3) /**< Set up the transfer but do not start it. */
#define NRF_DRV_TWI_FLAG_REPEATED_XFER (1UL << 4) /**< Flag indicating that the transfer will be executed multiple times. */
#define NRF_DRV_TWI_FLAG_TX_NO_STOP (1UL << 5) /**< Flag indicating that the TX transfer will not end with a stop condition. */
/**
* @brief TWI master driver event types.
*/
typedef enum
{
NRF_DRV_TWI_EVT_DONE, ///< Transfer completed event.
NRF_DRV_TWI_EVT_ADDRESS_NACK, ///< Error event: NACK received after sending the address.
NRF_DRV_TWI_EVT_DATA_NACK ///< Error event: NACK received after sending a data byte.
} nrf_drv_twi_evt_type_t;
/**
* @brief TWI master driver transfer types.
*/
typedef enum
{
NRF_DRV_TWI_XFER_TX, ///< TX transfer.
NRF_DRV_TWI_XFER_RX, ///< RX transfer.
NRF_DRV_TWI_XFER_TXRX, ///< TX transfer followed by RX transfer with repeated start.
NRF_DRV_TWI_XFER_TXTX ///< TX transfer followed by TX transfer with repeated start.
} nrf_drv_twi_xfer_type_t;
/**
* @brief Structure for a TWI transfer descriptor.
*/
typedef struct
{
nrf_drv_twi_xfer_type_t type; ///< Type of transfer.
uint8_t address; ///< Slave address.
uint8_t primary_length; ///< Number of bytes transferred.
uint8_t secondary_length; ///< Number of bytes transferred.
uint8_t * p_primary_buf; ///< Pointer to transferred data.
uint8_t * p_secondary_buf; ///< Pointer to transferred data.
} nrf_drv_twi_xfer_desc_t;
/**@brief Macro for setting the TX transfer descriptor. */
#define NRF_DRV_TWI_XFER_DESC_TX(addr, p_data, length) \
{ \
.type = NRF_DRV_TWI_XFER_TX, \
.address = addr, \
.primary_length = length, \
.p_primary_buf = p_data, \
}
/**@brief Macro for setting the RX transfer descriptor. */
#define NRF_DRV_TWI_XFER_DESC_RX(addr, p_data, length) \
{ \
.type = NRF_DRV_TWI_XFER_RX, \
.address = addr, \
.primary_length = length, \
.p_primary_buf = p_data, \
}
/**@brief Macro for setting the TXRX transfer descriptor. */
#define NRF_DRV_TWI_XFER_DESC_TXRX(addr, p_tx, tx_len, p_rx, rx_len) \
{ \
.type = NRF_DRV_TWI_XFER_TXRX, \
.address = addr, \
.primary_length = tx_len, \
.secondary_length = rx_len, \
.p_primary_buf = p_tx, \
.p_secondary_buf = p_rx, \
}
/**@brief Macro for setting the TXTX transfer descriptor. */
#define NRF_DRV_TWI_XFER_DESC_TXTX(addr, p_tx, tx_len, p_tx2, tx_len2) \
{ \
.type = NRF_DRV_TWI_XFER_TXTX, \
.address = addr, \
.primary_length = tx_len, \
.secondary_length = tx_len2, \
.p_primary_buf = p_tx, \
.p_secondary_buf = p_tx2, \
}
/**
* @brief Structure for a TWI event.
*/
typedef struct
{
nrf_drv_twi_evt_type_t type; ///< Event type.
nrf_drv_twi_xfer_desc_t xfer_desc; ///< Transfer details.
} nrf_drv_twi_evt_t;
/**
* @brief TWI event handler prototype.
*/
typedef void (* nrf_drv_twi_evt_handler_t)(nrf_drv_twi_evt_t const * p_event,
void * p_context);
/**
* @brief Function for initializing the TWI driver instance.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] p_config Initial configuration. If NULL, the default configuration is used.
* @param[in] event_handler Event handler provided by the user. If NULL, blocking mode is enabled.
* @param[in] p_context Context passed to event handler.
*
* @retval NRF_SUCCESS If initialization was successful.
* @retval NRF_ERROR_INVALID_STATE If the driver is in invalid state.
* @retval NRF_ERROR_BUSY If some other peripheral with the same
* instance ID is already in use. This is
* possible only if PERIPHERAL_RESOURCE_SHARING_ENABLED
* is set to a value other than zero.
*/
ret_code_t nrf_drv_twi_init(nrf_drv_twi_t const * p_instance,
nrf_drv_twi_config_t const * p_config,
nrf_drv_twi_evt_handler_t event_handler,
void * p_context);
/**
* @brief Function for uninitializing the TWI instance.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrf_drv_twi_uninit(nrf_drv_twi_t const * p_instance);
/**
* @brief Function for enabling the TWI instance.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrf_drv_twi_enable(nrf_drv_twi_t const * p_instance);
/**
* @brief Function for disabling the TWI instance.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrf_drv_twi_disable(nrf_drv_twi_t const * p_instance);
/**
* @brief Function for sending data to a TWI slave.
*
* The transmission will be stopped when an error occurs. If a transfer is ongoing,
* the function returns the error code @ref NRF_ERROR_BUSY.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] address Address of a specific slave device (only 7 LSB).
* @param[in] p_data Pointer to a transmit buffer.
* @param[in] length Number of bytes to send.
* @param[in] no_stop If set, the stop condition is not generated on the bus
* after the transfer has completed successfully (allowing
* for a repeated start in the next transfer).
*
* @retval NRF_SUCCESS If the procedure was successful.
* @retval NRF_ERROR_BUSY If the driver is not ready for a new transfer.
* @retval NRF_ERROR_INTERNAL If an error was detected by hardware.
* @retval NRF_ERROR_INVALID_ADDR If the EasyDMA is used and memory adress in not in RAM.
* @retval NRF_ERROR_DRV_TWI_ERR_ANACK If NACK received after sending the address.
* @retval NRF_ERROR_DRV_TWI_ERR_DNACK If NACK received after sending a data byte.
*/
ret_code_t nrf_drv_twi_tx(nrf_drv_twi_t const * p_instance,
uint8_t address,
uint8_t const * p_data,
uint8_t length,
bool no_stop);
/**
* @brief Function for reading data from a TWI slave.
*
* The transmission will be stopped when an error occurs. If a transfer is ongoing,
* the function returns the error code @ref NRF_ERROR_BUSY.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] address Address of a specific slave device (only 7 LSB).
* @param[in] p_data Pointer to a receive buffer.
* @param[in] length Number of bytes to be received.
*
* @retval NRF_SUCCESS If the procedure was successful.
* @retval NRF_ERROR_BUSY If the driver is not ready for a new transfer.
* @retval NRF_ERROR_INTERNAL If an error was detected by hardware.
* @retval NRF_ERROR_DRV_TWI_ERR_OVERRUN If the unread data was replaced by new data
* @retval NRF_ERROR_DRV_TWI_ERR_ANACK If NACK received after sending the address.
* @retval NRF_ERROR_DRV_TWI_ERR_DNACK If NACK received after sending a data byte.
*/
ret_code_t nrf_drv_twi_rx(nrf_drv_twi_t const * p_instance,
uint8_t address,
uint8_t * p_data,
uint8_t length);
/**
* @brief Function for preparing a TWI transfer.
*
* The following transfer types can be configured (@ref nrf_drv_twi_xfer_desc_t::type):
* - @ref NRF_DRV_TWI_XFER_TXRX<span></span>: Write operation followed by a read operation (without STOP condition in between).
* - @ref NRF_DRV_TWI_XFER_TXTX<span></span>: Write operation followed by a write operation (without STOP condition in between).
* - @ref NRF_DRV_TWI_XFER_TX<span></span>: Write operation (with or without STOP condition).
* - @ref NRF_DRV_TWI_XFER_RX<span></span>: Read operation (with STOP condition).
*
* Additional options are provided using the flags parameter:
* - @ref NRF_DRV_TWI_FLAG_TX_POSTINC and @ref NRF_DRV_TWI_FLAG_RX_POSTINC<span></span>: Post-incrementation of buffer addresses. Supported only by TWIM.
* - @ref NRF_DRV_TWI_FLAG_NO_XFER_EVT_HANDLER<span></span>: No user event handler after transfer completion. In most cases, this also means no interrupt at the end of the transfer.
* - @ref NRF_DRV_TWI_FLAG_HOLD_XFER<span></span>: Driver is not starting the transfer. Use this flag if the transfer is triggered externally by PPI. Supported only by TWIM.
* Use @ref nrf_drv_twi_start_task_get to get the address of the start task.
* - @ref NRF_DRV_TWI_FLAG_REPEATED_XFER<span></span>: Prepare for repeated transfers. You can set up a number of transfers that will be triggered externally (for example by PPI).
* An example is a TXRX transfer with the options @ref NRF_DRV_TWI_FLAG_RX_POSTINC, @ref NRF_DRV_TWI_FLAG_NO_XFER_EVT_HANDLER, and @ref NRF_DRV_TWI_FLAG_REPEATED_XFER.
* After the transfer is set up, a set of transfers can be triggered by PPI that will read, for example, the same register of an
* external component and put it into a RAM buffer without any interrupts. @ref nrf_drv_twi_stopped_event_get can be used to get the
* address of the STOPPED event, which can be used to count the number of transfers. If @ref NRF_DRV_TWI_FLAG_REPEATED_XFER is used,
* the driver does not set the driver instance into busy state, so you must ensure that the next transfers are set up
* when TWIM is not active. Supported only by TWIM.
* - @ref NRF_DRV_TWI_FLAG_TX_NO_STOP<span></span>: No stop condition after TX transfer.
*
* @note
* Some flag combinations are invalid:
* - @ref NRF_DRV_TWI_FLAG_TX_NO_STOP with @ref nrf_drv_twi_xfer_desc_t::type different than @ref NRF_DRV_TWI_XFER_TX
* - @ref NRF_DRV_TWI_FLAG_REPEATED_XFER with @ref nrf_drv_twi_xfer_desc_t::type set to @ref NRF_DRV_TWI_XFER_TXTX
*
* If @ref nrf_drv_twi_xfer_desc_t::type is set to @ref NRF_DRV_TWI_XFER_TX and the @ref NRF_DRV_TWI_FLAG_TX_NO_STOP and @ref NRF_DRV_TWI_FLAG_REPEATED_XFER
* flags are set, two tasks must be used to trigger a transfer: TASKS_RESUME followed by TASKS_STARTTX. If no stop condition is generated,
* TWIM is in SUSPENDED state. Therefore, it must be resumed before the transfer can be started.
*
* @note
* This function should be used only if the instance is configured to work in non-blocking mode. If the function is used in blocking mode, the driver asserts.
* @note If you are using this function with TWI, the only supported flag is @ref NRF_DRV_TWI_FLAG_TX_NO_STOP. All other flags require TWIM.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] p_xfer_desc Pointer to the transfer descriptor.
* @param[in] flags Transfer options (0 for default settings).
*
* @retval NRF_SUCCESS If the procedure was successful.
* @retval NRF_ERROR_BUSY If the driver is not ready for a new transfer.
* @retval NRF_ERROR_NOT_SUPPORTED If the provided parameters are not supported.
* @retval NRF_ERROR_INTERNAL If an error was detected by hardware.
* @retval NRF_ERROR_INVALID_ADDR If the EasyDMA is used and memory adress in not in RAM
* @retval NRF_ERROR_DRV_TWI_ERR_OVERRUN If the unread data was replaced by new data (TXRX and RX)
* @retval NRF_ERROR_DRV_TWI_ERR_ANACK If NACK received after sending the address.
* @retval NRF_ERROR_DRV_TWI_ERR_DNACK If NACK received after sending a data byte.
*/
ret_code_t nrf_drv_twi_xfer(nrf_drv_twi_t const * p_instance,
nrf_drv_twi_xfer_desc_t const * p_xfer_desc,
uint32_t flags);
/**
* @brief Function for getting the transferred data count.
*
* This function provides valid results only in legacy mode.
*
* @param[in] p_instance Pointer to the driver instance structure.
*
* @return Data count.
*/
uint32_t nrf_drv_twi_data_count_get(nrf_drv_twi_t const * const p_instance);
/**
* @brief Function for returning the address of a TWI/TWIM start task.
*
* This function should be used if @ref nrf_drv_twi_xfer was called with the flag @ref NRF_DRV_TWI_FLAG_HOLD_XFER.
* In that case, the transfer is not started by the driver, but it must be started externally by PPI.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] xfer_type Transfer type used in the last call of the @ref nrf_drv_twi_xfer function.
*
* @return Start task address (TX or RX) depending on the value of xfer_type.
*/
uint32_t nrf_drv_twi_start_task_get(nrf_drv_twi_t const * p_instance, nrf_drv_twi_xfer_type_t xfer_type);
/**
* @brief Function for returning the address of a STOPPED TWI/TWIM event.
*
* A STOPPED event can be used to detect the end of a transfer if the @ref NRF_DRV_TWI_FLAG_NO_XFER_EVT_HANDLER
* option is used.
*
* @param[in] p_instance Pointer to the driver instance structure.
*
* @return STOPPED event address.
*/
uint32_t nrf_drv_twi_stopped_event_get(nrf_drv_twi_t const * p_instance);
/**
*@}
**/
#ifdef __cplusplus
}
#endif
#endif // NRF_DRV_TWI_H__