<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="https://devzone.nordicsemi.com/cfs-file/__key/system/syndication/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>SPI Slave Comms using byte count (eg Rx buffer full) rather CSN (Chip Select) to indicate end of SPI transaction)</title><link>https://devzone.nordicsemi.com/f/nordic-q-a/41249/spi-slave-comms-using-byte-count-eg-rx-buffer-full-rather-csn-chip-select-to-indicate-end-of-spi-transaction</link><description>Hi 
 My SPI Master wraps SPI comms using a couple of additional logic lines nReadFromSlave (Master Output) and nSlaveReady (Master Input). 
 It treats an SPI transaction as a Write (of 8 bytes), followed by a read of the ACK/NAK response which is a single</description><dc:language>en-US</dc:language><generator>Telligent Community 13</generator><lastBuildDate>Thu, 13 Dec 2018 11:11:37 GMT</lastBuildDate><atom:link rel="self" type="application/rss+xml" href="https://devzone.nordicsemi.com/f/nordic-q-a/41249/spi-slave-comms-using-byte-count-eg-rx-buffer-full-rather-csn-chip-select-to-indicate-end-of-spi-transaction" /><item><title>RE: SPI Slave Comms using byte count (eg Rx buffer full) rather CSN (Chip Select) to indicate end of SPI transaction)</title><link>https://devzone.nordicsemi.com/thread/161642?ContentTypeID=1</link><pubDate>Thu, 13 Dec 2018 11:11:37 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:40654688-2621-4f9e-90ea-f8181469d88b</guid><dc:creator>veletron</dc:creator><description>&lt;p&gt;Appears I was premature on thinking this was &amp;#39;solved&amp;#39; although the data Rx is signalled complete&amp;nbsp; via ENDRX, it is not possible to start a new transaction (eg to respond to the master with ACK/NAK) until CS has been de-asserted and then re-asserted (which causes an END event). Basically, the SPIS pheriperal hogs the semaphore until CS toggle is seen. I believe that this is hardwired in the MCU.&lt;/p&gt;
&lt;p&gt;Actively requesting the semaphore from my own code (after the initial ENDRX has been seen) using the code below does not work.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;nrf_spis_semstat_t semstat = nrf_spis_semaphore_status_get (spis.p_reg);
NRF_LOG_INFO(&amp;quot;Semstat B4 NRF_SPIS_TASK_ACQUIRE: %d&amp;quot;,semstat);
nrf_spis_task_trigger(spis.p_reg, NRF_SPIS_TASK_ACQUIRE);
while (1)
{
                semstat = nrf_spis_semaphore_status_get (spis.p_reg);
                NRF_LOG_INFO(&amp;quot;Semstat In While(1) Loop: %d&amp;quot;,semstat);
                if (semstat == NRF_SPIS_SEMSTAT_CPU)
                                break;
                                                                
                nrf_delay_ms(1000);
}
                                
NRF_LOG_INFO(&amp;quot;Semstat On While Loop Exit: %d&amp;quot;,semstat);

typedef enum
{
    NRF_SPIS_SEMSTAT_FREE       = 0, ///&amp;lt; Semaphore is free.
    NRF_SPIS_SEMSTAT_CPU        = 1, ///&amp;lt; Semaphore is assigned to the CPU.
    NRF_SPIS_SEMSTAT_SPIS       = 2, ///&amp;lt; Semaphore is assigned to the SPI slave.
    NRF_SPIS_SEMSTAT_CPUPENDING = 3  ///&amp;lt; Semaphore is assigned to the SPI, but a handover to the CPU is pending.
} nrf_spis_semstat_t;

&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The log output from the above is below. The semaphore request is registered (state changes to 3), but CPU does not get handed the semaphore until I manually trigger a CS toggle on the master:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="text"&gt;&amp;lt;info&amp;gt; app: Started Proteus-Murata Main Application
&amp;lt;info&amp;gt; app: Entered WaitForNextSpiMessage
&amp;lt;info&amp;gt; app: ENDRX --&amp;gt; Rx Byte Count: 8
&amp;lt;info&amp;gt; app: ENDRX --&amp;gt; Tx Byte Count: 0
&amp;lt;info&amp;gt; app: Rx Transfer Done - preparing ACK
&amp;lt;info&amp;gt; app: Semstat B4 NRF_SPIS_TASK_ACQUIRE: 2       The semstat content before entering the while loop SPIS owns semaphore
&amp;lt;info&amp;gt; app: Semstat In While(1) Loop: 3                                   Semstat content in the while loop – this is repeated forever  status:     NRF_SPIS_SEMSTAT_CPUPENDING
&amp;lt;info&amp;gt; app: Semstat In While(1) Loop: 3
&amp;lt;info&amp;gt; app: Semstat In While(1) Loop: 3
&amp;lt;info&amp;gt; app: Semstat In While(1) Loop: 3
&amp;lt;info&amp;gt; app: Semstat In While(1) Loop: 3
&amp;lt;info&amp;gt; app: Semstat In While(1) Loop: 3
&amp;lt;info&amp;gt; app: Semstat In While(1) Loop: 3
&amp;lt;info&amp;gt; app: Semstat In While(1) Loop: 3
&amp;lt;info&amp;gt; app: Semstat In While(1) Loop: 3
&amp;lt;info&amp;gt; app: Semstat In While(1) Loop: 3
&amp;lt;info&amp;gt; app: Semstat In While(1) Loop: 3
&amp;lt;info&amp;gt; app: Semstat In While(1) Loop: 3
&amp;lt;info&amp;gt; app: Semstat In While(1) Loop: 3
&amp;lt;info&amp;gt; app: Semstat In While(1) Loop: 3
&amp;lt;info&amp;gt; app: Semstat In While(1) Loop: 3
&amp;lt;info&amp;gt; app: Semstat In While(1) Loop: 3
&amp;lt;info&amp;gt; app: Semstat In While(1) Loop: 3
&amp;lt;info&amp;gt; app: Semstat In While(1) Loop: 3
&amp;lt;info&amp;gt; app: Semstat In While(1) Loop: 3
&amp;lt;info&amp;gt; app: Semstat In While(1) Loop: 3
&amp;lt;info&amp;gt; app: Semstat In While(1) Loop: 3
&amp;lt;info&amp;gt; app: Semstat In While(1) Loop: 3
&amp;lt;info&amp;gt; app: Semstat In While(1) Loop: 1                                  Here, I manually de-assert CS on the master, this instantly hands the Semaphore to the CPU
&amp;lt;info&amp;gt; app: Semstat On While Loop Exit: 1                            
&amp;lt;info&amp;gt; SPIS: Rx Max Cnt: 8 | Tx Max Cnt: 1
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Going to have to find another way - eg re-write the SPIS driver. NB: this will need to be done on the registers, not using the SPIS HAL as the HAL functions appear to use the hardware SPIS semaphore as well. I will need to implement my own guard around EASYDMA - which appears to be the only mechanism to get data to/from SPIS.&lt;/p&gt;
&lt;p&gt;Nigel&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SPI Slave Comms using byte count (eg Rx buffer full) rather CSN (Chip Select) to indicate end of SPI transaction)</title><link>https://devzone.nordicsemi.com/thread/160556?ContentTypeID=1</link><pubDate>Thu, 06 Dec 2018 11:35:23 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:508d2396-d022-4390-acda-fce3a9a7d07d</guid><dc:creator>veletron</dc:creator><description>&lt;p&gt;Hi&lt;/p&gt;
&lt;p&gt;To add to this, you&amp;#39;ll get funny results if the interrupts for both&amp;nbsp;&lt;span&gt;NRF_SPIS_INT_END_MASK&amp;nbsp; and&amp;nbsp;NRF_SPIS_INT_ENDRX_MASK are enabled via the following in the API code above.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;// Enable IRQ.&lt;br /&gt; nrf_spis_int_enable(p_spis, NRF_SPIS_INT_ACQUIRED_MASK |&lt;br /&gt; NRF_SPIS_INT_END_MASK | NRF_SPIS_INT_ENDRX_MASK);&lt;/p&gt;
&lt;p&gt;Where both are enabled, Callbacks&amp;nbsp;to your SPIS Handler wont happen properly - in my experience, behaviour is a bit random if they are both enabled. I suspect that the enumerated types that these signal through the layers eg:&lt;/p&gt;
&lt;p&gt;NRF_DRV_SPIS_XFER_DONE&lt;/p&gt;
&lt;p&gt;NRFX_SPIS_XFER_DONE&lt;/p&gt;
&lt;p&gt;SPIS_XFER_COMPLETED&lt;/p&gt;
&lt;p&gt;NRF_SPIS_EVENT_END&lt;/p&gt;
&lt;p&gt;would need to become bitmasks at each code layer so that the callback gets all the reasons for end of transaction delivered at the same time?&lt;/p&gt;
&lt;p&gt;I will just mod&amp;nbsp;nrf_drv_spis_init so that the accepted interrupt sources can be passed in. With&amp;nbsp;&lt;span&gt;NRF_SPIS_INT_END_MASK&amp;nbsp; disabled, ENDRX will work alone, and the driving CS line can be tied high permanently, the SPIS config does not accept&amp;nbsp;NRF_SPIS_PIN_NOT_CONNECTED which is a pain because the SPIM config does via&amp;nbsp;NRF_DRV_SPI_PIN_NOT_USED.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Nigel&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SPI Slave Comms using byte count (eg Rx buffer full) rather CSN (Chip Select) to indicate end of SPI transaction)</title><link>https://devzone.nordicsemi.com/thread/160410?ContentTypeID=1</link><pubDate>Wed, 05 Dec 2018 14:29:38 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:f0bcc25b-d47d-4a32-9ffb-705aebfd5296</guid><dc:creator>veletron</dc:creator><description>&lt;p&gt;Hi&lt;/p&gt;
&lt;p&gt;Got this working - the issue is that Nordic don&amp;#39;t provide a means to propagate the ENDRX signal back to the upper layers. Perhaps Nordic can implement these changes in a future SDK?&lt;/p&gt;
&lt;p&gt;If you search for EVENTS_ENDRX you&amp;#39;ll find it present in nrf52.h for UARTE, SPIM, SPIS and NFCT.&lt;/p&gt;
&lt;p&gt;Apart from UARTE, it is not propigated upwards through the SDK Layers, some SDK-hacking fixes this (NB Don&amp;#39;t hack the SDK - shift the code into your project level!)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SDK15_2_0_9412b96\nRF5_SDK\modules\nrfx\hal\nrf_spis.h&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;/**
 * @brief SPIS events.
 */
typedef enum
{
    /*lint -save -e30*/
    NRF_SPIS_EVENT_END      = offsetof(NRF_SPIS_Type, EVENTS_END),     ///&amp;lt; Granted transaction completed.
    NRF_SPIS_EVENT_ACQUIRED = offsetof(NRF_SPIS_Type, EVENTS_ACQUIRED), ///&amp;lt; Semaphore acquired.
	NRF_SPIS_EVENT_ENDRX = offsetof(NRF_SPIS_Type,EVENTS_ENDRX)   ///&amp;lt; ENDRX completed
    /*lint -restore*/
} nrf_spis_event_t;

/**
 * @brief SPIS interrupts.
 */
typedef enum
{
    NRF_SPIS_INT_END_MASK      = SPIS_INTENSET_END_Msk,     ///&amp;lt; Interrupt on END event.
    NRF_SPIS_INT_ACQUIRED_MASK = SPIS_INTENSET_ACQUIRED_Msk, ///&amp;lt; Interrupt on ACQUIRED event.
		NRF_SPIS_INT_ENDRX_MASK = SPIS_INTENSET_ENDRX_Msk    ///&amp;lt; Interrupt on ENDRX event
	
} nrf_spis_int_mask_t;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SDK15_2_0_9412b96\nRF5_SDK\modules\nrfx\drivers\include\nrfx_spis.h&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;/** @brief SPI slave driver event types. */
typedef enum
{
    NRFX_SPIS_BUFFERS_SET_DONE, //!&amp;lt; Memory buffer set event. Memory buffers have been set successfully to the SPI slave device, and SPI transaction can be done.
    NRFX_SPIS_XFER_DONE,        //!&amp;lt; SPI transaction event. SPI transaction has been completed.
		NRFX_SPIS_ENDRX_DONE,   //!&amp;lt; SPI Transation event. SPI transaction completed - expected no of bytes recieved via ENDRX event
    NRFX_SPIS_EVT_TYPE_MAX      //!&amp;lt; Enumeration upper bound.
} nrfx_spis_evt_type_t;&lt;/pre&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SDK15_2_0_9412b96\nRF5_SDK\modules\nrfx\drivers\src\nrfx_spis.c&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;//Needs sorting!
#define EVT_TO_STR(event)                                           \
    (event == NRF_SPIS_EVENT_ACQUIRED ? &amp;quot;NRF_SPIS_EVENT_ACQUIRED&amp;quot; : \
    (event == NRF_SPIS_EVENT_END      ? &amp;quot;NRF_SPIS_EVENT_END&amp;quot;      : \
                                     &amp;quot;UNKNOWN ERROR - prob ENDRX&amp;quot;))
                                     

/**@brief States of the SPI transaction state machine. */
typedef enum
{
    SPIS_STATE_INIT,                                 /**&amp;lt; Initialization state. In this state the module waits for a call to @ref spi_slave_buffers_set. */
    SPIS_BUFFER_RESOURCE_REQUESTED,                  /**&amp;lt; State where the configuration of the memory buffers, which are to be used in SPI transaction, has started. */
    SPIS_BUFFER_RESOURCE_CONFIGURED,                 /**&amp;lt; State where the configuration of the memory buffers, which are to be used in SPI transaction, has completed. */
    SPIS_XFER_COMPLETED,
    SPIS_ENDRX_COMPLETED
	/**&amp;lt; State where SPI transaction has been completed. */
} nrfx_spis_state_t;

//--------------------------

// Clear possible pending events.
    nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_END);
	nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_ENDRX);
    nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_ACQUIRED);

//---------------------------

// Enable IRQ.
    nrf_spis_int_enable(p_spis, NRF_SPIS_INT_ACQUIRED_MASK |
                                NRF_SPIS_INT_END_MASK | NRF_SPIS_INT_ENDRX_MASK);
                 
    //-----------------------------
                 
                                
	case SPIS_ENDRX_COMPLETED:  //todo nmw remove SDK hack

						event.evt_type  = NRFX_SPIS_ENDRX_DONE;
            event.rx_amount = nrf_spis_rx_amount_get(p_spis);
            event.tx_amount = nrf_spis_tx_amount_get(p_spis);
            NRFX_LOG_INFO(&amp;quot;Transfer rx_len:%d.&amp;quot;, event.rx_amount);
            NRFX_LOG_DEBUG(&amp;quot;Rx data:&amp;quot;);
            NRFX_LOG_HEXDUMP_DEBUG((uint8_t const *)p_cb-&amp;gt;rx_buffer,
                                   event.rx_amount * sizeof(p_cb-&amp;gt;rx_buffer[0]));
            NRFX_ASSERT(p_cb-&amp;gt;handler != NULL);
            p_cb-&amp;gt;handler(&amp;amp;event, p_cb-&amp;gt;p_context);
            break;
            
    //------------------------------
    
    switch (p_cb-&amp;gt;spi_state)
    {
        case SPIS_STATE_INIT:
        case SPIS_XFER_COMPLETED:
	    case SPIS_ENDRX_COMPLETED:    
        case SPIS_BUFFER_RESOURCE_CONFIGURED:
            p_cb-&amp;gt;tx_buffer      = p_tx_buffer;
            p_cb-&amp;gt;rx_buffer      = p_rx_buffer;
            p_cb-&amp;gt;tx_buffer_size = tx_buffer_length;
            p_cb-&amp;gt;rx_buffer_size = rx_buffer_length;
            err_code             = NRFX_SUCCESS;

            spis_state_change(p_instance-&amp;gt;p_reg, p_cb, SPIS_BUFFER_RESOURCE_REQUESTED);
            break;

        case SPIS_BUFFER_RESOURCE_REQUESTED:
            err_code = NRFX_ERROR_INVALID_STATE;
            break;

        default:
            // @note: execution of this code path would imply internal error in the design.
            err_code = NRFX_ERROR_INTERNAL;
            break;
    }
    
    //----------------------------------
    
    //duplicate block above for ENDRX event
    
    // Check for SPI transaction complete event (via ENDRX).
    if (nrf_spis_event_check(p_spis, NRF_SPIS_EVENT_ENDRX))
    {
        nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_ENDRX);
        NRFX_LOG_DEBUG(&amp;quot;SPIS: Event: %s.&amp;quot;, EVT_TO_STR(NRF_SPIS_EVENT_ENDRX));

        switch (p_cb-&amp;gt;spi_state)
        {
            case SPIS_BUFFER_RESOURCE_CONFIGURED:
                spis_state_change(p_spis, p_cb, SPIS_ENDRX_COMPLETED);
                break;

            default:
                // No implementation required.
                break;
        }
    }
    
    
    &lt;/pre&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SDK15_2_0_9412b96\nRF5_SDK\integration\nrfx\legacy\nrf_drv_spis.h&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;#define NRF_DRV_SPIS_BUFFERS_SET_DONE       NRFX_SPIS_BUFFERS_SET_DONE
/** @brief Macro for forwarding the new implementation. */
#define NRF_DRV_SPIS_XFER_DONE              NRFX_SPIS_XFER_DONE
/** @brief Macro for forwarding the new implementation. */
#define NRF_DRV_SPIS_ENDRX_DONE              NRFX_SPIS_ENDRX_DONE&lt;/pre&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;And then in your own SPI Event Handler callback...&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;void spis_read_event_handler(nrf_drv_spis_event_t event)
{
		if (event.evt_type == NRF_DRV_SPIS_ENDRX_DONE)
		{
			if (event.rx_amount &amp;gt; 0)
			{
					NRF_LOG_INFO(&amp;quot;ENDRX --&amp;gt; Rx Byte Count: %d&amp;quot;,event.rx_amount);
					spis_xfer_rx_done = true;
					return;
			}
		}
	
		if (event.evt_type == NRF_DRV_SPIS_XFER_DONE)
        {
			//Detect rx/tx - we should not get both at the same time
			if (event.rx_amount &amp;gt; 0 &amp;amp;&amp;amp; event.tx_amount &amp;gt; 0)
			{
				NRF_LOG_INFO(&amp;quot;Error - simultanious Rx and Tx | Rx Count: %d | Tx Count: %d&amp;quot;,event.rx_amount,event.tx_amount);
				return;
			}
			
			if (event.rx_amount &amp;gt; 0)
			{
				NRF_LOG_INFO(&amp;quot;Rx Byte Count: %d&amp;quot;,event.rx_amount);
				spis_xfer_rx_done = true;
					return;
			}
					
			//If we get here it was as a result of having completed an SPI Tx (for the ACK/NAK
			NRF_LOG_INFO(&amp;quot;Tx Byte Count: %d&amp;quot;,event.tx_amount);
				
			if (event.tx_amount &amp;gt; 0)
			{
				NRF_LOG_INFO(&amp;quot;Tx Byte Count: %d&amp;quot;,event.tx_amount);
				spis_xfer_tx_done = true;
				return;
			}
    }
}&lt;/pre&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item></channel></rss>