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

Problems Implementing Workaround to get nrf52 to send an octet / one byte through SPI

I'm having trouble implementing the workaround that was mentioned in the following previous post: https://devzone.nordicsemi.com/question/55937/nrf52-sending-an-octet/

Thus, I've attached the relevant code that I have so far.

P.S. I'm a beginner so some things that may be obvious to you, might not be obvious to me. Thus I would greatly appreciate detailed answers! The more information, the better.

In my main.c file:

/**
 * @brief Work-around for transmitting 1 byte with SPIM.
 *
 * @param spim: The SPIM instance that is in use.
 * @param ppi_channel: An unused PPI channel that will be used by the
		workaround.
 * @param gpiote_channel: An unused GPIOTE channel that will be used by
		the workaround.
 *
 * @warning Must not be used when transmitting multiple bytes.
 * @warning After this workaround is used, the user must reset the PPI
		channel and the GPIOTE channel before attempting to transmit multiple
		bytes.
 */
void setup_workaround_for_ftpan_58(NRF_SPIM_Type *spim, 
							       uint32_t ppi_channel, 
							       uint32_t gpiote_channel){
	
    // Create an event when SCK toggles.
	NRF_GPIOTE->CONFIG[gpiote_channel] = 
		(GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos) | 
		(spim->PSEL.SCK << GPIOTE_CONFIG_PSEL_Pos) | 
		(GPIOTE_CONFIG_POLARITY_Toggle <<GPIOTE_CONFIG_POLARITY_Pos);

	// Stop the spim instance when SCK toggles.
	NRF_PPI->CH[ppi_channel].EEP = (uint32_t)&NRF_GPIOTE->EVENTS_IN[gpiote_channel];
	NRF_PPI->CH[ppi_channel].TEP = (uint32_t)&spim->TASKS_STOP;
	NRF_PPI->CHENSET = 1U << ppi_channel;
}

/**@brief Functions prepares buffers and starts data transfer to AS3911
 *
 * @param[in] p_tx_data     A pointer to a buffer TX.
 * @param[in] p_rx_data     A pointer to a buffer RX.
 * @param[in] len           A length of the data buffers.
 */
static void spi_send_recv(uint8_t * const p_tx_data,
                          uint8_t * const p_rx_data,
                          const uint16_t  len)
{
	SEGGER_RTT_WriteString(0, "Send and Receive info \n");
	
    if (len == 1){
		nrf_ppi_channel_t ppi_channel;
		uint32_t gpiote_task_addr;
		ret_code_t err_code;
			
		//initializes the GPIOTE channel so that SCK toggles
		nrf_drv_gpiote_out_config_t config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(false);
		err_code = nrf_drv_gpiote_out_init(SPIM0_SCK_PIN, &config);
		APP_ERROR_CHECK(err_code);	
	
		//allocates the first unused PPI Channel
		err_code = nrf_drv_ppi_channel_alloc(&ppi_channel);
		APP_ERROR_CHECK(err_code);
	
		//get the address of the GPIOTE task 
		//(is this is a GPIOTE channel??????)
		gpiote_task_addr = nrf_drv_gpiote_out_task_addr_get	(SPIM0_SCK_PIN);
	
		//enable the PPI channel.
		err_code = nrf_drv_ppi_channel_enable(ppi_channel);
		APP_ERROR_CHECK(err_code);
	
		//enable the GPIOTE output pin task.
		nrf_drv_gpiote_out_task_enable(SPIM0_SCK_PIN);
			
		//Start transfer of data
		err_code = nrf_drv_spi_transfer(&m_spi_master, p_tx_data, len, p_rx_data, len);
		APP_ERROR_CHECK(err_code);
			
		//interrupt transfer of data so that only one byte is sent
		setup_workaround_for_ftpan_58(NRF_SPIM_Type *spim, 
									       ppi_channel, 
									       gpiote_task_addr);
																
		//disable the ppi channel
		err_code = nrf_drv_ppi_channel_disable(ppi_channel);
	
		//disable a GPIOTE output pin task.
		nrf_drv_gpiote_out_task_disable(SPIM0_SCK_PIN);
	}
	else{
		// Start transfer.
		uint32_t err_code = nrf_drv_spi_transfer(&m_spi_master, p_tx_data, len,         
                                                                            p_rx_data, len);
		APP_ERROR_CHECK(err_code);
	}
		
    nrf_delay_ms(delay);
}

/**@brief Function for sending 1 byte to AS3911
*
* @param[in] cmd is the register of the AS3911 that you want to write to
*/
void as3911ExecuteCommand(uint8_t cmd){
	uint8_t write_buffer[1];
	SEGGER_RTT_WriteString(0, "Entered Execute Command\n");
	write_buffer[0] = cmd | AS3911_CMD_MODE;
	spi_send_recv(write_buffer, NULL, 1);
}

int main(void){
	//0 is the terminal number where the text is output on the J-link RTT
	//These lines are meant for debugging purposes and are not necessary 
	SEGGER_RTT_WriteString(0, "Program Begin\n");			
		
	//INITIALIZING PERIPHERALS
	//Initialize UART, and board support
	uart_config();
	bsp_configuration();
		
	//Configure SPI interface
    nrf_drv_spi_config_t const config =
    {
        #if (SPI0_ENABLED == 1)
            .sck_pin  = SPIM0_SCK_PIN, 
            .mosi_pin = SPIM0_MOSI_PIN,
            .miso_pin = SPIM0_MISO_PIN,
            .ss_pin   = SPIM0_SS_PIN,
        
        #endif
        .irq_priority = APP_IRQ_PRIORITY_LOW, //tells computer what to prioritize over other things
				.orc          = 0x00,
        .frequency    = NRF_DRV_SPI_FREQ_1M,
        .mode         = NRF_DRV_SPI_MODE_1,
        .bit_order    = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST,	
    };
		
	//Initialize SPI
	ret_code_t err_code = nrf_drv_spi_init(&m_spi_master, &config, spi_master_event_handler);
    APP_ERROR_CHECK(err_code);
		
	//initialize GPIOTE and PPI
    err_code = nrf_drv_ppi_init();
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_gpiote_init();
    APP_ERROR_CHECK(err_code);
		
	//VARIABLES
	uint8_t numBytesReg = 0x1D;
		
	//Infinite loop containing main functionality
	for(;;){
		if (m_transfer_completed)
		{
			m_transfer_completed = false;		
			as3911WriteRegister(numBytesReg, 0x01);
			as3911ExecuteCommand(0xC1);				
		}			
	}
}	

ATTACHMENTS: main.c nrf_drv_spi.c nrf_drv_config.h nrf_drv_gpiote.c nrf_drv_ppi.c

Parents
  • This method did not work for me using SDK11. Nordic provided the following fix. The SDK drivers is not designed for this workaround.

    The stop event was not handled. In srf_drv_spi.c replace irq_handler_spim at line 557 with the below

    static void irq_handler_spim(NRF_SPIM_Type * p_spim, spi_control_block_t * p_cb)
    {
        ASSERT(p_cb->handler);
    #ifdef NRF52_PAN_23
        if (nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_STOPPED))
        {
            nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_STOPPED);
            finish_transfer(p_cb);
        }
        else
        {
            if (nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_ENDTX))
            {
                nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_ENDTX);
                p_cb->tx_done = true;
            }
            if (nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_ENDRX))
            {
                nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_ENDRX);
                p_cb->rx_done = true;
            }
            if (p_cb->tx_done && p_cb->rx_done)
            {
                nrf_spim_task_trigger(p_spim, NRF_SPIM_TASK_STOP);
            }
        }
    #else
        if (nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_END))
        {
            nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
            finish_transfer(p_cb);
        }
        else
        {
          if (nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_STOPPED))
          {
              nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_STOPPED);
              finish_transfer(p_cb);
          }
        }
    #endif
    }
    

    Here you can see that i have added handling of STOPPED_EVENT clearing the event. I tested it and it works ok now.

Reply
  • This method did not work for me using SDK11. Nordic provided the following fix. The SDK drivers is not designed for this workaround.

    The stop event was not handled. In srf_drv_spi.c replace irq_handler_spim at line 557 with the below

    static void irq_handler_spim(NRF_SPIM_Type * p_spim, spi_control_block_t * p_cb)
    {
        ASSERT(p_cb->handler);
    #ifdef NRF52_PAN_23
        if (nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_STOPPED))
        {
            nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_STOPPED);
            finish_transfer(p_cb);
        }
        else
        {
            if (nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_ENDTX))
            {
                nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_ENDTX);
                p_cb->tx_done = true;
            }
            if (nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_ENDRX))
            {
                nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_ENDRX);
                p_cb->rx_done = true;
            }
            if (p_cb->tx_done && p_cb->rx_done)
            {
                nrf_spim_task_trigger(p_spim, NRF_SPIM_TASK_STOP);
            }
        }
    #else
        if (nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_END))
        {
            nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
            finish_transfer(p_cb);
        }
        else
        {
          if (nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_STOPPED))
          {
              nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_STOPPED);
              finish_transfer(p_cb);
          }
        }
    #endif
    }
    

    Here you can see that i have added handling of STOPPED_EVENT clearing the event. I tested it and it works ok now.

Children
Related