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

Infrared send driver time length is not correct sometimes, why ?

I use example ble_app_uart, SoftDevice sdk 6.2.1, when receive data from bluetooth, then drive IO pin 18 to send infrared wave. received data is Infrared raw formate, which means IO output pin send wave time length (micro second), the odd data is 'mark' time length, the even data is 'space' time length. receive data is:

Blockquote

8976 4556 600 1696 612 1688 608 540
604 544 608 540 604 544 600 1700
608 1688 608 544 600 544 608 540
604 1696 600 1700 600 548 604 544
600 1700 608 544 608 540 604 544
612

Blockquote

I call sendRaw function below to send infrared wave,The forty one data length is 612 us,however, I capture the wave time length by logic analyzer, result is 1380 us, other data is correct,why this happed, and how to fix it ? Or is there any other infrared send driver ? Thank you ! image description

below is the driver using time 1 and timer 2(time 1 to generate carrier, timer 2 to control time length)

     static   void timer_delay(volatile uint32_t usecond){
    	 //delay for usecond
    
        NRF_TIMER2->TASKS_CLEAR = 1;
        NRF_TIMER2->PRESCALER =7;                  
        NRF_TIMER2->MODE      = TIMER_MODE_MODE_Timer;
        NRF_TIMER2->BITMODE   = TIMER_BITMODE_BITMODE_16Bit;
    	NRF_TIMER2->CC[0]     = (usecond>>3);
        NRF_TIMER2->TASKS_START=1;
    		
        while(NRF_TIMER2->EVENTS_COMPARE[0] == 0)
    	  {
    	   //wait 
    	  }	
    	  NRF_TIMER2->EVENTS_COMPARE[0]=0;
    
    	  NRF_TIMER2->TASKS_SHUTDOWN=1;
    }
    
   static  void Mark(uint32_t time){

      // send carrier

        nrf_gpio_cfg_output(GPIO_OUTPUT_PIN_NUMBER);
    	nrf_gpiote_task_config(3, GPIO_OUTPUT_PIN_NUMBER, \
                               NRF_GPIOTE_POLARITY_TOGGLE, GPIOTE_CONFIG_OUTINIT_Low);
       
    	  // Clear TIMER1
        NRF_TIMER1->TASKS_CLEAR = 1;
        NRF_TIMER1->PRESCALER =4;
        NRF_TIMER1->CC[0]     =26;    
        NRF_TIMER1->CC[1]     = 9; 
        NRF_TIMER1->MODE      = TIMER_MODE_MODE_Timer;
        NRF_TIMER1->BITMODE   = TIMER_BITMODE_BITMODE_16Bit;
        NRF_TIMER1->SHORTS    = (TIMER_SHORTS_COMPARE0_CLEAR_Enabled <<    TIMER_SHORTS_COMPARE0_CLEAR_Pos);
    	NRF_TIMER1->TASKS_START = 1;
    	timer_delay(time);
    	
    	  NRF_TIMER1->TASKS_SHUTDOWN = 1;
    	  NRF_GPIOTE->CONFIG[3] = (GPIOTE_CONFIG_MODE_Disabled   << GPIOTE_CONFIG_MODE_Pos);
       	NRF_GPIO->OUTCLR = (1UL << GPIO_OUTPUT_PIN_NUMBER);
    }
    
      


      static void sendRaw(volatile uint16_t buf[], int len, int hz)
    {
       // send driver
    
      for (int i = 0; i < len; i++) {
        if (i &1) {
            timer_delay(buf[i]);
        } 
        else {
            Mark(buf[i]);
        }
      }
    }

    void gpiote_init_Midea(){ 
        // init gpiote 
    		nrf_gpio_cfg_output(GPIO_OUTPUT_PIN_NUMBER);
    
    		nrf_gpiote_task_config(3, GPIO_OUTPUT_PIN_NUMBER, \
                               NRF_GPIOTE_POLARITY_TOGGLE, GPIOTE_CONFIG_OUTINIT_Low);
    		
    }

    void ppi_init_Midea(){
         //init ppi
		ppi_enable_channel(4,&(NRF_TIMER1->EVENTS_COMPARE[0]),&(NRF_GPIOTE->TASKS_OUT[3]));
		ppi_enable_channel(5,&(NRF_TIMER1->EVENTS_COMPARE[1]),&(NRF_GPIOTE->TASKS_OUT[3]));
	}

        static void ppi_enable_channel(uint32_t ch_num, volatile uint32_t *event_ptr, volatile uint32_t *task_ptr)
    {
       uint32_t err_code;
       uint32_t error;
      err_code =  sd_ppi_channel_assign(ch_num, event_ptr, task_ptr);
    	 if( err_code != NRF_SUCCESS ){
    					error = err_code;
    				}
      err_code =  sd_ppi_channel_enable_set(1 << ch_num);
    				if( err_code != NRF_SUCCESS ){
    					error = err_code;
    				}				
    }
  • Hi

    Are you saying you are not going to use any carrier at all?

    In other words, you just want the output to be off for 12us, on for 5076us, off for 12us, on for 7204us and so forth?

    Best regards
    Torbjørn

  •  I want the output to be on for 12us, off for 5076us, on for 12us, off for 7204us and so forth, the last off time can 

    ignore(because at the end the driver is off, it takes no effect) .

     It is this IR code feature. Can you tell me how to change the  driver code ? 

  • Hi

    In this case the IR example is overkill, and it's probably easier to implement this functionality from the ground up rather than using the IR example. 

    If you don't need a carrier pulse you can set up everything with a single timer. Use 4 of the compare registers of the timer to toggle the GPIOTE at different points in time, and update the compare registers as you go along. Each compare event must be connected to the GPIOTE toggle task over PPI, and the GPIOTE must be configured to set the pin you want. 

    If you set the timer prescaler to 4 then it will run at a 1MHz frequency, which means you can set the compare registers based on how many microseconds of delay you need. 

    Best regards
    Torbjørn

  • Thanks for the example code.  It helps our project tremendously.

    As a followup to your example project, we are trying stop all gpiote, timers and PPIs after we sent the IR signal.  We do such cleanup inside the interrupt function IR_CARRIER_COUNTER_IRQHandler() when m_bits_remaining==0.  With PPIs, the code is crashing in some assembly code whenever I try to call either of the following functions:

        sd_ppi_group_task_disable(IR_PPI_GROUP);
        sd_ppi_channel_enable_clr(1 << IR_PPI_CH_A | 1 << IR_PPI_CH_B | 1 << IR_PPI_CH_C | 1 << IR_PPI_CH_D | 1 << IR_PPI_CH_E);   

    Is it because I can't do this inside a IRQ?   How can we solve this?

  • Hi 

    It sounds like a interrupt priority issue. 

    On the nRF52 series you have to be in IRQ priority 6 or 7 to be able to call into the SoftDevice, any higher priority (lower number) and you will get an assert. 

    Alternatively you would have to defer the SoftDevice calls to the main context, by setting a flag in the interrupt that you later check in your main loop, or by using the app_scheduler module. 

    If you have more questions on this please open a new devzone ticket, the system is not really set up to handle multiple different questions in each case. You can refer to this case and mention my name if you want, and it will assigned to me if I'm available. 

    Best regards
    Torbjørn

Related