mirror of
https://github.com/jam422470459/EPD-nRF52-hema213.git
synced 2025-12-19 14:53:19 +08:00
move components to SDK dir
This commit is contained in:
@@ -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
|
||||
@@ -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" */
|
||||
@@ -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
|
||||
@@ -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" */
|
||||
1136
SDK/12.3.0_d7731ad/components/drivers_nrf/twi_master/nrf_drv_twi.c
Normal file
1136
SDK/12.3.0_d7731ad/components/drivers_nrf/twi_master/nrf_drv_twi.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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__
|
||||
Reference in New Issue
Block a user