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 Reply Children
Related