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, ®_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, ®_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?