Implementing infrared functions on UART0 with FRDM-KE02Z platform.

cancel
Showing results for 
Search instead for 
Did you mean: 

Implementing infrared functions on UART0 with FRDM-KE02Z platform.

No ratings

Implementing infrared functions on UART0 with FRDM-KE02Z platform.

This document shows the implementation of the infrared on the UART0 using the FRDM-KE02Z platform.

The FRDM-KE02Z platform is a developing platform for rapid prototyping. The board has a MKE02Z64VQH2 MCU a Kinetis E series MCU which is the first 5-Volt MCU built on the ARM Cortex-M0+ core. You can check the evaluation board in the Freescale’s webpage (FRDM-KE02Z: Kinetis E Series Freedom Development Platform)

The Freedom Board has a lot of great features and one of this is an IrDA transmitter and receiver on it. Check this out!

infrared on board.png

One of the features of the MCU is that the UART0 module can implement Infrared functions just following some tricks (MCU-magic tricks). According to the Reference Manual (Document Number: MKE02Z64M20SF0RM) this tricks are:

     UART0_TX modulation:

    • UART0_TX output can be modulated by FTM0 channel 0 PWM output

     UART0_RX Tag:

    • UART0_RX input can be tagged to FTM0 channel 1 or filtered by ACMP0 module

For this example we are going to use the ACMP0 module to implement the UART0_RX functionality.

Note1: The Core is configured to run at the maximum frequency: 20 Mhz

Note2: Refer to the reference manual document for more information about the registers.


Configuring the FTM0.

The next lines show the configuration of the FTM0; the module is configured with a Frequency of 38 KHz which is the ideal frequency for an infrared led. The FTM0_CH0 is in Edge_Aligned PWM mode (EPWM).

    

     #define IR_FREQUENCY       38000 //hz

     #define FTM0_CLOCK                BUS_CLK_HZ

     #define FTM0_MOD_VALUE            FTM0_CLOCK/IR_FREQUENCY

     #define FTM0_C0V_VALUE            FTM0_MOD_VALUE/2

     void FTM0CH0_Init( void )

     {

       SIM_SCGC |= SIM_SCGC_FTM0_MASK;

            // Init FTM0 to PWM output,frequency is 38khz

       FTM0_MOD= FTM0_MOD_VALUE;

       FTM0_C0SC = 0x28;

       FTM0_C0V = FTM0_C0V_VALUE;

       FTM0_SC = 0x08; // bus clock divide by 2

     }

With this we accomplish the UART0_TX modulation through a PWM on the FTM0_CH0.

Configuring the ACMP0.

The configuration of the ACMP0 is using a DAC and allowing the ACMP0 can be driven by an analog input.

     void ACMP_Init ( void )

     {

       SIM_SCGC |= SIM_SCGC_ACMP0_MASK;

       ACMP0_C1 |= ACMP_C1_DACEN_MASK |

                  ACMP_C1_DACREF_MASK|

                  ACMP_C1_DACVAL(21);    // enable DAC

       ACMP0_C0 |= ACMP_C0_ACPSEL(0x03)|

                           ACMP_C0_ACNSEL(0x01);

       ACMP0_C2 |= ACMP_C2_ACIPE(0x02);  // enable ACMP1 connect to PIN

       ACMP0_CS |= ACMP_CS_ACE_MASK;     // enable ACMP          

     }


With this we have now implemented the UART0_RX.

   

IrDA initialization.

Now the important thing is to initialize the UART0 to work together with these tricks and implement the irDA functions.

Basically we initialize the UART0 like when we use normal serial communication (this is not the topic of this post, refer to the project to see the UART_init function) and we write to the most important registers:

  

     SIM_SOPT |= SIM_SOPT_RXDFE_MASK;

    • UART0_RX input signal is filtered by ACMP, then injected to UART0.

     SIM_SOPT |= SIM_SOPT_TXDME_MASK;

    • UART0_TX output is modulated by FTM0 channel 0 before mapped to pinout.

The configuration is as follows:

     void IrDA_Init( void )

     {

// initialize UART0, 2400 baudrate

       UART_init(UART0_BASE_PTR,BUS_CLK_HZ/1000,2400);

    

            // clear RDRF flag

       UART0_S1 |= UART_S1_RDRF_MASK;

    

            // initialize FTM0CH1 as 38k PWM output

       FTM0CH0_Init();

        

            // enable ACMP

       ACMP_Init();

SIM_SOPT |= SIM_SOPT_RXDFE_MASK;  //UART0_RX input signal is filtered by ACMP, then injected to UART0.

       UART0_S2 &= ~UART_S2_RXINV_MASK;  //inverse data input

SIM_SOPT |= SIM_SOPT_TXDME_MASK;  //UART0_TX output is modulated by FTM0 channel 0 before mapped to pinout.

     }

With the irDA initialization we got the infrared features on the UART0.

Philosophy of the Example

In the attachments of this post you can find the example which shows the use of these functions in a basic application; the project was compiled in CodeWarrior 10.6 and the philosophy is:

Slide1.JPG

I hope that the information presented on this document could be useful for you. Thank you!

Best Regards!

Attachments
Comments

Hello Sanchez,

          A good post indeed. But, I was wondering what might be the communication pattern? Is it a standard 3/16th bit width communication or the modulated Tx waveform looks different altogether? Couldn't capture on oscilloscope as the FTM is running continuously. Is the modulated waveform similar to the one attached?HT32F125x_IrDA_TimingDiagram.png

I am trying this with the TWR-K60N512 KIT, I can receive interrupts on UART0_Rx through Comparator from a TV remote signal, but not from the Tx pin although checking with a smartphone camera, the Tx IR signal is going on. The code is as follows:

#include "types.h"
#include "infrared.h"
#define IR_FREQUENCY    38000
#define FTM1_CLOCK        750000
#define FTM1_MOD_VALUE    FTM1_CLOCK/IR_FREQUENCY
#define FTM1_C0V_VALUE            FTM1_MOD_VALUE/2
void init_infrared(void){
    //initialize uart0 as infrared port through CMP0
    init_uart0();
    //initialize Comparator
    init_cmp0();
    //initialize the Flex timer
    init_ftm();
}
void init_uart(UART_MemMapPtr uartch, int sysclk, int baud){
    uint16_t ubd, temp, brfa;
   //disable Tx and Rx during setup
    UART_C2_REG(uartch) &= ~(UART_C2_TE_MASK | UART_C2_RE_MASK );
    /* Configure the UART for 8-bit mode, no parity */
    /* We need all default settings, so entire register is cleared */
    UART_C1_REG(uartch) = 0;
    /* Calculate baud settings */
    ubd = (uint16_t)((sysclk*1000)/(baud * 16));
    /* Save off the current value of the UARTx_BDH except for the SBR */
    temp = UART_BDH_REG(uartch) & ~(UART_BDH_SBR(0x1F));
    UART_BDH_REG(uartch) = temp | UART_BDH_SBR(((ubd & 0x1F00) >> 8));
    UART_BDL_REG(uartch) = (uint8_t)(ubd & UART_BDL_SBR_MASK);
    /* Determine if a fractional divider is needed to get closer to the baud rate */
    brfa = (((sysclk*32000)/(baud * 16)) - (ubd * 32));
    /* Save off the current value of the UARTx_C4 register except for the BRFA */
    temp = UART_C4_REG(uartch) & ~(UART_C4_BRFA(0x1F));
    UART_C4_REG(uartch) = temp | UART_C4_BRFA(brfa);
    // enable the reciever interrupts
    UART_C2_REG(uartch) |= UART_C2_RIE_MASK;
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
void init_uart0(void){
    //Gate clock to uart0
      SIM_SCGC4 |= SIM_SCGC4_UART0_MASK;
    init_uart(UART0_BASE_PTR,96000,2400);//core clock is 96Mhz=96000Khz
    //enable IR encoding and decoding
    UART0_IR |= UART_IR_IREN_MASK;
    UART0_IR |= UART_IR_TNP(0x0);//narrow pulse 3/16 of baudrate
    //System integration to route UART0_RX to CMP0
    SIM_SOPT5 |= SIM_SOPT5_UART0RXSRC(01);//CMP0 as source of UART0_RX
    SIM_SOPT5 |= SIM_SOPT5_UART0TXSRC(01);//Tx pin modulated with FTM1 channel0 output
    SIM_SOPT2 |= SIM_SOPT2_CMTUARTPAD_MASK;//select dual pad drive strength for UART0_TX
    //Enable receiver and transmitter
    UART0_C2 |= UART_C2_RE_MASK;
    UART0_C2 |= UART_C2_TE_MASK;
    // configure Nested Vector Interrupt Controller: clear pending and set enable
    NVICICPR1 |= interrupt_mask(1,INT_UART0_RX_TX);
    NVICISER1 |= interrupt_mask(1,INT_UART0_RX_TX);
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
//UART0 brief interrupt handler
void UART0_RX_TX_IRQHandler(){
    if((UART0_S1 & UART_S1_RDRF_MASK)==UART_S1_RDRF_MASK){
        byte2 = (uint8_t)UART0_D;
        data_available2=1;
    }
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
//FTM1 initialization, used to modulate UART0_TX
void init_ftm(void){
    SIM_SCGC6 |= SIM_SCGC6_FTM1_MASK;//gate the clock
    FTM1_SC |= FTM_SC_CLKS(01);//system core clock as clock source
    FTM1_SC |= FTM_SC_PS(7);//divide system clock by 128 = 750Khz
    FTM1_MODE |= FTM_MODE_WPDIS_MASK;//disable write protect
    FTM1_MOD |= FTM_MOD_MOD(FTM1_MOD_VALUE);//modulo value
    FTM1_C0SC = 0x28;//edge-aligned PWM
    FTM1_C0V = FTM1_C0V_VALUE;
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
void init_cmp0(void){
    //gate the clock to CMP
    SIM_SCGC4 |= SIM_SCGC4_CMP_MASK;
    //disable comparator while configuring
    CMP0_CR1 &= ~(CMP_CR1_OPE_MASK | CMP_CR1_EN_MASK);
    //Configure and enable the Comparator's DAC for reference voltage
    CMP0_DACCR |= CMP_DACCR_VRSEL_MASK;//supply voltage select is 1 for Vin2
    CMP0_DACCR |= CMP_DACCR_VOSEL(0x0F);//Output voltage select is (Vin/64)*VOSEL+1 = Vin * 0.5 for a high(1)
    CMP0_DACCR |= CMP_DACCR_DACEN_MASK;
    //enable PMUX and MMUX
    CMP0_MUXCR |= CMP_MUXCR_PEN_MASK | CMP_MUXCR_MEN_MASK;
    //select IN0 for PMUX(positive side) and DACOUT i.e channel 7 as MMUX(minus side)
    //          |\
    //    IN0---|+\
    //          |  \______CMP_OUT
    //          |  /
    // DACout---|-/
    //          |/
    //         COMPARATOR
    //
    CMP0_MUXCR |= CMP_MUXCR_PSEL(0);
    CMP0_MUXCR |= CMP_MUXCR_MSEL(7);
    //set 0 samples per measurement
    CMP0_CR0 |= CMP_CR0_FILTER_CNT(0x0);//disable filter
    CMP0_CR1 |= CMP_CR1_COS_MASK;//unfiltered output
    CMP0_CR1 |= CMP_CR1_INV_MASK;//invert output
    //enable comparator and the output pin
    CMP0_CR1 |= (CMP_CR1_OPE_MASK | CMP_CR1_EN_MASK);
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

I think I am missing some information on how the modulation actually works. Could you please explain a little further on the actual protocol, how the timing diagrams look like, how do we demodulate, where are the UART settings for demodulation, i can see how we modulate with the FTM, but not how we are actually demodulating the received signal. Is it by sampling the CMP input?

BlackNight‌ you have any ideas?

I got it to work without FTM modulation, just with the 3/16 narrow pulse. UART0 configured with 2400 baudrate and inverted RX, CMP DAC Output voltage select is (Vin/64)*31+1 = VDD(3.3v) * 0.5 = 1.65V for a high(1), supply voltage select is 1 for Vin2 which is VDD (3.3v). The trick is to configure the Comparator properly with a good reference voltage on the inverting input. I did not configure any sampling. Next I will try with FTM modulation, only I dont know how exactly to demodulate on the comparator end using the sampling feature.

I figured out what was the problem. The TWR-K60 has a different IR receiver filter with R=1KOhm and C=0.1uF, which passes frequencies less than 1.6KHz compared to the FRDM-KE02Z which has R=1KOhm and C=1000PF, which will passes frequencies less than 160KHz, hence 38KHz is OK for that board. 38KHz wont work with TWR-K60N512 because it wiIR_connection.pngll be blocked by the filter. I set the UART0 baud lower to 1400 and the FTM1 frequency to 1.5KHz and it works like a charm! I compared the two user manuals :-)

Formula:

fc = 1/(2*pi*Τ) = 1/(2pi*RC); where R=1000Ohms, C=0.1*10^-6Farads

fc = 1.6KHz

Version history
Revision #:
1 of 1
Last update:
‎06-05-2014 02:33 PM
Updated by: