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

nRF52 with FreeRTOS: TWI error NRF_ERROR_INTERNAL

Hello,

I'm developing firmware for nRF52832 with FreeRTOS, I would like to use TWI to access to an external memory. Every time I try to use "nrf_drv_twi_tx" function i get NRF_ERROR_INTERNAL error.

I already read lot of answer about this issue, but any solution is working.

#include <stdbool.h>
#include <stdint.h>
#include <string.h>

#include <nordic_common.h>
#include <nrf.h>

#include <nrf_drv_clock.h>
#include <nrf_log.h>
#include <nrf_log_ctrl.h>
#include <nrf_log_default_backends.h>

#include <nrf_sdh.h>
#include <nrf_sdh_soc.h>
#include <nrf_sdh_freertos.h>

#include <sdk_errors.h>
#include <nrf_drv_twi.h>
#include <nrf_gpio.h>

#include <app_timer.h>
#include <app_error.h>

#include <FreeRTOS.h>
#include <task.h>
#include <timers.h>
#include <SEGGER_RTT.h>


#define		VERB_HW_TWI																		// enable verbose output for debug

#define		TWI_SCL_PIN								9										// PIN		9 (P0.9)
#define		TWI_SDA_PIN								10										// PIN		10 (P0.10)
#define		TWI_INSTANCE							1										// value		TWI instance index.
#define		TWI_IRQ_PRIORITY						APP_IRQ_PRIORITY_LOW				// value		Interrupt priority.
#define		FM24CL16B_SLAVE_ADDR					0x50									// value		slave address (with A2=0, A1=0)

// tasks stack sizes and priorities: 0 = lowest priority; (configMAX_PRIORITIES–1) = highest priority
#define		vTask_Main_STACK_SIZE				300
#define		vTask_Main_PRIORITY					(1+tskIDLE_PRIORITY)
#define		vTask_LOGGER_STACK_SIZE				256
#define		vTask_LOGGER_PRIORITY				(2+tskIDLE_PRIORITY)


/**					Internal Variable Declaration									**/
static const nrf_drv_twi_t	twi_instance = NRF_DRV_TWI_INSTANCE( TWI_INSTANCE );				// Instance of TWI master driver that will be used for communication
static SemaphoreHandle_t	xProtection_smphr = NULL;


/* INIT for TWI hardware for peripheral */
void vInit_TWI_Hardware( void ) {
	NRF_LOG_INFO( "vInit_TWI_Hardware" );
	ret_code_t err_code;
	static const nrf_drv_twi_config_t twi_config = {
		.scl =						TWI_SCL_PIN,											// SCL pin number.
		.sda =						TWI_SDA_PIN,											// SDA pin number.
		.frequency =				NRF_DRV_TWI_FREQ_400K,								// TWI frequency.
		.interrupt_priority =	TWI_IRQ_PRIORITY,										// Interrupt priority.
		.clear_bus_init =			false,													// Clear bus during init.
		.hold_bus_uninit =		false														// Hold pull up state on gpio pins after uninit.
	};
	err_code = nrf_drv_twi_init( &twi_instance, &twi_config, NULL, NULL );
	APP_ERROR_CHECK( err_code );
	//
	nrf_gpio_cfg( TWI_SCL_PIN,											// pin_number
					  NRF_GPIO_PIN_DIR_INPUT,							// Input.
					  NRF_GPIO_PIN_INPUT_CONNECT,						// Connect input buffer.
					  NRF_GPIO_PIN_NOPULL,								// Pin pull-up resistor disabled.
					  NRF_GPIO_PIN_S0S1,									// Standard '0', standard '1'.
					  NRF_GPIO_PIN_NOSENSE								// Pin sense level disabled.
					);
	nrf_gpio_cfg( TWI_SDA_PIN,											// pin_number
					  NRF_GPIO_PIN_DIR_INPUT,							// Input.
					  NRF_GPIO_PIN_INPUT_CONNECT,						// Connect input buffer.
					  NRF_GPIO_PIN_NOPULL,								// Pin pull-up resistor disabled.
					  NRF_GPIO_PIN_S0S1,									// Standard '0', standard '1'.
					  NRF_GPIO_PIN_NOSENSE								// Pin sense level disabled.
					);
	// RTOS init
	xProtection_smphr = xSemaphoreCreateBinary();									// Ensure the semaphore is created before it gets used.
	ASSERT( xProtection_smphr );															// LOCK HERE: the semaphore could not be created
	xSemaphoreGive( xProtection_smphr );												// 'Give' the peripheral protection semaphore
	NRF_LOG_INFO( "vInit_TWI_Hardware: DONE" );
	return;
}

/*  */
ret_code_t xUtil_TWI_Read( uint8_t slave_addr, uint8_t start_addr, uint8_t *p_buff, uint16_t length ) {
	#ifdef VERB_HW_TWI
	NRF_LOG_INFO( "xUtil_TWI_Read:\tslave = 0x%02X\taddr = 0x%02X\tlenght = %u", slave_addr, start_addr, length );
	#endif
	ret_code_t err_code;
	static uint8_t reg_addr;
	reg_addr = start_addr;

	if( length == 0 ) {																							// sanity check for lenght
		err_code = NRF_ERROR_INVALID_LENGTH;

	} else if( xSemaphoreTake( xProtection_smphr, portMAX_DELAY ) == pdPASS ) {				// execute operation only if resuorce is free
		nrf_drv_twi_enable( &twi_instance );																// enable I2C
		err_code = nrf_drv_twi_tx( &twi_instance, slave_addr, &reg_addr, 1, true );
		APP_ERROR_CHECK( err_code );
		err_code = nrf_drv_twi_rx( &twi_instance, slave_addr, p_buff, length );
		APP_ERROR_CHECK( err_code );
		nrf_drv_twi_disable( &twi_instance );
		xSemaphoreGive( xProtection_smphr );																// 'Give' the semaphore to unblock the blocked task.

	} else { err_code = NRF_ERROR_RESOURCES; }

	return err_code;
}

/*  */
ret_code_t xUtil_TWI_Write( uint8_t slave_addr, uint8_t start_addr, uint8_t const *p_buff, uint16_t length ) {
	#ifdef VERB_HW_TWI
	NRF_LOG_INFO( "xUtil_TWI_Write:\tslave = 0x%02X\taddr = 0x%02X\tlenght = %u", slave_addr, start_addr, length );
	#endif
	ret_code_t err_code;
	static uint8_t reg_addr;
	reg_addr = start_addr;

	if( length == 0 ) {																							// sanity check for lenght
		err_code = NRF_ERROR_INVALID_LENGTH;

	} else if( xSemaphoreTake( xProtection_smphr, portMAX_DELAY ) == pdPASS ) {				// execute operation only if resuorce is free
		nrf_drv_twi_enable( &twi_instance );																// enable I2C
		err_code = nrf_drv_twi_tx( &twi_instance, slave_addr, &reg_addr, 1, true );
		APP_ERROR_CHECK( err_code );
		err_code = nrf_drv_twi_tx( &twi_instance, slave_addr, p_buff, length, false );
		APP_ERROR_CHECK( err_code );
		nrf_drv_twi_disable( &twi_instance );
		xSemaphoreGive( xProtection_smphr );																// 'Give' the semaphore to unblock the blocked task.

	} else { err_code = NRF_ERROR_RESOURCES; }

	return err_code;
}

/* MAIN Task */
static void vTask_Main( void *pvParameters ) {
	NRF_LOG_INFO( "Task started: vTask_Main" );
	UNUSED_PARAMETER( pvParameters );
	ret_code_t err_code;
	static uint8_t tx[2] = {100, 150};
	static uint8_t rx[2] = {200, 250};
	vInit_TWI_Hardware();

	while( 1 ) {																				// task Loop
		err_code = xUtil_TWI_Write( FM24CL16B_SLAVE_ADDR, 0, tx, 1 );
		NRF_LOG_INFO( "%10ums\tvTask_Main: write:\terr_code: %u\tbuffer = %u", xTaskGetTickCount(), err_code, tx[0] );
		err_code = xUtil_TWI_Read( FM24CL16B_SLAVE_ADDR, 0, rx, 1 );
		NRF_LOG_INFO( "%10ums\tvTask_Main: write:\terr_code: %u\tbuffer = %u", xTaskGetTickCount(), err_code, rx[0] );
		vTaskDelay( pdMS_TO_TICKS( 2000 ) );
	}
}

/**					MAIN Program														**/
int main( void ) {
	ret_code_t err_code;
	// Initialize clock
	err_code = nrf_drv_clock_init();
	APP_ERROR_CHECK( err_code );
	// Initialize logging
	err_code = NRF_LOG_INIT( NULL );
	APP_ERROR_CHECK( err_code );
	NRF_LOG_DEFAULT_BACKENDS_INIT();
	NRF_LOG_INFO( RTT_CTRL_CLEAR );									// clear the terminal window
	NRF_LOG_INFO( RTT_CTRL_BG_BLACK );
	NRF_LOG_INFO( RTT_CTRL_TEXT_BRIGHT_WHITE );
	// Do not start any interrupt that uses system functions before system initialisation.
	// The best solution is to start the OS before any other initalisation.
	#if NRF_LOG_ENABLED

	// LOG task creation
	if( pdPASS != xTaskCreate( vTask_Logger, "Logger", vTask_LOGGER_STACK_SIZE, NULL, vTask_LOGGER_PRIORITY, &m_task_handle_Logger ) ) {
		APP_ERROR_HANDLER( NRF_ERROR_NO_MEM );
	}

	#endif
	SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;								// Activate deep sleep mode.
	// Initialize the SoftDevice and the stack event interrupt.
	err_code = nrf_sdh_enable_request();
	APP_ERROR_CHECK( err_code );
	ASSERT( nrf_sdh_is_enabled() );									// sanity check for SoftDevice Initialized
	err_code = app_timer_init();										// Initialize timer module (used by BLE)
	APP_ERROR_CHECK( err_code );
	//

	if( xTaskCreate( vTask_Main, "main", vTask_Main_STACK_SIZE, NULL, vTask_Main_PRIORITY, NULL ) != pdPASS ) {
		APP_ERROR_HANDLER( NRF_ERROR_NO_MEM );						// LOCK HERE: the task could not be created
	}

	NRF_LOG_INFO( "FreeRTOS: Starting Scheduler..." );
	vTaskStartScheduler();												// Start FreeRTOS scheduler

	while( 1 ) { APP_ERROR_HANDLER( NRF_ERROR_FORBIDDEN ); }	// LOCK HERE: there is not enough FreeRTOS heap memory available to create the Idle and Timer tasks
}

when I run the code, every time it call the "nrf_drv_twi_tx" function i get NRF_ERROR_INTERNAL error.

Please can you help me?

Parents
  • It's most likely the timeout occurred when there is no response (ACK) from the slave. 

    Could you show the schematics and a close up photo of your setup ?

    I don't think so. I checked with oscilloscope and there is no signal running on TWI pins. whe the circuit powers up the SDA and SCL goes high (by an externel pullup 4k7 resistor) and remains high.

    I would suggest to test TWI with emulated EEPROM memory before you test with the actual memory. We have an example in nRF5 SDK that does that, please check the twi_master_with_twis_slave 

    I based my code exactly on this example, so I can't figure out what is wrong.

    what other test I should do?

    Thanks.

Reply
  • It's most likely the timeout occurred when there is no response (ACK) from the slave. 

    Could you show the schematics and a close up photo of your setup ?

    I don't think so. I checked with oscilloscope and there is no signal running on TWI pins. whe the circuit powers up the SDA and SCL goes high (by an externel pullup 4k7 resistor) and remains high.

    I would suggest to test TWI with emulated EEPROM memory before you test with the actual memory. We have an example in nRF5 SDK that does that, please check the twi_master_with_twis_slave 

    I based my code exactly on this example, so I can't figure out what is wrong.

    what other test I should do?

    Thanks.

Children
Related