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

nRF51822 SPI Slave Problem

Hi, For our current application we are using NRF51822, SDK 6.1, Soft device s110 ver 7.1.0. In our application nRF is configured as SPI Slave and another controller as SPI master. For this implementation I have considered example project “spi_slave”. As per implementation, whenever nRF is ready with data to transfer to controller, it first fills the DMA buffers and makes a GPIO pin High to interrupts the controller. SPI master (controller) will read the data from SPI port in ISR routine. I have observed that sometimes controller is reading default character clocked out from NRF. Here I am giving more explanation.

When nrf is ready with data, it fills the DMA Buffer.

error_code = spi_slave_buffers_set(m_tx_buf, m_rx_buf,(unp_updated_len+1), UNP_PACKET_MAX_SIZE);

semaphore_status = acquired;

in the spi interrupt routine I am enabling the GPIO pin high to give the interrupt to the controller

*/ void SPI1_TWI1_IRQHandler(void) {
// @note: as multiple events can be pending for processing, the correct event processing order // is as follows: // - SPI semaphore acquired event. // - SPI transaction complete event.

// Check for CPU semaphore acquired event.

	if (NRF_SPIS1->EVENTS_ACQUIRED != 0)
	{

	NRF_SPIS1->EVENTS_ACQUIRED = 0;
	//semaphore_status = acquired;
	/** SPI is not ready to receive and transmit data */
	NRF_SPIS1->DEF = NRF51_STATE_BUSY;

		switch (m_spi_state)
		{
		case SPI_BUFFER_RESOURCE_REQUESTED:
		NRF_SPIS1->TXDPTR = (uint32_t)mp_spi_tx_buf;
		NRF_SPIS1->RXDPTR = (uint32_t)mp_spi_rx_buf;
		NRF_SPIS1->MAXRX  = m_spi_rx_buf_size;
		NRF_SPIS1->MAXTX  = m_spi_tx_buf_size;

		NRF_SPIS1->TASKS_RELEASE = 1u;
		if(semaphore_status == acquired)
		{
			semaphore_status = released;
			nrf_gpio_pin_set(INTERRUPT_TO_STM);
	

		}

		//NRF_SPIS1->DEF = NRF51_STATE_RXDATA_AVAIL;
		NRF_SPIS1->DEF =NRF51_STATE_BUSY;
		/* release STM Interrupt */
	

		sm_state_change(SPI_BUFFER_RESOURCE_CONFIGURED);
		break;

		default:
		// No implementation required.
		break;
		}
	//}
}

// Check for SPI transaction complete event.
if (NRF_SPIS1->EVENTS_END != 0)
{
    NRF_SPIS1->EVENTS_END = 0;            


		/* Clear STM32 interrupt */
		//NRF_SPIS1->DEF = NRF51_STATE_TXDATA_ONLY;
		NRF_SPIS1->DEF = NRF51_STATE_BUSY;
    switch (m_spi_state)
    {
        case SPI_BUFFER_RESOURCE_CONFIGURED:                                  
            sm_state_change(SPI_XFER_COMPLETED);  
num_bytes_received= NRF_SPIS1->AMOUNTRX;
				
            break;

        default:
            // No implementation required.                    
            break;                
    }    
}

}

I am ensuring that by the time GPIO high (interrupt to the controller) hardware semaphore was released by CPU , and semaphore is available with SPI slave. Sometimes I am always reading the default character from slave. Could please comment on my implementation, if something is wrong. Regards, Raju

  • Hi Raju

    What I find suspicious is that you set the STM interrupt before calling sm_state_change. I am wondering what will happen if there is a higher priority interrupt happening before sm_state_change call has finished execution. I am not about how that would fail exactly but just want to point out my suspicion. What happens if you place the STM interrupt after the call to sm_state_change?

    Why do you not choose to use the spi_slave.c driver unmodified and instead set the STM interrupt in a registered spi_slave_event_handle, similar as done in the spi_slave_example? I would expect that to be safer.

    Update 9.7.2015 I would recommend to set your STM interrupt in the registered event handler, something like:

    static void spi_slave_event_handle(spi_slave_evt_t event)
    {
    		uint32_t err_code;
    		
    		if (event.evt_type == SPI_SLAVE_XFER_DONE)
    		{ 		
    				//Set buffers.
    				err_code = spi_slave_buffers_set(m_tx_buf, m_rx_buf, sizeof(m_tx_buf), sizeof(m_rx_buf));
    				APP_ERROR_CHECK(err_code);          
    		}
            if (event.evt_type == SPI_SLAVE_BUFFERS_SET_DONE)
            {
                    nrf_gpio_pin_set(INTERRUPT_TO_STM);
            }
    }
    

    where you register your handler as follows:

    err_code = spi_slave_evt_handler_register(spi_slave_event_handle);
    APP_ERROR_CHECK(err_code);  
    

    In a similar fashion as done in the spi_slave_example in the SDK.

  • if I configure nRF as SPI Slave how I can ensure that SPI master can have a valid data transfer ( Hardware Semaphore is available for SPI Operation)

  • Im sorry if my previous answer was confusing. I have updated it in my attempt to make it clearer what I mean. Let me know if it makes sense

Related