Arm Community
Arm Community
  • Site
  • User
  • Site
  • Search
  • User
  • Groups
    • Arm Research
    • DesignStart
    • Education Hub
    • Graphics and Gaming
    • High Performance Computing
    • Innovation
    • Multimedia
    • Open Source Software and Platforms
    • Physical
    • Processors
    • Security
    • System
    • Software Tools
    • TrustZone for Armv8-M
    • 中文社区
  • Blog
    • Artificial Intelligence
    • Automotive
    • Healthcare
    • HPC
    • Infrastructure
    • Innovation
    • Internet of Things
    • Machine Learning
    • Mobile
    • Smart Homes
    • Wearables
  • Forums
    • All developer forums
    • IP Product forums
    • Tool & Software forums
    • Pelion IoT Platform
  • Activity
  • Support
    • Open a support case
    • Documentation
    • Downloads
    • Training
    • Arm Approved program
    • Arm Design Reviews
  • More
  • Cancel
System
  • Developer Community
  • IP Products
  • System
  • Jump...
  • Cancel
System
Embedded blog Infra-Red Code Learning And Repeating For The Batteryless Energy Harvesting Remote Control
  • Blogs
  • Forums
  • Videos & Files
  • Mentions
  • Sub-Groups
  • Tags
  • Jump...
  • Cancel
  • New
More blogs in System
  • Embedded blog

  • SoC Design blog

Tags
  • energy-harvesting
  • remote-control
  • Cortex-M0+
  • infra-red
Actions
  • RSS
  • More
  • Cancel
Related blog posts
Related forum threads

Infra-Red Code Learning And Repeating For The Batteryless Energy Harvesting Remote Control

Elliott Smith
Elliott Smith
December 2, 2013

The Batteryless Energy Harvesting Remote Control can be taught Infra-red codes and then repeat them. This post explains the way in which this was achieved.

Learning Infrared codes

The circuit uses an Infra-red demodulator. The commands from an existing device are fed into the demodulator. The output of the demodulator is connected to an input pin on the MCU. The software is rather simple; it “guesses” which protocol is being sent. This is done by measuring the mark and space time of the received signal and applying a set of rules to determine the protocol. The flowchart below outlines the basic process.

The code utilizes the programmable interval timer (PIC) to determine the on and off time for the sample.

        PIT_configure();
        PIT_setInterupt(1);    
        PIT_resetVal();

        while(irDetector());                                                //wait until an IR signal is detected.

        PIT_start();                                                        //Start the programmable interval timer.

                do
                {
                    while(irDetector())                                          //Start with on time
                    {
                        if(PIT_readValS() > 5) break;                               //Break after 5 seconds of not changing.
                    }

                    diff_times[i] = PIT_readVal();                                //Store current counter value.
                    if(PIT_readValS() > 5) break;
                    PIT_resetVal();                                               //Reset to 0.
                    if(diff_times[i] > largest) largest = diff_times[i];          //Set new largest time where appropriate   
                    i++;

                    while(!irDetector())                                                                                    //Repeat for off time
                    {
                        if(PIT_readValS() > 5) break;
                    }

                    diff_times[i] = PIT_readVal();
                    if(PIT_readValS() > 5) break;
                    PIT_resetVal();
                    if(diff_times[i] > largest) largest = diff_times[i];
                    i++;


                } while(i < SAMPLE_LENGTH);
                num_samples = i;
                PIT_setInterupt(0);
                PIT_stop();
                PIT_powerDown();


The time of the initial high and initial low is then determined, as is the mark and space time:

    j=0;

        for(i=0;i<num_samples;i++)
                {
                    if(diff_times[i] >= (largest-(largest/100)))                
                        {
                            start_locat[j] = i;
                            if(j>0)
                            {
                                temp+= (start_locat[j] - start_locat[j-1]);
                            }
                            j++;
                            if(j>4) break;
                        }
                }

                    average_bits = start_locat[0]/2;
                    start_time_high = diff_times[1];                                   //determine the initial time high
                    start_time_low = diff_times[2];                                    //determine the initial time low 
                    temp = 5;
                    j = 25;
                    mark_time = largest;
                    for(i=temp;i<=j;i++)
                    {
                        if(diff_times[i] < mark_time) mark_time = diff_times[i];         //determine mark time.
                        if(diff_times[i] > space_time) space_time = diff_times[i];       //determine space time.
                    }


A different decoding algorithm is required for each type of protocol. The data is decoded by looking at each time difference and comparing it with the documented mark space ratios for the protocol determined. Some protocols are based on Manchester coding in which a slightly different decoding process is required. Example of decoding algorithms can be seen below:

/*----------------------RC-5 DECODE---------------------------------*/
                if((start_time_high >= 700 && start_time_high <= 950)
                    &&(start_time_low >= 700 && start_time_low <= 950)
                    &&(mark_time >= 700 && mark_time <= 950)
                    )
                {
                        device_learnt = RC5;
                    mark_time = 889;

                    space_time = 1778;

                    j=1;                    
                                        j=0;
                    for(i=1;i<start_locat[0];i++)
                    {
                        if(diff_times[i] >= (700) && diff_times[i] <= (950))
                        {
                            data_code |= (0x1<<j);
                            j++;
                        }

                        else if(diff_times[i] >= (1400) && diff_times[i] <= (1900))
                        {
                            data_code |= (0x0<<j);
                            j++;
                        }

                        else
                        {
                            break;
                        }
                    }

                }

/*----------------------NEC/LG/JVC DECODE---------------------------------*/
                else if((start_time_high >= 8000 && start_time_high <= 10000)
                    &&(start_time_low >= 1500 && start_time_low <= 5000)
                    &&(mark_time >= 450 && mark_time <= 600)
                    &&(space_time >= 1400 && space_time <= 2500))
                {
                        
                    
                        mark_time = 560;
                        space_time = 1690;
                    
                    j=0;
                    for(i=4;i<67;i+=2)
                    {
                        if(diff_times[i] >= (mark_time-(mark_time*0.25)) && diff_times[i] <= (mark_time+(mark_time*0.25)))
                        {
                            data_code |= (0x1<<j);
                            j++;
                        }
                        else if(diff_times[i] >= (space_time-(space_time*0.25)) && diff_times[i] <= (space_time+(space_time*0.25)))
                        {
                            data_code |= (0x0<<j);
                            j++;
                        }
                        else
                        {
                            break;
                        }
                    }
                    if(j==16) device_learnt = JVC;
                    else device_learnt = NEC;
                    
                }
                    
/*----------------------SONY DECODE---------------------------------*/
            else if((start_time_high >= 2300 && start_time_high <= 2500)
                    &&(start_time_low >= 500 && start_time_low <= 700)
                    &&(mark_time >= 500 && mark_time <= 700)
                    &&(space_time >= 1100 && space_time <= 1300))
                {
                        
                    
                        mark_time = 600;
                        space_time = 1200;
                    
                    j=0;
                    for(i=start_locat[0]+3;j<20;i+=2)
                    {
                        if(diff_times[i] >= (mark_time-(mark_time*0.25)) && diff_times[i] <= (mark_time+(mark_time*0.25)))
                        {
                            data_code |= (0x1<<j);
                            j++;
                        }
                        else if(diff_times[i] >= (space_time-(space_time*0.25)) && diff_times[i] <= (space_time+(space_time*0.25)))
                        {
                            data_code |= (0x0<<j);
                            j++;
                        }
                        else
                        {
                            break;
                        }
                    }
                    
                    if(j==12) device_learnt = SONY_12;
                    else if(j==15) device_learnt = SONY_15;
                    else device_learnt = SONY_20;
                    
                }
                
/*----------------------SAMSUNG DECODE---------------------------------*/
                else if((start_time_high >= 4400 && start_time_high <= 4600)
                    &&(start_time_low >= 4400 && start_time_low <= 4600)
                    &&(mark_time >= 450 && mark_time <= 550)
                    &&(space_time >= 1500 && space_time <= 1700))
                {
                        device_learnt = SAMSUNG;

                    mark_time = 560;
                    space_time = 1690;
                    j=0;
                    for(i=start_locat[0]+4;j<32;i+=2)
                    {
                        if(diff_times[i] >= (mark_time-(mark_time*0.25)) && diff_times[i] <= (mark_time+(mark_time*0.25)))
                        {
                            data_code |= (0x1<<j);
                            j++;
                        }
                        else if(diff_times[i] >= (space_time-(space_time*0.25)) && diff_times[i] <= (space_time+(space_time*0.25)))
                        {
                            data_code |= (0x0<<j);
                            j++;
                        }
                        else
                        {
                            break;
                        }
                    }
                    
                }
                else 
                {
                    device_learnt = UNKNOWN;
                }



Replaying learned codes

To replay the learned Infra-red data, an IR LED, which was connected to a PWM pin on the MCU, was used. Because the protocol has been determined, we can look up the correct mark space times and start conditions that need to be transmitted. This has the advantage of reducing any error encountered when learning the infra-red codes.

/*---------------REPLAY NEC/LG-----------------*/
if(command.device_id==NEC)
{    
    PIT_resetVal();
    PIT_start();
    PWM_for_time(9000);
    Delay_usRun(4500);
    for(i=0;i<32;i++)
    {
            PWM_for_time(560);
            bit_mask = 1 << i;
             bit = command.ir_code & bit_mask;
          bit >>= i;
        if(bit == 0x0) 
            {
                Delay_usRun(1690);
            }
        else if (bit == 0x1)
            {
                Delay_usRun(560);
            }

    }
    PWM_for_time(560);
    while(PIT_readVal() < 110000);
    
    for(i=0;i<5;i++)
    {        
        PIT_resetVal();
        PIT_start();
        PWM_for_time(9000);
        Delay_usRun(2250);
        PWM_for_time(560);
        while(PIT_readVal() < 110000);
    }
}

/*---------------REPLAY JVC-----------------*/
if(command.device_id==JVC)
{    
    PIT_resetVal();
    PIT_start();
    PWM_for_time(8400);
    Delay_usRun(4200);
    while(TSI_button_held())
    {
    for(i=0;i<16;i++)
    {
            PWM_for_time(526);
            bit_mask = 1 << i;
             bit = command.ir_code & bit_mask;
          bit >>= i;
        if(bit == 0x0) 
            {
                Delay_usRun(1574);
            }
        else if (bit == 0x1)
            {
                Delay_usRun(524);
            }

    }
    PWM_for_time(526);
    while(PIT_readVal() < 55000);
    PIT_resetVal();
    PIT_start();
    }
}


/*---------------REPLAY SAMSUNG-----------------*/
if(command.device_id==SAMSUNG)
{    
    PIT_resetVal();
    PIT_start();
    PWM_for_time(4500);
    Delay_usRun(4500);
    PWM_for_time(560);
    for(i=0;i<32;i++)
    {
            bit_mask = 1 << i;
             bit = command.ir_code & bit_mask;
          bit >>= i;
        if(bit == 0x0) 
            {
                Delay_usRun(1690);
            }
        else if (bit == 0x1)
            {
                Delay_usRun(560);
            }
        PWM_for_time(560);

    }
    while(PIT_readVal() < 108000);
}

/*-----------REPLAY RC5-----------------*/
if(command.device_id==RC5)
{    
    PIT_resetVal();
    PIT_start();
    j=0;
    for(i=0;j<27;i++)
    {
            bit_mask = 1 << i;
             bit = command.ir_code & bit_mask;
          bit >>= i;
        if(bit == 0x1) 
            {
                PWM_for_time(889);
                j++;
            }
        else if (bit == 0x0)
            {
                PWM_for_time(1778);
                j+=2;
            }
            
            i++;
            bit_mask = 1 << i;
             bit = command.ir_code & bit_mask;
          bit >>= i;
        if(bit == 0x1) 
            {
                Delay_usRun(889);
                j++;
                
            }
        else if (bit == 0x0)
            {
                Delay_usRun(1778);
                j+=2;
            }

    }
    while(PIT_readVal() < 114000);

}


The IR LED needs to be pulsed at 38KHz for the mark time and turned off for the space time. The way this was achieved is shown in the code below:

/*------------------------------------------------------------------------------
  PWM the IR led at 38Khz for a time given in us
 *------------------------------------------------------------------------------*/
/*__INLINE*/ void PWM_for_time(int time_us)
{
    uint32_t curTicks;
  curTicks = PIT_readVal();
  while ((PIT_readVal() - curTicks) < (time_us))
    {
        FPTD->PDOR |= (1UL << 7);
        Delay_usRun(11);
        FPTD->PDOR &= ~(1UL << 7);
        Delay_usRun(11);

    }
    FPTD->PDOR &= ~(1UL << 7);
}


The codes need to be stored in a more permanent place than RAM in case the remote control is powered off. Using EEPROM, which usually connects to the Microcontroller via I2C or SPI would have increased the power consumption of the circuit. Instead flash memory was used. Carrying out a procedure called in application programming allows you to save data into the flash memory. More information on writing data to flash can be found in Writing Data To Flash During Program Execution With The Freescale KL25z Series.


The next development step was Batteryless Energy Harvesting Remote Control Power Regulation With The ARM Cortex-M0+

Anonymous
Embedded blog
  • Embedded blog: Development of Arm based systems with Synopsys Virtual Prototyping: Anytime, Anywhere!

    Jason Andrews
    Jason Andrews
    Find out more about virtual prototyping from Synopsys as thousands of engineers around the world have been asked to work from home.
    • May 5, 2020
  • Embedded blog: Accelerating Innovation for Safety Systems with Arm Flexible Access

    Chet Babla
    Chet Babla
    Arm is proud to announce the addition of Arm Safety Packages for select IP within Arm Flexible Access, with the goal to make it easier for developers in the automotive and other safety-related industries…
    • February 19, 2020
  • Embedded blog: Functional Safety on Arm – Beyond Automotive

    Antonio Priore
    Antonio Priore
    Arm has moved a long way from the days where our only ‘safety’ requirement was to provide ECC or parity protections on CPU RAMs and we are now able to offer a number of System IP, GPUs, ISPs and NPUs as…
    • December 13, 2019