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