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;
    				}				
    }
Parents
  • Hi

    The problem is that you are being interrupted by the BLE stack in your while loop (when waiting for the TIMER2 event). In general it is not a good idea to base the system on while loops like this, it would be better to use the PPI to have TIMER2 turn on and off the carrier (TIMER1) in the background, so that BLE interrupts will not affect you.

    I decided to make a small example of my own to demonstrate this:
    ble_app_uart_IR.zip

    I chose to use a slightly different approach. Instead of using TIMER2 as a timer, I use it as a counter, and count the number of pulses from the carrier before turning it on and off.

    The API is comparable to yours I believe. You just provide the library a list of 16-bit values, each storing the number of microseconds the carrier should be on and off. To implement specific IR protocols you have to fill in the buffer correctly.

    The example is based off of ble_app_uart, and will output an IR version of the first UART byte sent to the nRF51 on P0.04
    The GPIO used is configured when calling the init function. All other parameters are configured in the ir_lib.h file (such as the frequency of the carrier).

    Best regards
    Torbjørn

  • Hi Ovrebekk, can I run this example on nrf52832 ? I have a PCA10040 development board.

  • Hi

    The example was written for the nRF51x22 only, but the ir_lib.c/h files should work fine on the nRF52832 as well (they just haven't been tested). 

    If you want to try the code out on the nRF52 I suggest you start out with an example written for the nRF52832, and add the ir_lib.c and ir_lib.h files afterwards. Trying to migrate the entire example to the nRF52 is likely to be more work. 

    Best regards
    Torbjørn

  • Hi , thanks for the IR driver and it helps a lot . But now I have a question , how can I send out the IR data without  IR carrier , like the data below :

    12,5076,12,7204,12,5076,12,7204,12,5076,12,5076,12,7204,12,14716

    The 'mark' data is small , so it has no carrier , but I don't know how to change the driver .   

  • 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

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

Related