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

the problem of high frequency send iic data

hi,i want to control a led driver by frequency send iic data, i need send 600 bytles once at least  10ms each time ,and the 600 bytles send by 3times.send the 600 bytles need 24ms.i create a 10ms once timer,and in the end of the timer handler start the timer again.but now i find after run few mins the seeger will report the error:

00> <error> app: ERROR 4 [NRF_ERROR_NO_MEM] at ..\..\..\..\..\..\components\libraries\timer\app_timer2.c:181

and the chip cant work before reset.

at frist i guess the reson is the time of execute the 10ms timer handler is so long(24ms) that  reslut in the scheduler problem.but when try to replace the iic send api to nrf_delay_ms( 24); the problem will not occur.so it is obvious that the reson is the iic send action.

this is my code 

//扫描定时器回调
void led_scan_timer_handler(void * p_context)
{
	UNUSED_PARAMETER(p_context);
	disp_scan();

//	led_test();
	
	
//stream_prase(stream_page.para,led_data);
	
}
//定时器初始化
void led_scan_timer_init(void)
{
	  ret_code_t err_code;
	/*
    err_code = app_timer_init();
    APP_ERROR_CHECK(err_code);
    */
	 
    err_code = app_timer_create(&m_led_scan_timer_id,
                                APP_TIMER_MODE_SINGLE_SHOT,
                                led_scan_timer_handler);
    APP_ERROR_CHECK(err_code);
}
//启动定时器
void led_scan_timer_start(void )
{
    ret_code_t err_code;

    err_code = app_timer_start(m_led_scan_timer_id, LED_FLASH_INTERVAL, NULL);
    APP_ERROR_CHECK(err_code);

}
//关闭定时器
void led_scan_timer_stop(void)
{
    ret_code_t err_code;

    err_code = app_timer_stop(m_led_scan_timer_id);
    APP_ERROR_CHECK(err_code);
}

disp_frame_data() in the disp_scan() is my iic send api

//led显示扫描函数
void disp_scan(void)
{
	
	uint8_t need_flash=0;
	/*
	if(!disp_control.valid)
		return;
	*/
	
	//控制速度   显示间隔: 50+(101-speed)*10  ms
//	if(disp_control.time_count%(LED_MIN_INTERVAL_MS/*+LED_SCAN_BASE_MS*(100-disp_control.disp_page->speed)*/)==0)
	{
		

#if SCAN_DEBUG
		//数据解析
		if(disp_control.disp_page->value_prase!=NULL)
		{
			need_flash = disp_control.disp_page->value_prase(disp_control.disp_page->para,led_data);
		//	stream_prase(stream_page.para, led_data);
		}


		//定时器是否需要关闭
		if(need_flash)
		{
			
		}
		else
		{
			led_scan_timer_stop();
			//关闭定时器
		}
		

		//led 显示函数
        disp_frame_data( led_data,/*disp_control.disp_page->lightness*/10);
		//port_delay_ms(24);
		
		send_flag = 1;
#endif		

		
	}
	

	
	//触发延时动作
	if(disp_control.time_count == disp_control.disp_page->delay_ms/LED_SCAN_BASE_MS)//
	{
		if(disp_control.disp_page->action!=NULL)
		{
			disp_control.disp_page->action();
		}
	}
	
	#if 1
	
	//用于某个插入界面只显示一段时间
	if(disp_control.disp_page->show_ms==AWLAYS_LIGHTING)//常亮
	{
		
	}
	else
	{
		
		
		if(disp_control.time_count == disp_control.disp_page->show_ms/LED_SCAN_BASE_MS)//定时显示
		{
			stop_led_show();
			if(ExistPushPage)//退出插入界面
			{
				
				ExistPushPage = 0;
				//重新进入之前的界面
				cmd_exit_push(NULL , NULL);
				
			}
			
		}
		
		
	}
	#endif
		disp_control.time_count++;
	
	if(disp_control.time_count%10)
	{
	 NRF_LOG_INFO("disp_scan   disp_control.time_count =%d\r\n",disp_control.time_count);
	}
	
	  led_scan_timer_start( );//由于led的iic显示需要耗费大约30ms,所以不适用周期性毫秒定时器,采用接力方式完成,更为稳妥和保险
}

void disp_frame_data(uint8_t (*led_data)[RGB_LED_X_NUM][3],uint8_t lightness_per)
{
	frame_data_to_chip( led_data);
	disp_one_chip_data( AW_CHIP_INDEX_0, chip0_data,lightness_per);
    disp_one_chip_data( AW_CHIP_INDEX_1, chip1_data,lightness_per);
	disp_one_chip_data( AW_CHIP_INDEX_2, chip2_data,lightness_per);
}


static void disp_one_chip_data(uint8_t device_index,uint8_t *pwm_data,uint8_t brightness)
{
  static uint8_t last_brightness[AW_CHIP_MAX_NUM] ={0};
	
	if(last_brightness[device_index]!=brightness)
	{
	  set_chip_led_brightness( chip_table[device_index], brightness);
	}
	
  set_led_pwm_brightness(chip_table[device_index], pwm_data);
	last_brightness[device_index] = brightness;
	
}


void set_led_pwm_brightness(uint8_t device_addr,uint8_t *pwm_data)
{
    set_page(device_addr, AW20216_REG_PAGE1);
	memcpy(&page_data[1],pwm_data,216);
	page_data[0] = PWM_REG_START_ADDR;
	aw_iic_writebytes(device_addr,page_data,216);
}

void iic_writebytes(uint8_t device_addr,uint8_t *data,uint8_t len)
{
	port_i2c_send( device_addr,data,len+1);
}

void port_i2c_send(uint8_t addr,uint8_t *p_data, uint8_t length)
{
	#if (SOC_TYPE ==NRF_52832)

	#elif (SOC_TYPE ==NRF_52840)
	
	am_i2c_send_data( addr,  p_data,length, 0 );
	
		#else
	#endif
}

void am_i2c_send_data(uint8_t addr,uint8_t const * p_data, uint8_t length, bool no_stop)
{
    ret_code_t err_code;
	
    err_code = nrf_drv_twi_tx(&m_twi, addr, p_data, length, no_stop);
    APP_ERROR_CHECK(err_code);
    while (m_xfer_done == false);	
	m_xfer_done = false;

}



when i comment the code 

disp_frame_data( led_data,/*disp_control.disp_page->lightness*/10);

and replace by the code 

port_delay_ms(24);




void port_delay_ms(uint32_t ms)
{
#if (SOC_TYPE ==NRF_52832)
	nrf_delay_ms( ms );
	
#elif (SOC_TYPE ==NRF_52840)
		nrf_delay_ms( ms );
	
#endif
}

the problem will not occur.

so i dont konw if the twi cant send data frequency ? and what should i do to slove this problem?

Parents
  • Hi,

    From the location of the error, it looks like you are using the app_timer with the application scheduler library (APP_TIMER_CONFIG_USE_SCHEDULER). Most likely the frequent transfers are causing the application to not process the scheduler queue fast enough, causing the NO_MEM error when the scheduler queue is full. You could try increasing the scheduler queue size in the scheduler initialization (second parameter to APP_SCHED_INIT()).

    It may also be a better option to push the interrupt handling to the scheduler, to process it in the way that the events come in. That way, the lengthy interrupt handler will not prevent other events from being handled. See the application scheduler tutorial for more details.

    Best regards,
    Jørgen 

  • Is disp_frame_data called from interrupt context? Does this function start any timers? Replacing it with a delay command does not necessarily cause the application to behave in the same way. The delay will only stall the CPU in the context it is currently running, higher priority tasks will still be running. It is hard to say exactly what happens in your application without seeing the full project.

    Did you try increasing the scheduler queue size? Did it help?

Reply
  • Is disp_frame_data called from interrupt context? Does this function start any timers? Replacing it with a delay command does not necessarily cause the application to behave in the same way. The delay will only stall the CPU in the context it is currently running, higher priority tasks will still be running. It is hard to say exactly what happens in your application without seeing the full project.

    Did you try increasing the scheduler queue size? Did it help?

Children
No Data
Related