This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nRF52840 output the 32.768kHz clock on any GPIO in SPI Communication.

Dear Nordic Developer Zone,

I am working on MAX30003 ECG (https://datasheets.maximintegrated.com/en/ds/MAX30003.pdf)  with Nrf52840-DK. My sensor is work on the 32.768kHz external clock. 

but in Nrf I don't know which GPIO_PIN is assigned for that.

I visited below link but I unable to find solutions: 

https://devzone.nordicsemi.com/f/nordic-q-a/23474/nrf52832-fclk-pin/92210#92210

https://devzone.nordicsemi.com/f/nordic-q-a/15996/can-the-nrf52-output-the-32-768khz-clock-on-a-gpio

I am referring (SDK15.2 -PCA10056-spi code)

I have some questions about that:

1) Can I do the merging of timer and gpiote example code into SPI?

2) please give me detail about how to generate 32.768kHz clock ?

I have stuck  on below issue, 

https://maximsupport.microsoftcrmportals.com/en-us/knowledgebase/article/000096610

Thanks,

Rohit Patil

Parents
  • 1) Yes of course.

    2) You can't output the 32.768 clock on a GPIO. What you can do is share an external 32.768kHz clock with both the MAX30003 and the nRF52840 by setting the BYPASS and EXTERNAL bits in the LFCLKSRC register. 

  • Hi,

    Thanks for the suggestion,

    I am stuck in max30003 and nrf52840 because of I unable to read ECG_FIFO register value. it's showing zero.

    (I try to  read INFO Register and other read register then  I got  default result as per max30003 datasheet ,surely my driver is working properly)

    I discussed this issue  on MAXIM Forum.

    maximsupport.microsoftcrmportals.com/.../000096610

    As per his suggestion,  if I  check crystal oscillator of max30003 working or not ?, But it's working.

    I got 32.768khz frequency on fclk pin of max30003.

    Let me know,

    1) is it any configuration required from nrf52840 side?

    I am generating 16khz frequency on gpio pin using RTC example,

    2) is it possible to generate 32.768khz using RTC? How to generate?

    Kindly help me,

    Thanks,

    Rohit

  • 32.000kHz is not a problem, just set up a TIMER or the PWM peripheral.

    32.768 is not possible: 

    (1/ 32.768 kHz) / (1/ 16MHz) = 488.2812501

    You'll be off by 0.2812501 * (1 / 16MHz) = 17.757813ns. 

    In Hz; 1/ ((1/ 32.768kHz) + 17.757813ns) = 32.74894378kHz

  • Hi ,

    I have generated almost closest frequency near of 32.7KHz using  PWM_Liabrary Example( PCA10056).

    But I unable to get same frequency when  I merge this code into Ble_app_uart.so please help me with this issues, please Find Attachment.

    void pwm_init()
    {
       ret_code_t err_code;
        /* 2-channel PWM, 200Hz, output on DK LED pins. */
        app_pwm_config_t pwm1_cfg = APP_PWM_DEFAULT_CONFIG_2CH(31L, ARDUINO_0_PIN, BSP_LED_1);
        /* Switch the polarity of the second channel. */
        pwm1_cfg.pin_polarity[1] = APP_PWM_POLARITY_ACTIVE_HIGH;
        /* Initialize and enable PWM. */
        err_code = app_pwm_init(&PWM1,&pwm1_cfg,pwm_ready_callback);
        APP_ERROR_CHECK(err_code);
        app_pwm_enable(&PWM1);
       
    
    //	  while (true)
        {
     for (uint8_t i = 0; i < 40; ++i)
            {
                value = (i < 20) ? (i * 5) : (100 - (i - 20) * 5);
                ready_flag = false;
                /* Set the duty cycle - keep trying until PWM is ready... */
                while (app_pwm_channel_duty_set(&PWM1, 0, value) == NRF_ERROR_BUSY);
                /* ... or wait for callback. */
                while (!ready_flag);
                APP_ERROR_CHECK(app_pwm_channel_duty_set(&PWM1, 1, value));
            }
    				
        }
    }
    
    int main(void)
    {
    	pwm_init();
        bool erase_bonds;
        uint32_t err_code;
        // Initialize.
        uart_init();
        log_init();
        timers_init();
        buttons_leds_init(&erase_bonds);
        power_management_init();
        ble_stack_init();
        gap_params_init();
        gatt_init();
        services_init();
        advertising_init();
        conn_params_init();
        APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    	  
    spi_config.frequency = NRF_SPIM_FREQ_125K;
    spi_config.ss_pin = NRFX_SPIM_SS_PIN;
    spi_config.miso_pin = NRFX_SPIM_MISO_PIN;
    spi_config.mosi_pin = NRFX_SPIM_MOSI_PIN;
    spi_config.sck_pin = NRFX_SPIM_SCK_PIN;
    //spi_config.dcx_pin = NRFX_SPIM_DCX_PIN;
    spi_config.use_hw_ss = true;
    spi_config.ss_active_high = false;
    spi_config.mode = NRF_SPIM_MODE_0; // SCK active high, sample on leading edge of clock, CPOL=0/CPHA=0
    spi_config.bit_order=NRF_SPIM_BIT_ORDER_MSB_FIRST; 
    spi_config.orc=0x00;
    APP_ERROR_CHECK(nrfx_spim_init(&spi, &spi_config, spim_event_handler, NULL));
    	NRF_LOG_INFO("NRFX SPIM example started.");
    	MAX30003_begin();
        // Start execution.
        printf("\r\nUART started.\r\n");
        NRF_LOG_INFO("Debug logging for UART over RTT started.");
        advertising_start();
    
    
        for (;;)
        {	
    			
    			  // Reset rx buffer and transfer done flag
             memset(m_rx_buf, 0, m_length);
             spi_xfer_done = false;
    			  	for(i=0;i<=200;i++)
    	        {
    						nrf_delay_ms(10);
                stored[i]=MAX30003_Reg_Read(ECG_FIFO); //0x0F 
                stored[i]=stored[i]>>8;	
    						
                valid_data[i] = (((uint8_t)stored[i])>>3)&0x07;
    						sprintf(ARRAY,"%d\n",  stored_status[i]);
    						printf(ARRAY);
    	        }
    			  err_code = ble_nus_data_send(&m_nus, ARRAY , &size, m_conn_handle);
            idle_state_handle();
    			  while (!spi_xfer_done)
    
    NRF_LOG_FLUSH();
    
        }
    	}

  • The SoftDevice has execution priority. You can use the Timeslot API to schedule periods of time where you are guaranteed not to be preemted by the SoftDevice.

  • You can use the Timeslot API to schedule periods of time where you are guaranteed not to be preemted by the SoftDevice.

    I have done following setting   https://devzone.nordicsemi.com/tutorials/b/software-development-kit/posts/setting-up-the-timeslot-api 

    In Timeslot API example I have replaced 

    #include "softdevice_handler.h"  to "nrf_sdh.h". as per below link 

    https://devzone.nordicsemi.com/f/nordic-q-a/33156/recent-timeslot-api-example

    But I unable to get the Output.so, let me know correct proceduere to follow this
    example and getting the correct output on GPIO PIN?

    As per our previous conversation is it possible to generate 32.7 or 32 kHz frequency on Any of GPIO Pin. 

    You can't output a 32.768 clock on a GPIO. What you can do is share an external 32.768kHz clock with both the MAX30003 and the nRF52840 by setting the BYPASS and EXTERNAL bits in the LFCLKSRC register. 

    Instead of PWM and Timeslot API, Is there any other example to use for frequency?

    I have generated almost closest frequency near of 32.7KHz using  PWM_Liabrary Example( PCA10056).

    But I unable to get same frequency when  I merge this code into Ble_app_uart


    why this code is not working?

    Thanks,

    Rohit

Reply Children
  • @haakonsh

    I got 32KHZ frequency on GPIO pin using GPIOTE example. But if I merge this code into my Ble_app_uart I am not getting the frequency. 

    I refer to this link 

    https://devzone.nordicsemi.com/f/nordic-q-a/26207/gpio-interrupt-not-work-in-ble_app_uart/103217#103217

    but I am not getting a clear solution, 

  • " But if I merge this code into my Ble_app_uart I am not getting the frequency. "

    I need more information on this issue.

  • I need more information on this issue.

    OK;

    I am working on one sensor which is required 32KHz clock frequency. so I generated 32KHz frequency on one of NRF GPIO Pin using GPIOTE example. 

    But I have to merge this code into Ble_app_uart, because of my plan to take sensor data using Bluetooth, so if I merge GPIOTE code (Which is already generated 32.0KHz Frequency) into BLE_APP_UART (SDK15.2.0- PCA10056-S140).

     But when I merge it with my working ble_app_uart code then GPIOTE stop working. it can't show 32.0KHz frequency, so please help me with these issues.

    please check my below code.

    Ble_App_Uart + GPIOTE

    
    /*Working ECG And RR Interval Code with Bluetooth and Pushing data on Server and Generating Interrupt (Timer) */
    
    #include <stdint.h>
    #include <string.h>
    #include "nordic_common.h"
    #include "nrf.h"
    #include "ble_hci.h"
    #include "ble_advdata.h"
    #include "ble_advertising.h"
    #include "ble_conn_params.h"
    #include "nrf_sdh.h"
    #include "nrf_sdh_soc.h"
    #include "nrf_sdh_ble.h"
    #include "nrf_ble_gatt.h"
    #include "nrf_ble_qwr.h"
    #include "app_timer.h"
    #include "ble_nus.h"
    #include "app_uart.h"
    #include "app_util_platform.h"
    #include "bsp_btn_ble.h"
    #include "nrf_pwr_mgmt.h"
    #include "nrfx_spi.h"
    #include "nrf_drv_spi.h"
    
    #include "nrfx_spim.h"
    #include "nrf_delay.h"
    #include "boards.h"
    #include "app_error.h"
    #include <string.h>
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    #include "stdio.h"
    //#include "app_uart.h"
    //#include "nrf_uart.h"
    #include <nrfx_ppi.h>
    
    
    #include <stdbool.h>
    #include <stdint.h>
    #include "nrf.h"
    #include "nrf_drv_timer.h"
    #include "bsp.h"
    #include "app_error.h"
    
    
    
    #include "nrf_gpiote.h"
    #include "nrf_gpio.h"
    #include "boards.h"
    #include "nrf_drv_ppi.h"
    #include "nrf_drv_gpiote.h"
    
    #if defined (UART_PRESENT)
    #include "nrf_uart.h"
    #endif
    #if defined (UARTE_PRESENT)
    #include "nrf_uarte.h"
    #endif
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    
    
    
    #define APP_BLE_CONN_CFG_TAG            1                                           /**< A tag identifying the SoftDevice BLE configuration. */
    
    #define DEVICE_NAME                     "ECG_BLE_Timer_RR"                               /**< Name of device. Will be included in the advertising data. */
    #define NUS_SERVICE_UUID_TYPE           BLE_UUID_TYPE_VENDOR_BEGIN                  /**< UUID type for the Nordic UART Service (vendor specific). */
    
    #define APP_BLE_OBSERVER_PRIO           3                                           /**< Application's BLE observer priority. You shouldn't need to modify this value. */
    
    #define APP_ADV_INTERVAL                64                                          /**< The advertising interval (in units of 0.625 ms. This value corresponds to 40 ms). */
    
    #define APP_ADV_DURATION                18000                                       /**< The advertising duration (180 seconds) in units of 10 milliseconds. */
    
    #define MIN_CONN_INTERVAL               MSEC_TO_UNITS(20, UNIT_1_25_MS)             /**< Minimum acceptable connection interval (20 ms), Connection interval uses 1.25 ms units. */
    #define MAX_CONN_INTERVAL               MSEC_TO_UNITS(75, UNIT_1_25_MS)             /**< Maximum acceptable connection interval (75 ms), Connection interval uses 1.25 ms units. */
    #define SLAVE_LATENCY                   0                                           /**< Slave latency. */
    #define CONN_SUP_TIMEOUT                MSEC_TO_UNITS(4000, UNIT_10_MS)             /**< Connection supervisory timeout (4 seconds), Supervision Timeout uses 10 ms units. */
    #define FIRST_CONN_PARAMS_UPDATE_DELAY  APP_TIMER_TICKS(5000)                       /**< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (5 seconds). */
    #define NEXT_CONN_PARAMS_UPDATE_DELAY   APP_TIMER_TICKS(30000)                      /**< Time between each call to sd_ble_gap_conn_param_update after the first call (30 seconds). */
    #define MAX_CONN_PARAMS_UPDATE_COUNT    3                                           /**< Number of attempts before giving up the connection parameter negotiation. */
    
    #define DEAD_BEEF                       0xDEADBEEF                                  /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */
    
    #define UART_TX_BUF_SIZE                256                                         /**< UART TX buffer size. */
    #define UART_RX_BUF_SIZE                256                                         /**< UART RX buffer size. */
    
    /**/
    #define SPI_SCK_PIN 3
    #define SPI_MISO_PIN 28
    #define SPI_MOSI_PIN 4
    #define SPI_SS_PIN 29
    
    #define   STATUS          0x01
    #define   EN_INT          0x02
    #define   EN_INT2         0x03
    #define   MNGR_INT        0x04
    #define   MNGR_DYN        0x05
    #define   SW_RST          0x08
    #define   SYNCH           0x09
    #define   FIFO_RST        0x0A
    #define   INFO            0x0F
    #define   CNFG_GEN        0x10
    #define   CNFG_CAL        0x12
    #define   CNFG_EMUX       0x14
    #define   CNFG_ECG        0x15
    #define   CNFG_RTOR1      0x1D
    #define   CNFG_RTOR2      0x1E
    #define   ECG_FIFO_BURST  0x20
    #define   ECG_FIFO        0x21
    #define   RTOR            0x25
    #define   NO_OP           0x7F
    #define SPI_INSTANCE  0 /**< SPI instance index. */
     const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE);  /**< SPI instance. */
     volatile bool spi_xfer_done;  /**< Flag used to indicate that SPI instance completed the transfer. */
     uint8_t       m_tx_buf[4] = {0x00, 0x00, 0x00, 0x00};           /**< TX buffer. */
     uint8_t       m_rx_buf[4];    /**< RX buffer. */
    static const uint8_t m_length = sizeof(m_tx_buf);        /**< Transfer length. */
     uint32_t datareturn1 = 0x00;
     uint32_t datareturn2 = 0x00;
     uint32_t RR_Interval = 0x00;
     uint32_t HR_Read = 0x00;
     
     const nrf_drv_timer_t TIMER_LED = NRF_DRV_TIMER_INSTANCE(2);
     uint32_t i=0;
     
        uint32_t err_code;
    	  uint8_t ARRAY[10];
        uint16_t size = 9;
     
        uint32_t err_code1;
        uint8_t ARRAY1[3];
        uint16_t size1 = 2;
     
        uint32_t HR;
        uint8_t ARRAY2[3];
        uint16_t size2 = 3;
    	
    #ifdef ARDUINO_1_PIN
        #define GPIO_OUTPUT_PIN_NUMBER ARDUINO_1_PIN  /**< Pin number for output. */
    #endif
    #ifndef GPIO_OUTPUT_PIN_NUMBER
        #error "Please indicate output pin"
    #endif
    
    static nrf_drv_timer_t timer = NRF_DRV_TIMER_INSTANCE(0);
    
    void timer_dummy_handler(nrf_timer_event_t event_type, void * p_context){}
    
    	
    
     void spi_event_handler(nrf_drv_spi_evt_t const * p_event,
                           void *                    p_context)
    {
        spi_xfer_done = true;
    //    NRF_LOG_INFO("Transfer completed.");
        if (m_rx_buf[0] != 0)
        {
    //        NRF_LOG_INFO(" Received:");
            NRF_LOG_HEXDUMP_INFO(m_rx_buf, strlen((const char *)m_rx_buf));
        }
    }
    /**/
    BLE_NUS_DEF(m_nus, NRF_SDH_BLE_TOTAL_LINK_COUNT);                                   /**< BLE NUS service instance. */
    NRF_BLE_GATT_DEF(m_gatt);                                                           /**< GATT module instance. */
    NRF_BLE_QWR_DEF(m_qwr);                                                             /**< Context for the Queued Write module.*/
    BLE_ADVERTISING_DEF(m_advertising);                                                 /**< Advertising module instance. */
    
    static uint16_t   m_conn_handle          = BLE_CONN_HANDLE_INVALID;                 /**< Handle of the current connection. */
    static uint16_t   m_ble_nus_max_data_len = BLE_GATT_ATT_MTU_DEFAULT - 3;            /**< Maximum length of data (in bytes) that can be transmitted to the peer by the Nordic UART service module. */
    static ble_uuid_t m_adv_uuids[]          =                                          /**< Universally unique service identifier. */
    {
        {BLE_UUID_NUS_SERVICE, NUS_SERVICE_UUID_TYPE}
    };
    
    
    /**@brief Function for assert macro callback.
     *
     * @details This function will be called in case of an assert in the SoftDevice.
     *
     * @warning This handler is an example only and does not fit a final product. You need to analyse
     *          how your product is supposed to react in case of Assert.
     * @warning On assert from the SoftDevice, the system can only recover on reset.
     *
     * @param[in] line_num    Line number of the failing ASSERT call.
     * @param[in] p_file_name File name of the failing ASSERT call.
     */
    void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
    {
        app_error_handler(DEAD_BEEF, line_num, p_file_name);
    }
    
    
    
     void led_blinking_setup()
    {
        uint32_t compare_evt_addr;
        uint32_t gpiote_task_addr;
        nrf_ppi_channel_t ppi_channel;
        ret_code_t err_code;
        nrf_drv_gpiote_out_config_t config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(false);
    
        err_code = nrf_drv_gpiote_out_init(GPIO_OUTPUT_PIN_NUMBER, &config);
        APP_ERROR_CHECK(err_code);
    
    
        nrf_drv_timer_extended_compare(&timer, (nrf_timer_cc_channel_t)0, 251, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);
    
        err_code = nrf_drv_ppi_channel_alloc(&ppi_channel);
        APP_ERROR_CHECK(err_code);
    
        compare_evt_addr = nrf_drv_timer_event_address_get(&timer, NRF_TIMER_EVENT_COMPARE0);
        gpiote_task_addr = nrf_drv_gpiote_out_task_addr_get(GPIO_OUTPUT_PIN_NUMBER);
    
        err_code = nrf_drv_ppi_channel_assign(ppi_channel, compare_evt_addr, gpiote_task_addr);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_ppi_channel_enable(ppi_channel);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_gpiote_out_task_enable(GPIO_OUTPUT_PIN_NUMBER);
    }
    void Frequency_init()
    {
    	 ret_code_t err_code;
    
        err_code = nrf_drv_ppi_init();
        APP_ERROR_CHECK(err_code);
    
    //    err_code = nrf_drv_gpiote_init();
    //    APP_ERROR_CHECK(err_code);
    
        nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
        err_code = nrf_drv_timer_init(&timer, &timer_cfg, timer_dummy_handler);
        APP_ERROR_CHECK(err_code);
    #ifdef NRF51
        //Workaround for PAN-73.
        *(uint32_t *)0x40008C0C = 1;
    #endif
    
        // Setup PPI channel with event from TIMER compare and task GPIOTE pin toggle.
        led_blinking_setup();
    
        // Enable timer
        nrf_drv_timer_enable(&timer);
    
    }
    static void timers_init(void)
    {
        ret_code_t err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for the GAP initialization.
     *
     * @details This function will set up all the necessary GAP (Generic Access Profile) parameters of
     *          the device. It also sets the permissions and appearance.
     */
    static void gap_params_init(void)
    {
        uint32_t                err_code;
        ble_gap_conn_params_t   gap_conn_params;
        ble_gap_conn_sec_mode_t sec_mode;
    
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
    
        err_code = sd_ble_gap_device_name_set(&sec_mode,
                                              (const uint8_t *) DEVICE_NAME,
                                              strlen(DEVICE_NAME));
        APP_ERROR_CHECK(err_code);
    
        memset(&gap_conn_params, 0, sizeof(gap_conn_params));
    
        gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
        gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
        gap_conn_params.slave_latency     = SLAVE_LATENCY;
        gap_conn_params.conn_sup_timeout  = CONN_SUP_TIMEOUT;
    
        err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling Queued Write Module errors.
     *
     * @details A pointer to this function will be passed to each service which may need to inform the
     *          application about an error.
     *
     * @param[in]   nrf_error   Error code containing information about what went wrong.
     */
    static void nrf_qwr_error_handler(uint32_t nrf_error)
    {
        APP_ERROR_HANDLER(nrf_error);
    }
    
    
    /**@brief Function for handling the data from the Nordic UART Service.
     *
     * @details This function will process the data received from the Nordic UART BLE Service and send
     *          it to the UART module.
     *
     * @param[in] p_evt       Nordic UART Service event.
     */
    /**@snippet [Handling the data received over BLE] */
    static void nus_data_handler(ble_nus_evt_t * p_evt)
    {
    
        if (p_evt->type == BLE_NUS_EVT_RX_DATA)
        {
            uint32_t err_code;
    
            NRF_LOG_DEBUG("Received data from BLE NUS. Writing data on UART.");
            NRF_LOG_HEXDUMP_DEBUG(p_evt->params.rx_data.p_data, p_evt->params.rx_data.length);
    
            for (uint32_t i = 0; i < p_evt->params.rx_data.length; i++)
            {
                do
                {
                    err_code = app_uart_put(p_evt->params.rx_data.p_data[i]);
                    if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_BUSY))
                    {
                        NRF_LOG_ERROR("Failed receiving NUS message. Error 0x%x. ", err_code);
                        APP_ERROR_CHECK(err_code);
                    }
                } while (err_code == NRF_ERROR_BUSY);
            }
            if (p_evt->params.rx_data.p_data[p_evt->params.rx_data.length - 1] == '\r')
            {
                while (app_uart_put('\n') == NRF_ERROR_BUSY);
            }
        }
    
    }
    /**@snippet [Handling the data received over BLE] */
    /**@brief Function for initializing services that will be used by the application.
     */
    static void services_init(void)
    {
        uint32_t           err_code;
        ble_nus_init_t     nus_init;
        nrf_ble_qwr_init_t qwr_init = {0};
    
        // Initialize Queued Write Module.
        qwr_init.error_handler = nrf_qwr_error_handler;
    
        err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);
        APP_ERROR_CHECK(err_code);
    
        // Initialize NUS.
        memset(&nus_init, 0, sizeof(nus_init));
    
        nus_init.data_handler = nus_data_handler;
    
        err_code = ble_nus_init(&m_nus, &nus_init);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling an event from the Connection Parameters Module.
     *
     * @details This function will be called for all events in the Connection Parameters Module
     *          which are passed to the application.
     *
     * @note All this function does is to disconnect. This could have been done by simply setting
     *       the disconnect_on_fail config parameter, but instead we use the event handler
     *       mechanism to demonstrate its use.
     *
     * @param[in] p_evt  Event received from the Connection Parameters Module.
     */
    static void on_conn_params_evt(ble_conn_params_evt_t * p_evt)
    {
        uint32_t err_code;
    
        if (p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED)
        {
            err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
            APP_ERROR_CHECK(err_code);
        }
    }
    
    
    /**@brief Function for handling errors from the Connection Parameters module.
     *
     * @param[in] nrf_error  Error code containing information about what went wrong.
     */
    static void conn_params_error_handler(uint32_t nrf_error)
    {
        APP_ERROR_HANDLER(nrf_error);
    }
    
    
    /**@brief Function for initializing the Connection Parameters module.
     */
    static void conn_params_init(void)
    {
        uint32_t               err_code;
        ble_conn_params_init_t cp_init;
    
        memset(&cp_init, 0, sizeof(cp_init));
    
        cp_init.p_conn_params                  = NULL;
        cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
        cp_init.next_conn_params_update_delay  = NEXT_CONN_PARAMS_UPDATE_DELAY;
        cp_init.max_conn_params_update_count   = MAX_CONN_PARAMS_UPDATE_COUNT;
        cp_init.start_on_notify_cccd_handle    = BLE_GATT_HANDLE_INVALID;
        cp_init.disconnect_on_fail             = false;
        cp_init.evt_handler                    = on_conn_params_evt;
        cp_init.error_handler                  = conn_params_error_handler;
    
        err_code = ble_conn_params_init(&cp_init);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for putting the chip into sleep mode.
     *
     * @note This function will not return.
     */
    static void sleep_mode_enter(void)
    {
        uint32_t err_code = bsp_indication_set(BSP_INDICATE_IDLE);
        APP_ERROR_CHECK(err_code);
    
        // Prepare wakeup buttons.
        err_code = bsp_btn_ble_sleep_mode_prepare();
        APP_ERROR_CHECK(err_code);
    
        // Go to system-off mode (this function will not return; wakeup will cause a reset).
        err_code = sd_power_system_off();
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling advertising events.
     *
     * @details This function will be called for advertising events which are passed to the application.
     *
     * @param[in] ble_adv_evt  Advertising event.
     */
    static void on_adv_evt(ble_adv_evt_t ble_adv_evt)
    {
        uint32_t err_code;
    
        switch (ble_adv_evt)
        {
            case BLE_ADV_EVT_FAST:
                err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
                APP_ERROR_CHECK(err_code);
                break;
            case BLE_ADV_EVT_IDLE:
                sleep_mode_enter();
                break;
            default:
                break;
        }
    }
    
    
    /**@brief Function for handling BLE events.
     *
     * @param[in]   p_ble_evt   Bluetooth stack event.
     * @param[in]   p_context   Unused.
     */
    static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
    {
        uint32_t err_code;
     uint32_t led_to_invert = 1; //((i++) % LED_1);
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GAP_EVT_CONNECTED:
    //					   bsp_board_led_invert(led_to_invert);
                err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
                APP_ERROR_CHECK(err_code);
                m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
                err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_GAP_EVT_DISCONNECTED:
    //            NRF_LOG_INFO("Disconnected");
                // LED indication will be changed when advertising starts.
                m_conn_handle = BLE_CONN_HANDLE_INVALID;
                break;
    
            case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
            {
                NRF_LOG_DEBUG("PHY update request.");
                ble_gap_phys_t const phys =
                {
                    .rx_phys = BLE_GAP_PHY_AUTO,
                    .tx_phys = BLE_GAP_PHY_AUTO,
                };
                err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
                APP_ERROR_CHECK(err_code);
            } break;
    
            case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
                // Pairing not supported
                err_code = sd_ble_gap_sec_params_reply(m_conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_GATTS_EVT_SYS_ATTR_MISSING:
                // No system attributes have been stored.
                err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0, 0);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_GATTC_EVT_TIMEOUT:
                // Disconnect on GATT Client timeout event.
                err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
                                                 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_GATTS_EVT_TIMEOUT:
                // Disconnect on GATT Server timeout event.
                err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle,
                                                 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                APP_ERROR_CHECK(err_code);
                break;
    
            default:
                // No implementation needed.
                break;
        }
    }
    
    /**@brief Function for the SoftDevice initialization.
     *
     * @details This function initializes the SoftDevice and the BLE event interrupt.
     */
    static void ble_stack_init(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_sdh_enable_request();
        APP_ERROR_CHECK(err_code);
    
        // Configure the BLE stack using the default settings.
        // Fetch the start address of the application RAM.
        uint32_t ram_start = 0;
        err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
        APP_ERROR_CHECK(err_code);
    
        // Enable BLE stack.
        err_code = nrf_sdh_ble_enable(&ram_start);
        APP_ERROR_CHECK(err_code);
    
        // Register a handler for BLE events.
        NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
    }
    
    
    /**@brief Function for handling events from the GATT library. */
    void gatt_evt_handler(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_t const * p_evt)
    {
        if ((m_conn_handle == p_evt->conn_handle) && (p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED))
        {
            m_ble_nus_max_data_len = p_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH;
    //        NRF_LOG_INFO("Data len is set to 0x%X(%d)", m_ble_nus_max_data_len, m_ble_nus_max_data_len);
        }
        NRF_LOG_DEBUG("ATT MTU exchange completed. central 0x%x peripheral 0x%x",
                      p_gatt->att_mtu_desired_central,
                      p_gatt->att_mtu_desired_periph);
    }
    
    
    /**@brief Function for initializing the GATT library. */
    void gatt_init(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_ble_gatt_init(&m_gatt, gatt_evt_handler);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_ble_gatt_att_mtu_periph_set(&m_gatt, NRF_SDH_BLE_GATT_MAX_MTU_SIZE);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling events from the BSP module.
     *
     * @param[in]   event   Event generated by button press.
     */
    void bsp_event_handler(bsp_event_t event)
    {
        uint32_t err_code;
        switch (event)
        {
            case BSP_EVENT_SLEEP:
                sleep_mode_enter();
                break;
    
            case BSP_EVENT_DISCONNECT:
                err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                if (err_code != NRF_ERROR_INVALID_STATE)
                {
                    APP_ERROR_CHECK(err_code);
                }
                break;
    
            case BSP_EVENT_WHITELIST_OFF:
                if (m_conn_handle == BLE_CONN_HANDLE_INVALID)
                {
                    err_code = ble_advertising_restart_without_whitelist(&m_advertising);
                    if (err_code != NRF_ERROR_INVALID_STATE)
                    {
                        APP_ERROR_CHECK(err_code);
                    }
                }
                break;
    
            default:
                break;
        }
    }
    
    
    /**@brief   Function for handling app_uart events.
     *
     * @details This function will receive a single character from the app_uart module and append it to
     *          a string. The string will be be sent over BLE when the last character received was a
     *          'new line' '\n' (hex 0x0A) or if the string has reached the maximum data length.
     */
    /**@snippet [Handling the data received over UART] */
    void uart_event_handle(app_uart_evt_t * p_event)
    {
        static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
        static uint8_t index = 0;
        uint32_t       err_code;
    
        switch (p_event->evt_type)
        {
            case APP_UART_DATA_READY:
                UNUSED_VARIABLE(app_uart_get(&data_array[index]));
                index++;
    
                if ((data_array[index - 1] == '\n') ||
                    (data_array[index - 1] == '\r') ||
                    (index >= m_ble_nus_max_data_len))
                {
                    if (index > 1)
                    {
                        NRF_LOG_DEBUG("Ready to send data over BLE NUS");
                        NRF_LOG_HEXDUMP_DEBUG(data_array, index);
    
                        do
                        {
                            uint16_t length = (uint16_t)index;
                            err_code = ble_nus_data_send(&m_nus, data_array, &length, m_conn_handle);
                            if ((err_code != NRF_ERROR_INVALID_STATE) &&
                                (err_code != NRF_ERROR_RESOURCES) &&
                                (err_code != NRF_ERROR_NOT_FOUND))
                            {
                                APP_ERROR_CHECK(err_code);
                            }
                        } while (err_code == NRF_ERROR_RESOURCES);
                    }
    
                    index = 0;
                }
                break;
    
            case APP_UART_COMMUNICATION_ERROR:
                APP_ERROR_HANDLER(p_event->data.error_communication);
                break;
    
            case APP_UART_FIFO_ERROR:
                APP_ERROR_HANDLER(p_event->data.error_code);
                break;
    
            default:
                break;
        }
    }
    /**@snippet [Handling the data received over UART] */
    
    /**@brief  Function for initializing the UART module.
     */
    /**@snippet [UART Initialization] */
    static void uart_init(void)
    {
        uint32_t                     err_code;
        app_uart_comm_params_t const comm_params =
        {
            .rx_pin_no    = RX_PIN_NUMBER,
            .tx_pin_no    = TX_PIN_NUMBER,
            .rts_pin_no   = RTS_PIN_NUMBER,
            .cts_pin_no   = CTS_PIN_NUMBER,
            .flow_control = APP_UART_FLOW_CONTROL_DISABLED,
            .use_parity   = false,
    #if defined (UART_PRESENT)
            .baud_rate    = NRF_UART_BAUDRATE_115200
    #else
            .baud_rate    = NRF_UARTE_BAUDRATE_115200
    #endif
        };
    
        APP_UART_FIFO_INIT(&comm_params,
                           UART_RX_BUF_SIZE,
                           UART_TX_BUF_SIZE,
                           uart_event_handle,
                           APP_IRQ_PRIORITY_LOWEST,
                           err_code);
        APP_ERROR_CHECK(err_code);
    }
    /**@snippet [UART Initialization] */
    
    /**@brief Function for initializing the Advertising functionality.
     */
    static void advertising_init(void)
    {
        uint32_t               err_code;
        ble_advertising_init_t init;
    
        memset(&init, 0, sizeof(init));
    
        init.advdata.name_type          = BLE_ADVDATA_FULL_NAME;
        init.advdata.include_appearance = false;
        init.advdata.flags              = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE;
    
        init.srdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
        init.srdata.uuids_complete.p_uuids  = m_adv_uuids;
    
        init.config.ble_adv_fast_enabled  = true;
        init.config.ble_adv_fast_interval = APP_ADV_INTERVAL;
        init.config.ble_adv_fast_timeout  = APP_ADV_DURATION;
        init.evt_handler = on_adv_evt;
    
        err_code = ble_advertising_init(&m_advertising, &init);
        APP_ERROR_CHECK(err_code);
    
        ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);
    }
    
    
    /**@brief Function for initializing buttons and leds.
     *
     * @param[out] p_erase_bonds  Will be true if the clear bonding button was pressed to wake the application up.
     */
    static void buttons_leds_init(bool * p_erase_bonds)
    {
        bsp_event_t startup_event;
    
        uint32_t err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_event_handler);
        APP_ERROR_CHECK(err_code);
    
        err_code = bsp_btn_ble_init(NULL, &startup_event);
        APP_ERROR_CHECK(err_code);
    
        *p_erase_bonds = (startup_event == BSP_EVENT_CLEAR_BONDING_DATA);
    }
    
    
    /**@brief Function for initializing the nrf log module.
     */
    static void log_init(void)
    {
        ret_code_t err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    
    /**@brief Function for initializing power management.
     */
    static void power_management_init(void)
    {
        ret_code_t err_code;
        err_code = nrf_pwr_mgmt_init();
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling the idle state (main loop).
     *
     * @details If there is no pending log operation, then sleep until next the next event occurs.
     */
    static void idle_state_handle(void)
    {
        UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
        nrf_pwr_mgmt_run();
    }
    
    
    /**@brief Function for starting advertising.
     */
    static void advertising_start(void)
    {
        uint32_t err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Application main function.
     */
    
    
    
    
     
    
    int main(void)
    {
        bool erase_bonds;
        uart_init();
        log_init();
    	  timers_init();
    //  buttons_leds_init(&erase_bonds);
        power_management_init();
        ble_stack_init();
        gap_params_init();
        gatt_init();
        services_init();
        advertising_init();
        conn_params_init();
        advertising_start();
    	  
        nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
        spi_config.ss_pin   = SPI_SS_PIN;       
        spi_config.miso_pin = SPI_MISO_PIN;
        spi_config.mosi_pin = SPI_MOSI_PIN;
        spi_config.sck_pin  = SPI_SCK_PIN;
        spi_config.frequency = NRF_SPI_FREQ_125K;
        spi_config.mode = NRF_SPI_MODE_0;
        APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL));
        Frequency_init();
        for (;;)
        {
    						
    	      idle_state_handle();
        }
    }
    

    GPIOTE- 32.0KHz

    #include <stdbool.h>
    #include <stdint.h>
    #include "nrf.h"
    #include "nrf_gpiote.h"
    #include "nrf_gpio.h"
    #include "boards.h"
    #include "nrf_drv_ppi.h"
    #include "nrf_drv_timer.h"
    #include "nrf_drv_gpiote.h"
    #include "app_error.h"
    
    #ifdef BSP_LED_0
        #define GPIO_OUTPUT_PIN_NUMBER BSP_LED_0  /**< Pin number for output. */
    #endif
    #ifndef GPIO_OUTPUT_PIN_NUMBER
        #error "Please indicate output pin"
    #endif
    
    static nrf_drv_timer_t timer = NRF_DRV_TIMER_INSTANCE(0);
    
    void timer_dummy_handler(nrf_timer_event_t event_type, void * p_context){}
    
    static void led_blinking_setup()
    {
        uint32_t compare_evt_addr;
        uint32_t gpiote_task_addr;
        nrf_ppi_channel_t ppi_channel;
        ret_code_t err_code;
        nrf_drv_gpiote_out_config_t config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(false);
    
        err_code = nrf_drv_gpiote_out_init(GPIO_OUTPUT_PIN_NUMBER, &config);
        APP_ERROR_CHECK(err_code);
    
    
        nrf_drv_timer_extended_compare(&timer, (nrf_timer_cc_channel_t)0, 251, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);
    
        err_code = nrf_drv_ppi_channel_alloc(&ppi_channel);
        APP_ERROR_CHECK(err_code);
    
        compare_evt_addr = nrf_drv_timer_event_address_get(&timer, NRF_TIMER_EVENT_COMPARE0);
        gpiote_task_addr = nrf_drv_gpiote_out_task_addr_get(GPIO_OUTPUT_PIN_NUMBER);
    
        err_code = nrf_drv_ppi_channel_assign(ppi_channel, compare_evt_addr, gpiote_task_addr);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_ppi_channel_enable(ppi_channel);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_gpiote_out_task_enable(GPIO_OUTPUT_PIN_NUMBER);
    }
    
    /**
     * @brief Function for application main entry.
     */
    int main(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_drv_ppi_init();
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_gpiote_init();
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
        err_code = nrf_drv_timer_init(&timer, &timer_cfg, timer_dummy_handler);
        APP_ERROR_CHECK(err_code);
    #ifdef NRF51
        //Workaround for PAN-73.
        *(uint32_t *)0x40008C0C = 1;
    #endif
    
        // Setup PPI channel with event from TIMER compare and task GPIOTE pin toggle.
        led_blinking_setup();
    
        // Enable timer
        nrf_drv_timer_enable(&timer);
    
        while (true)
        {
            // Do Nothing - GPIO can be toggled without software intervention.
        }
    }
    

  • static nrf_drv_timer_t timer = NRF_DRV_TIMER_INSTANCE(0); 

    TIMER0 is used by the SoftDevice, you need to use TIMER1 or above.

    See System On Chip Requirements: Hardware peripherals, from S132 spec. 

Related