<?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>How to do SPIM with handshakes</title><link>https://devzone.nordicsemi.com/f/nordic-q-a/117144/how-to-do-spim-with-handshakes</link><description>I&amp;#39;m using SDK15.3 on an nRF52840 with FreeRTOS and specifically non-preemptive scheduling. 
 I want to so some transfers on SPIM (it&amp;#39;s configure with DMA but that&amp;#39;s not a requirement)... I&amp;#39;ve got a part I&amp;#39;m talking to that has a READY handshake signal</description><dc:language>en-US</dc:language><generator>Telligent Community 13</generator><lastBuildDate>Wed, 08 Jan 2025 21:11:26 GMT</lastBuildDate><atom:link rel="self" type="application/rss+xml" href="https://devzone.nordicsemi.com/f/nordic-q-a/117144/how-to-do-spim-with-handshakes" /><item><title>RE: How to do SPIM with handshakes</title><link>https://devzone.nordicsemi.com/thread/517554?ContentTypeID=1</link><pubDate>Wed, 08 Jan 2025 21:11:26 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:bf936536-7fef-46a7-a320-80196ef8c88c</guid><dc:creator>hmolesworth</dc:creator><description>&lt;p&gt;Don&amp;#39;t need toggle. The trick is to know the a single pin can be input to (but not output from) several GPIOTE channels. This works, I tested it on some other stuff.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;#define PIN_SPIM_XON_XOFF  14
#define PPI_SPIM_SUSPEND    0
#define PPI_SPIM_RESUME     1
#define GPIOTE_SPIM_SUSPEND 0
#define GPIOTE_SPIM_RESUME  1

static void TestPPI_SPIM_SuspendResume(void)
{
    NRF_P0-&amp;gt;OUTCLR = (1 &amp;lt;&amp;lt; PIN_SPIM_XON_XOFF);
    // Configuration                       Direction    Input            Pullup         Drive Level      Sense Level
    // ================================    ==========   ==============   ============   ==============   =============
    NRF_P0-&amp;gt;PIN_CNF[PIN_SPIM_XON_XOFF]  = (PIN_INPUT  | PIN_CONNECT    | PIN_PULLNONE | PIN_DRIVE_H0H1 | PIN_SENSE_LOW);

    // Configure input for resume on rising edge with suspend on falling edge
    NRF_GPIOTE-&amp;gt;CONFIG[GPIOTE_SPIM_RESUME]  = GPIOTE_CONFIG_MODE_Event      &amp;lt;&amp;lt; GPIOTE_CONFIG_MODE_Pos     |
                                              GPIOTE_CONFIG_POLARITY_LoToHi &amp;lt;&amp;lt; GPIOTE_CONFIG_POLARITY_Pos |
                                              PIN_SPIM_XON_XOFF             &amp;lt;&amp;lt; GPIOTE_CONFIG_PSEL_Pos     |
                                              GPIOTE_CONFIG_OUTINIT_Low     &amp;lt;&amp;lt; GPIOTE_CONFIG_OUTINIT_Pos;
    NRF_GPIOTE-&amp;gt;CONFIG[GPIOTE_SPIM_SUSPEND] = GPIOTE_CONFIG_MODE_Event      &amp;lt;&amp;lt; GPIOTE_CONFIG_MODE_Pos     |
                                              GPIOTE_CONFIG_POLARITY_HiToLo &amp;lt;&amp;lt; GPIOTE_CONFIG_POLARITY_Pos |
                                              PIN_SPIM_XON_XOFF             &amp;lt;&amp;lt; GPIOTE_CONFIG_PSEL_Pos     |
                                              GPIOTE_CONFIG_OUTINIT_Low     &amp;lt;&amp;lt; GPIOTE_CONFIG_OUTINIT_Pos;

    // Resume SPIM transfer on rising edge of pulse via PPI
    NRF_PPI-&amp;gt;CH[PPI_SPIM_RESUME].EEP = (uint32_t)&amp;amp;NRF_GPIOTE-&amp;gt;EVENTS_IN[GPIOTE_CHANNEL_B];
    NRF_PPI-&amp;gt;CH[PPI_SPIM_RESUME].TEP = (uint32_t)&amp;amp;NRF_SPIM0-&amp;gt;TASKS_RESUME;

    // Suspend SPIM transfer on falling edge via PPI
    NRF_PPI-&amp;gt;CH[PPI_SPIM_SUSPEND].EEP = (uint32_t)&amp;amp;NRF_GPIOTE-&amp;gt;EVENTS_IN[GPIOTE_CHANNEL_A]; // Event
    NRF_PPI-&amp;gt;CH[PPI_SPIM_SUSPEND].TEP = (uint32_t)&amp;amp;NRF_SPIM0-&amp;gt;TASKS_SUSPEND;                // Task #1
    // Let&amp;#39;s add an EGU interrupt to play with
    NRF_PPI-&amp;gt;FORK[PPI_SPIM_SUSPEND].TEP = (uint32_t)&amp;amp;NRF_EGU0-&amp;gt;TASKS_TRIGGER[0];            // Task #2

    // Enable the Suspend/Resume PPI channels
    NRF_GPIOTE-&amp;gt;EVENTS_PORT = 0;
    NRF_PPI-&amp;gt;CHENSET = (1UL &amp;lt;&amp;lt; PPI_SPIM_RESUME) | (1UL &amp;lt;&amp;lt; PPI_SPIM_SUSPEND);

    blah_blah();
}&lt;/pre&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How to do SPIM with handshakes</title><link>https://devzone.nordicsemi.com/thread/517547?ContentTypeID=1</link><pubDate>Wed, 08 Jan 2025 18:35:33 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:36a71e81-2c6d-46a3-8854-06f08a032119</guid><dc:creator>Randy Lee</dc:creator><description>&lt;p&gt;OK, this is more in line with my understanding of how this works.... I&amp;#39;ll try to deal with it that direction.&amp;nbsp; Timing could be somewhat tight here but it helps that these parts are fast....&lt;/p&gt;
&lt;p&gt;Thanx for you folks help on this; you guys are great at it...&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How to do SPIM with handshakes</title><link>https://devzone.nordicsemi.com/thread/517543?ContentTypeID=1</link><pubDate>Wed, 08 Jan 2025 17:48:57 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:becc146f-c361-4584-99c0-0f954f205513</guid><dc:creator>Hieu</dc:creator><description>&lt;p&gt;You are right that there is only a single event for both edge. The PPI&amp;nbsp;will not actually pingpong anything. It will simply trigger the PPI channel that is enabled.&lt;/p&gt;
&lt;p&gt;So, if both the suspend and resume channels are enabled, both tasks are triggered, which is obviously not what we want, and I have no idea what will happen in that case.&lt;/p&gt;
&lt;p&gt;And you are also completely right that you&amp;nbsp;will need to use ISR.&lt;/p&gt;
&lt;p&gt;There are several options to do this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Manual &amp;quot;pingpong&amp;quot; like you mentioned. The simplest and fastest (shortest ISR time) way is to only enable one of the two PPI channels during initialization.&lt;br /&gt;The ISR handle will disable&amp;nbsp;one channel and enable the other.
&lt;ol&gt;
&lt;li&gt;A potential downside with this approach is a race condition if the next edge arrive before the ISR handling is done. &lt;br /&gt;How big a risk this is depends on the particularities of your system. There might be ways to work around it.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;The ISR handler controls the SPI suspending and resuming. It can do both tasks; or it can do one, and the other task is&amp;nbsp;still done by PPI.&lt;/li&gt;
&lt;/ol&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How to do SPIM with handshakes</title><link>https://devzone.nordicsemi.com/thread/517295?ContentTypeID=1</link><pubDate>Tue, 07 Jan 2025 15:48:51 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:d354efed-0477-4210-be22-d5e972507fda</guid><dc:creator>Randy Lee</dc:creator><description>&lt;p&gt;Yah, I get the HITOLO and that thing... here&amp;#39;s the question then:&lt;/p&gt;
&lt;p&gt;I&amp;#39;ve got one pin that the HITOLO would cause a suspend and the LOTOHI would cause the resume.&amp;nbsp; Setting this to check on TOGGLE makes sense since it&amp;#39;s a single pin and both edges are significant (but different)&lt;/p&gt;
&lt;p&gt;How then would I work nrf_drv_ppi_channel_assign() since the pin is going to generate events on both edges and the nrf_drv_gpiote_in_event_addr_get(READY_PIN) wouldn&amp;#39;t therefor distinguish which edge it&amp;#39;s seeing.&lt;/p&gt;
&lt;p&gt;Does PPI just pingpong between the edges when you get both like this?&lt;/p&gt;
&lt;p&gt;Or do I need to assign an ISR to this nrfx_gpiote_in_init() and reset the association during that (i.e. a manual pingpong)?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How to do SPIM with handshakes</title><link>https://devzone.nordicsemi.com/thread/517218?ContentTypeID=1</link><pubDate>Tue, 07 Jan 2025 13:08:00 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:9e533808-3343-42a3-a346-0a92ae0f215b</guid><dc:creator>Hieu</dc:creator><description>&lt;p&gt;Hi Randy,&lt;/p&gt;
&lt;p&gt;The key lies in the configuration of the GPIOTE input:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;    nrf_drv_gpiote_in_config_t ready_pin_config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(false);&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Here, a preset configuration was used. The preset configurations can be found in modules/nrfx/drivers/include/nrfx_gpiote.h.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;/**
 * @brief Macro for configuring a pin to use a GPIO IN or PORT EVENT to detect low-to-high transition.
 * @details Set hi_accu to true to use IN_EVENT.
 */
#define NRFX_GPIOTE_CONFIG_IN_SENSE_LOTOHI(hi_accu) \
{                                                   \
    .sense = NRF_GPIOTE_POLARITY_LOTOHI,            \
    .pull = NRF_GPIO_PIN_NOPULL,                    \
    .is_watcher = false,                            \
    .hi_accuracy = hi_accu,                         \
    .skip_gpio_setup = false,                       \
}

/**
 * @brief Macro for configuring a pin to use a GPIO IN or PORT EVENT to detect high-to-low transition.
 * @details Set hi_accu to true to use IN_EVENT.
 */
#define NRFX_GPIOTE_CONFIG_IN_SENSE_HITOLO(hi_accu) \
{                                                   \
    .sense = NRF_GPIOTE_POLARITY_HITOLO,            \
    .pull = NRF_GPIO_PIN_NOPULL,                    \
    .is_watcher = false,                            \
    .hi_accuracy = hi_accu,                         \
    .skip_gpio_setup = false,                       \
}

/**
 * @brief Macro for configuring a pin to use a GPIO IN or PORT EVENT to detect any change on the pin.
 * @details Set hi_accu to true to use IN_EVENT.
 */
#define NRFX_GPIOTE_CONFIG_IN_SENSE_TOGGLE(hi_accu) \
{                                                   \
    .sense = NRF_GPIOTE_POLARITY_TOGGLE,            \
    .pull = NRF_GPIO_PIN_NOPULL,                    \
    .is_watcher = false,                            \
    .hi_accuracy = hi_accu,                         \
    .skip_gpio_setup = false,                       \
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;You might notice the symbols are named a little different. That&amp;#39;s because they are given aliases in integration/nrfx/legacy/nrf_drv_gpiote.h.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;/** @brief Macro for forwarding the new implementation. */
#define GPIOTE_CONFIG_IN_SENSE_LOTOHI     NRFX_GPIOTE_CONFIG_IN_SENSE_LOTOHI
/** @brief Macro for forwarding the new implementation. */
#define GPIOTE_CONFIG_IN_SENSE_HITOLO     NRFX_GPIOTE_CONFIG_IN_SENSE_HITOLO
/** @brief Macro for forwarding the new implementation. */
#define GPIOTE_CONFIG_IN_SENSE_TOGGLE     NRFX_GPIOTE_CONFIG_IN_SENSE_TOGGLE&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;These aliases are to adapt usage of the old nrf_drv APIs to new nrfx APIs.&lt;/p&gt;
&lt;p&gt;Hieu&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How to do SPIM with handshakes</title><link>https://devzone.nordicsemi.com/thread/517101?ContentTypeID=1</link><pubDate>Mon, 06 Jan 2025 23:10:43 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:5fd18ee5-299a-44d2-b36f-0b886fd450f2</guid><dc:creator>Randy Lee</dc:creator><description>&lt;p&gt;Thanx.. No problem on my side...&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How to do SPIM with handshakes</title><link>https://devzone.nordicsemi.com/thread/517067?ContentTypeID=1</link><pubDate>Mon, 06 Jan 2025 15:54:44 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:9cf6d2e4-4c2a-4509-864c-aa9b42943a3e</guid><dc:creator>Simonr</dc:creator><description>&lt;p&gt;Hi Randy&lt;/p&gt;
&lt;p&gt;Susheel is currently out of office, and will be back on Monday next week. We&amp;#39;re currently working through our backlog after the Christmas period, so we&amp;#39;ll get back to you before Monday if we find the time to read through and explain the code snippet. If not you&amp;#39;ll hear back from Susheel on Monday.&lt;/p&gt;
&lt;p&gt;Best regards,&lt;/p&gt;
&lt;p&gt;Simon&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How to do SPIM with handshakes</title><link>https://devzone.nordicsemi.com/thread/516538?ContentTypeID=1</link><pubDate>Mon, 30 Dec 2024 21:26:21 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:ed614f4b-7e40-476b-ae05-ea824fb3a67a</guid><dc:creator>Randy Lee</dc:creator><description>&lt;p&gt;How does this code know which edge is active and which is not? I&amp;#39;m looking for a down edge as suspend and an up edge as resume..&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How to do SPIM with handshakes</title><link>https://devzone.nordicsemi.com/thread/515143?ContentTypeID=1</link><pubDate>Mon, 16 Dec 2024 14:28:00 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:c025ac63-9b47-4a1b-aff7-f6cba9fd8092</guid><dc:creator>Randy Lee</dc:creator><description>&lt;p&gt;Great! Thanx... this should get me there..&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How to do SPIM with handshakes</title><link>https://devzone.nordicsemi.com/thread/515080?ContentTypeID=1</link><pubDate>Mon, 16 Dec 2024 11:38:41 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:e1c80871-f8ce-46cc-b48a-0567c2e2013c</guid><dc:creator>Susheel Nuguru</dc:creator><description>&lt;p&gt;I got involved just because I saw FreeRTOS here but the code that you seek does not necessarily depend on FreeRTOS.&lt;/p&gt;
&lt;p&gt;After you initialize the&amp;nbsp;SPI using nrf_drv_spim_init, I think you can use something like below code as template to have the connections you see through PPI to the tasks.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;static nrf_ppi_channel_t ppi_channel_suspend;
static nrf_ppi_channel_t ppi_channel_resume;

void gpio_ppi_init(void)
{
    APP_ERROR_CHECK(nrf_drv_gpiote_init());

    // Set up the READY_PIN as an input that can detect both active and inactive edges.
    // This will let us sense when the external device signals us to pause or resume.
    nrf_drv_gpiote_in_config_t ready_pin_config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(false);
    ready_pin_config.pull = NRF_GPIO_PIN_NOPULL; // adjust if your circuit requires it.
    APP_ERROR_CHECK(nrf_drv_gpiote_in_init(READY_PIN, &amp;amp;ready_pin_config, NULL));

    // Reserve two PPI channels: one for pausing SPI (SUSPEND) and one for resuming it (RESUME).
    APP_ERROR_CHECK(nrf_drv_ppi_channel_alloc(&amp;amp;ppi_channel_suspend));
    APP_ERROR_CHECK(nrf_drv_ppi_channel_alloc(&amp;amp;ppi_channel_resume));

    // Link the READY_PIN&amp;#39;s &amp;quot;active edge&amp;quot; event to the SPIM&amp;#39;s SUSPEND task.
    // This ensures the SPI pauses when the device signals us to stop.
    APP_ERROR_CHECK(nrf_drv_ppi_channel_assign(
        ppi_channel_suspend,
        nrf_drv_gpiote_in_event_addr_get(READY_PIN),
        (uint32_t)&amp;amp;NRF_SPIM0-&amp;gt;TASKS_SUSPEND
    ));

    // Link the READY_PIN&amp;#39;s &amp;quot;inactive edge&amp;quot; event to the SPIM&amp;#39;s RESUME task.
    // This ensures the SPI resumes when the device signals it&amp;#39;s ready to continue.
    APP_ERROR_CHECK(nrf_drv_ppi_channel_enable(ppi_channel_suspend));
    APP_ERROR_CHECK(nrf_drv_ppi_channel_enable(ppi_channel_resume));
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;This is uncompiled code trying to show you the logic. Please use that as template.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How to do SPIM with handshakes</title><link>https://devzone.nordicsemi.com/thread/514341?ContentTypeID=1</link><pubDate>Tue, 10 Dec 2024 16:58:13 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:3892afd8-d1e7-45fc-a3d3-1cf4e63bc43d</guid><dc:creator>Randy Lee</dc:creator><description>&lt;p&gt;Very interesting indeed.... sounds like that&amp;#39;s the ticket for sure.&amp;nbsp; I don&amp;#39;t suppose someone has some example code of how to do it?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How to do SPIM with handshakes</title><link>https://devzone.nordicsemi.com/thread/514340?ContentTypeID=1</link><pubDate>Tue, 10 Dec 2024 16:55:49 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:f8c0d47b-08f3-4e5e-ba8a-2f75e5cfdc51</guid><dc:creator>hmolesworth</dc:creator><description>&lt;p&gt;Yes, there is a similar XON/XOFF functionality in the SPIM, use PPI to trigger hardware SPIM TASKS_SUSPEND and TASKS_RESUME from the active and inactive edges of the external hold signal.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;quot;A transaction can be suspended and resumed using the SUSPEND and RESUME tasks. When the SUSPEND&amp;nbsp;&lt;/em&gt;&lt;em&gt;task is triggered, the SPI master will complete transmitting and receiving the current ongoing byte before&amp;nbsp;it is suspended&amp;quot;&lt;/em&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How to do SPIM with handshakes</title><link>https://devzone.nordicsemi.com/thread/514275?ContentTypeID=1</link><pubDate>Tue, 10 Dec 2024 13:48:44 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:06e3104d-5c60-4439-b8d3-2d29766e1170</guid><dc:creator>Randy Lee</dc:creator><description>&lt;p&gt;nuts,,,, wrong button here.. let me see if I can clear the idea.&lt;/p&gt;
&lt;p&gt;Think of RS232 XON/XOFF functionality.&amp;nbsp; In this case we&amp;#39;re using an outside signal to hold off the transmission of bytes.&amp;nbsp; When it asserts, I need to not send the next byte (while keeping the select signal asserted).&amp;nbsp; Once it de-asserts, I can resume sending bytes via SPI&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How to do SPIM with handshakes</title><link>https://devzone.nordicsemi.com/thread/514227?ContentTypeID=1</link><pubDate>Tue, 10 Dec 2024 11:48:42 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:39149a09-5ea5-4e8b-95d8-43f5e4371f97</guid><dc:creator>Simonr</dc:creator><description>&lt;p&gt;Hi&lt;/p&gt;
&lt;p&gt;I&amp;#39;m sorry, but I&amp;#39;m not sure what you&amp;#39;re asking how to handle here. Is the READY handshake interrupting your transfers when you&amp;#39;re not expecting it to, or what exactly is the issue here? There could be buffer that reaches its limit for example, but please share some more information here on what the issue here is.&lt;/p&gt;
&lt;p&gt;Best regards,&lt;/p&gt;
&lt;p&gt;Simon&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item></channel></rss>