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

Related