diff options
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master')
4 files changed, 1042 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master/deprecated/config/twi_master_config.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master/deprecated/config/twi_master_config.h new file mode 100644 index 0000000..9c182e6 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master/deprecated/config/twi_master_config.h @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2012 - 2018, 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 diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master/deprecated/twi_hw_master.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master/deprecated/twi_hw_master.c new file mode 100644 index 0000000..e3692a3 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master/deprecated/twi_hw_master.c @@ -0,0 +1,331 @@ +/** + * Copyright (c) 2009 - 2018, 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" */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master/deprecated/twi_master.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master/deprecated/twi_master.h new file mode 100644 index 0000000..3cd975e --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master/deprecated/twi_master.h @@ -0,0 +1,137 @@ +/** + * Copyright (c) 2009 - 2018, 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 diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master/deprecated/twi_sw_master.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master/deprecated/twi_sw_master.c new file mode 100644 index 0000000..115e997 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master/deprecated/twi_sw_master.c @@ -0,0 +1,519 @@ +/** + * Copyright (c) 2009 - 2018, 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" */ |