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

nRF51422 SPI disable/enable with softdevice

I have an issue with waking up SPI communication after sleep.

Befor I go to sleep I'm disabling SPI communication:

NRF_SPI0->ENABLE = 0;
NRF_SPI1->ENABLE = 0;

Handler function triggered by timer (which is responsible for wake-up) enabling SPI:

NRF_SPI0->ENABLE = 1;
NRF_SPI1->ENABLE = 1;

and send/receive data

err_code = nrf_drv_spi_transfer....

I'm getting err_code = 17 (NRF_ERROR_BUSY?) which causing reset.

When I remove commands:

NRF_SPI0->ENABLE = 0;
NRF_SPI1->ENABLE = 0;
NRF_SPI0->ENABLE = 1;
NRF_SPI1->ENABLE = 1;

SPI communication works fine, but current consumption is higher then expected during sleep

Should I disable SPI in different way?

Regards, Marcin

  • Hello Jorgen,

    I replaced:

    NRF_SPI0->ENABLE... 
    

    with

    nrf_drv_spi_init
    nrf_drv_spi_uninit
    

    accordingly

    Same result.

    Marcin

  • Can you upload your code, to show how SPI is init, transfer, going to sleep, etc.?

  • Hello Jorgen,

    My code is quite long and divided into a couple of files, but below are parts related to SPI and sleep. I suppose that it will be challenging to go through. I skipped some parts like variables definition and not related code... Briefly: I have 2 modules (ADC and gyro) connected to nRF51422, both work fine till the moment when go to sleep - go_sleep() function. Then I want to wake up gyro module and read current values. I'm not able to do it because communication causing reset (return code 17). Timer1_handler function is responsible for waking up.

            int main(void)
            {
            	ret_code_t err_code;
            		softdevice_setup();
                ant_channel_tx_broadcast_setup();
            		**spi_setup_adc();
            		spi_setup_gyro();**
                gpio_init();
            	
            		create_timers();
            		start_timer1(CHECK_TIME_WHEN_SLEEP);
            
            		// reset
            	  	ads1247_reset();
            		nrf_delay_ms(2); // 0.6 ms after reset
             		ads1247_set_reg_MUX1(2, 2, 0); // ON, but OFF when sleep
            		nrf_delay_ms(1);
            		// ADS1247 set register SYS0
            		// Gain: 1,2,4,8,16,32,64,128 SPS:5,10,20,40,80,160,320,640,1000,2000
            		ads1247_set_reg_SYS0(128, 160);
            		nrf_delay_ms(10);
            		// Self offset calibration
            		ads1247_selfocal();
            		nrf_delay_ms(10);
        
            		l3g4200d_set_register(CTRL_REG4, 0xE0);
            		nrf_delay_ms(10);
            		l3g4200d_set_register(CTRL_REG1, 0x7C);
            		
            		pwr_start_flag = true;
            		nrf_delay_ms(1);
              
            		for (;;)
            		{
            			// Calibration request
            			if (pwr_calib_request)
            				pwr_calib();
            
            			**if (cad0_counter>20) go_sleep();**
            			
            			// Put CPU in sleep if possible.			
            			err_code = sd_app_evt_wait();
                  APP_ERROR_CHECK(err_code);
            			nrf_delay_ms(10);
            	
            		}
        
            void spi_setup_gyro()
            {
            	  nrf_drv_spi_config_t const config_gyro =
                {
                    .sck_pin  		= SPIM1_SCK_PIN_GYRO,
                    .mosi_pin 		= SPIM1_MOSI_PIN_GYRO,
                    .miso_pin 		= SPIM1_MISO_PIN_GYRO,
                    .ss_pin   		= SPIM1_SS_PIN_GYRO,
                    .irq_priority = APP_IRQ_PRIORITY_LOW,
            				.orc          = 0xFF,
                    .frequency    = NRF_DRV_SPI_FREQ_1M,
                    .mode         = NRF_DRV_SPI_MODE_3,
                    .bit_order    = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST,
                };
                ret_code_t err_code = nrf_drv_spi_init(&m_spi_master_gyro, &config_gyro, spi_master_event_handler_gyro);
            		APP_ERROR_CHECK(err_code);
            	}
    
    void spi_unsetup_gyro()
    {
        nrf_drv_spi_uninit(&m_spi_master_gyro);
    }
        
        
            void l3g4200d_read_register(uint8_t reg, uint8_t len)
            {
            		m_tx_data_gyro[0] = 192 + reg;
            		spi_send_recv_gyro(m_tx_data_gyro, m_rx_data_gyro, SPI_BUF_LEN1, len+1);
            		int i;  
        // Temporary for error analyzing		
            		for (i = 0; i < len; i++)
                {
            				SEGGER_RTT_WriteString(0, "\nGyro register ");
            				sprintf(RTT_terminal_str, "%i", reg+i);
            				SEGGER_RTT_WriteString(0, RTT_terminal_str);
            				SEGGER_RTT_WriteString(0, " : ");
            				sprintf(RTT_terminal_str, "%i", m_rx_data_gyro[i+1]);
            				SEGGER_RTT_WriteString(0, RTT_terminal_str);
                    }
                }
        
        
        static void spi_send_recv_gyro(uint8_t * const p_tx_data,
                                  uint8_t * const p_rx_data,
                                  const uint16_t  len_tx,
        													const uint16_t  len_rx)
        {	
            uint32_t err_code = nrf_drv_spi_transfer(&m_spi_master_gyro,
                p_tx_data, len_tx, p_rx_data, len_rx);
        		APP_ERROR_CHECK(err_code);
        }
    
    
    void go_sleep()
    {
    ret_code_t err_code;	
    		// Sleep
    			cad0_counter = 0;
    			// ------ Close ANT channel
    				err_code = sd_ant_channel_close(BPWR_CHANNEL_NUMBER);
    				APP_ERROR_CHECK(err_code);
    				nrf_delay_ms(1);
    			// ------ Stop counting
    				pwr_start_flag = false;
    			// ------ Power down ADC
    				nrf_drv_gpiote_out_clear(START_PIN_ADC); //Power down
    				nrf_delay_ms(1);
    				//NRF_SPI0->ENABLE = 0;
    				spi_unsetup_adc();
    			// ------ Power down Gyro			
    				l3g4200d_set_register(CTRL_REG1, 0x70); //Power down
    				nrf_delay_ms(1);
    				//NRF_SPI1->ENABLE = 0;
    				spi_unsetup_gyro();
    				nrf_drv_gpiote_out_set(SPIM1_MOSI_PIN_GYRO); // Pull up MOSI to save power ~300uA
    			// ------ Set sleep flag
    				sleep_flag = true;
    }
    
    
    static void timer1_handler(void * p_context)
    {
    int32_t l_gyro_val = 0;
    	
    	nrf_drv_gpiote_out_toggle(LED_PIN);
    		if(sleep_flag)
    		{
    			//Wake up gyro for a while and check
    				//NRF_SPI1->ENABLE = 1;
    				spi_setup_gyro();
    				nrf_delay_ms(1);
    				l3g4200d_read_register(CTRL_REG1, 1);  // Reading data causing the issue (reset) !!!
    				//l3g4200d_set_register(CTRL_REG1, 0x7C); //Power up
    				nrf_delay_ms(1);
    				//NRF_SPI1->ENABLE = 0;
    				spi_unsetup_gyro();
    		}
    		else
    		{
    			// do nothing
    		}
    }
    
  • It may be that the SPI interface is not successfully disabled before you go to sleep. Can you try to wait for the bit to be set, before going to sleep:

    while(NRF_SPI0->ENABLE != 0)
    {
        nrf_drv_spi_uninit(&spi);
    }
    

    Or check if it is set before enabling the SPI interface on wakeup:

    if(NRF_SPI0->ENABLED == 0)
    {
       nrf_drv_spi_init(&spi, &spi_config, spi_event_handler)
    }
    
Related