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

nrf52832 SPI no transfer done OLED

Hei guys,

this is my environment:

  • nrf52832 on custom board.

  • SDK 9.2

  • SD 132 1.0..0-3 preloaded in SD memory region

  • OLED with no MISO line

  • PINS configuration: CLK P04 CS P03 MOSI P05

The OLED needs one byte transfer. Due to this I tried to implement workaround PAN58 that another user asked but with no effect, the spi_master_event_handler() is never called. Here attached image of the serial comunication needed by the OLED:

image description

where XCS -> CS, A0 command select, D7/SI is MOSI, D6/SCL is CLK.

Now, the OLED needs a particular init sequence transferring data. Problem is that nothing seems to be transferred and, as already mentioned, evt_done is never reached. This result in a reset of the chip itself after a while.

Here the code implemented:

nrf_ppi_channel_t ppi_channel;
//OLED pin definition
#define OLED_ON					2
#define OLED_XRES				7
#define OLED_A0					6
#define OLED_MOSI				5
#define OLED_CS					3
#define OLED_CLK			    4

//setting up the SPI based on the spi_master_with_spi_slave example
//uses DMA
#if (SPI0_ENABLED == 1)
		static const nrf_drv_spi_t m_spi_master = NRF_DRV_SPI_INSTANCE(0);

#else
		#error "No SPI enabled."
#endif

static volatile bool m_transfer_completed = true; /**< A flag to inform about completed transfer. */

/**@brief Function for SPI master event callback.
 *
 * Upon receiving an SPI transaction complete event, checks if received data are valid.
 *
 * @param[in] spi_master_evt    SPI master driver event. 
 */
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(OLED_CLK);

						// 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;
		}
}


/**@brief Function for initializing bsp module.
 */
void bsp_configuration()
{
	
		uint32_t err_code = NRF_SUCCESS;

		NRF_CLOCK->LFCLKSRC            = (CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos);
		NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
		NRF_CLOCK->TASKS_LFCLKSTART    = 1;

		while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0)
		{
				// Do nothing.
		}
		/*APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, NULL);
		err_code = bsp_init(BSP_INIT_LED, APP_TIMER_TICKS(100, APP_TIMER_PRESCALER), NULL);
		APP_ERROR_CHECK(err_code);*/
}



	
void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
		nrf_drv_gpiote_out_toggle(OLED_CLK);
}

/**@brief Functions prepares buffers and starts data transfer
 *
 * @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)
{
				
				uint32_t err_code;
		NRF_SPIM_Type * p_spim = m_spi_master.p_registers;

		if (len == 1){
						ret_code_t err_code;
nrf_gpio_pin_clear(OLED_CS);
						// 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(OLED_CLK, &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(OLED_CLK), (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(OLED_CLK, 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					
						//disable a GPIOTE output pin task.
						nrf_drv_gpiote_out_task_disable(OLED_CLK);

										 
nrf_gpio_pin_set(OLED_CS);						
				}
				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(1);
}

void  oledWriteData(uint8_t byteToSend, uint8_t comm) { 
 
	
	if(comm == 1)
	{
		nrf_gpio_pin_set(OLED_A0);
	}
	else
	{
		nrf_gpio_pin_clear(OLED_A0);
	}
	uint8_t write_buffer[1];
	write_buffer[0] = byteToSend;
	spi_send_recv(write_buffer,NULL,1);	
	nrf_gpio_pin_set(OLED_A0);
}

void oledInit(void)
{
	oledWriteData(0x01, 1);
	nrf_delay_ms(1);
	oledWriteData(0x02, 1);	
	oledWriteData(0x00, 0);

	oledWriteData(0x07, 1);
	oledWriteData(0x00, 0);

	oledWriteData(0x09, 1);	
	oledWriteData(0x00, 0);

	oledWriteData(0x10, 1);	
	oledWriteData(0x04, 0); //Here it blocks anyway, some buffers full?

	oledWriteData(0x12, 1);	
	oledWriteData(0x65, 0);

	oledWriteData(0x13, 1);	
	oledWriteData(0x00, 0);

	oledWriteData(0x14, 1);	
	oledWriteData(0x00, 0);

	oledWriteData(0x16, 1);	
	oledWriteData(0x00, 0);

	oledWriteData(0x17, 1);	
	oledWriteData(0x00, 0);

	oledWriteData(0x18, 1);
	oledWriteData(0x04, 0);

	oledWriteData(0x1a, 1);	
	oledWriteData(0x01, 0);

	oledWriteData(0x1c, 1);	
	oledWriteData(0x00, 0);

	oledWriteData(0x1d, 1);	
	oledWriteData(0x00, 0);

	oledWriteData(0x30, 1);	
	oledWriteData(0x10, 0);
	oledWriteData(0x6f, 0);

	oledWriteData(0x32, 1);	
	oledWriteData(0x00, 0);
	oledWriteData(0x26, 0); 

	oledWriteData(0x34, 1);
	oledWriteData(0x00, 0);

	oledWriteData(0x35, 1);
	oledWriteData(0x0f, 0);

	oledWriteData(0x36, 1);
	oledWriteData(0x00, 0);

	oledWriteData(0x37, 1);
	oledWriteData(0x26, 0);


	oledWriteData(0x38, 1);	
	oledWriteData(0x70, 0);


	oledWriteData(0x39, 1);	
	oledWriteData(0x00, 0);




	oledWriteData(0x48, 1);	
	oledWriteData(0x03, 0);

	oledWriteData(0xc3, 1);	
	oledWriteData(0x00, 0);

	oledWriteData(0xc4, 1);
	oledWriteData(0x00, 0);

	oledWriteData(0xcc, 1);	
	oledWriteData(0x00, 0);

	oledWriteData(0xcd, 1);	
	oledWriteData(0x00, 0);

	oledWriteData(0xd0, 1);
	oledWriteData(0x80, 0);


	oledWriteData(0xd2, 1);	
	oledWriteData(0x00, 0);

	oledWriteData(0xd9, 1);	
	oledWriteData(0x00, 0);

	oledWriteData(0xdb, 1);	
	oledWriteData(0x0f, 0);

	oledWriteData(0xdd, 1);
	oledWriteData(0x86, 0);


}
int main(void){
		
		bsp_configuration();
		
		nrf_gpio_cfg_output(OLED_ON);	
		nrf_gpio_cfg_output(OLED_XRES);
		nrf_gpio_cfg_output(OLED_CS);
		nrf_gpio_cfg_output(OLED_CLK);
		nrf_gpio_cfg_output(OLED_MOSI);
		nrf_gpio_cfg_output(OLED_A0);

		nrf_gpio_pin_clear(OLED_ON);
		nrf_delay_ms(2);
		nrf_gpio_pin_clear(OLED_XRES);
		nrf_delay_ms(1);
		nrf_gpio_pin_set(OLED_XRES);
		nrf_delay_ms(1);
		nrf_gpio_pin_set(OLED_ON);	
		
		//Configure SPI interface
		nrf_drv_spi_config_t const config =
		{
				#if (SPI0_ENABLED == 1)
						.sck_pin  = OLED_CLK, 
						.mosi_pin = OLED_MOSI,
						.miso_pin = NRF_DRV_SPI_PIN_NOT_USED,
						.ss_pin   = NRF_DRV_SPI_PIN_NOT_USED,
						
				
				#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_0,
						.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 PPI and GPIOTE
		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;
		delay = 100;
		
		oledInit();
		//oledOn();
		//oledClear(0, 11, 0, 39, 0x01);
		//oledPrintBitmap(my_hello_message,0,39,0,96);
		//Infinite loop containing main functionality
		for(;;){
		 // nrf_delay_ms(delay);
			//SEGGER_RTT_WriteString(0, "Enterred For loop \n");	
			
			
			
			if (m_transfer_completed)
			{
				//SEGGER_RTT_WriteString(0, "SPI transfer successful \n");			
				m_transfer_completed = false;
			}
			nrf_delay_ms(1);
		}
}		

Could you help me? It would be very appreciated.

Thanks.

Parents
  • mmhhh as far as I understood, uC is resetting thx to APP_ERROR_CHECK due to temptative to assign GPIOTE in function nrf_drv_gpiote_in_init() after the second write temptative. It enters in the first if and result is NRF_ERROR_INVALID_STATE (8). I think this is because the GPIOTE channel is not released by the spi_master_event_handler(). But i still missing something....

Reply
  • mmhhh as far as I understood, uC is resetting thx to APP_ERROR_CHECK due to temptative to assign GPIOTE in function nrf_drv_gpiote_in_init() after the second write temptative. It enters in the first if and result is NRF_ERROR_INVALID_STATE (8). I think this is because the GPIOTE channel is not released by the spi_master_event_handler(). But i still missing something....

Children
No Data
Related