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
  • Modified your code Update 28.01.16 : code fixed for this workaround to work correctly ...

    static void spi_master_event_handler(nrf_drv_spi_event_t event)
    {
        uint32_t err_code = NRF_SUCCESS;
        switch (event)
        {
            //if event is equal to NRF_DRV_SPI_EVENT_DONE, then this block is executed to check if data is valid
    			  case NRF_DRV_SPI_EVENT_DONE:   
                      
                  			//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);
                  
                // Check if data are valid.
                err_code = bsp_indication_set(BSP_INDICATE_RCV_OK);
                APP_ERROR_CHECK(err_code);
    
                // Inform application that transfer is completed.
                m_transfer_completed = true;
                break;
    				
    				//if event is not equal to NRF_DRV_SPI_EVENT_DONE, then nothing happens
            default:
                // No implementation needed.
                break;
        }
    }
    
    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");
    		uint32_t err_code;
        NRF_SPIM_Type * p_spim = m_spi_master.p_registers;
    	
        if (len == 1){
    			ret_code_t err_code;
    			
    			// initializes the GPIOTE channel so that SCK toggles generates events
    			nrf_drv_gpiote_in_config_t config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(true);
    			err_code = nrf_drv_gpiote_in_init(SPIM0_SCK_PIN, &config, in_pin_handler);
    			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);
    
                err_code = nrf_drv_ppi_channel_assign(ppi_channel,
                                              nrf_drv_gpiote_in_event_addr_get(SPIM0_SCK_PIN),
                                              (uint32_t)&p_spim->TASKS_STOP);
                APP_ERROR_CHECK(err_code);
    
    	
    			//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_in_event_enable(SPIM0_SCK_PIN, false);
    			
    			//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);
    			
    												
    			//uninitializes the gpiote channel
    			//the gpiote channel is represented by a 32-bit variable
    			//not sure if we need to unintitialize the pin, or if we can just disable it
    			//nrf_drv_gpiote_out_uninit(SPIM0_SCK_PIN);	
    		}
    		else{
    			// Start transfer.
    			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);
    }
    
  • I'm having trouble with figuring out what should be included in the in_pin_handler(). Could you please clarify this. Furthermore, for some reason, the program will not run past the instruction err_code = nrf_drv_ppi_channel_assign(ppi_channel_workaround, nrf_drv_gpiote_in_event_addr_get(SPIM0_SCK_PIN), p_spim->TASKS_STOP); Currently, when I comment out the workaround, it does not affect anything so i have a feeling that the workaround is still not properly implemented.

Reply
  • I'm having trouble with figuring out what should be included in the in_pin_handler(). Could you please clarify this. Furthermore, for some reason, the program will not run past the instruction err_code = nrf_drv_ppi_channel_assign(ppi_channel_workaround, nrf_drv_gpiote_in_event_addr_get(SPIM0_SCK_PIN), p_spim->TASKS_STOP); Currently, when I comment out the workaround, it does not affect anything so i have a feeling that the workaround is still not properly implemented.

Children
No Data
Related