Kinetis Microcontrollers Knowledge Base

cancel
Showing results for 
Search instead for 
Did you mean: 

Kinetis Microcontrollers Knowledge Base

Discussions

Sort by:
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! 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: I hope that the information presented on this document could be useful for you. Thank you! Best Regards!
View full article
        在我们嵌入式工程应用中,中断作为最常用的异步手段是必不可少的,而且在一个应用程序中,一个中断往往是不够用的,多个中断混合使用甚至多级中断嵌套也经常会使用到,而这样就涉及到一个中断优先级的问题。         以我们最熟悉的Cortex-M系列为例,我们知道ARM从Cortex-M系列开始引入了NVIC的概念(Nested Vectors Interrupts Controller),即嵌套向量中断控制器,以它为核心通过一张中断向量表来控制系统中断功能,NVIC可以提供以下几个功能: 1)可嵌套中断支持; 2)向量中断支持; 3)动态优先级调整支持; 4)中断可屏蔽。         抛开其他不谈,这里我们只说说中断优先级的问题。我们知道NVIC的核心工作原理即是对一张中断向量表的维护上,其中M4最多支持240+16个中断向量,M0+则最多支持32+16个中断向量, 而这些中断向量默认的优先级则是 向量号越小的优先级越高 ,即从小到大,优先级是递减的。但是我们肯定不会满足于默认的状态(人往往不满足于约束,换句俗话说就是不喜欢按套路出牌,呵呵),而NVIC则恰恰提供了这种灵活性,即支持动态优先级调整,无论是M0+还是M4除了3个中断向量之外(复位、NMI和HardFault,他们的中断优先级为负数,它们3个的优先级是最高的且不可更改),其他中断向量都是可以动态调整的。         不过需要注意的是, 中断向量表的前16个为内核级中断,之后的为外部中断 ,而内核级中断和外部中断的优先级则是由两套不同的寄存器组来控制的,其中内核级中断由SCB_SHPRx寄存器来控制(M0+为SCB_SHPR[2:3],M4为SCB_SHPR[1:3]),外部中断则由NVIC_IPRx来控制(M0+为NVIC_IPR[0:7],M4为NVIC_IPR[0:59]),如下图所示: M0+中断优先级寄存器: M4中断优先级寄存器:         其中M4所支持的动态优先级范围为 0~15 (8位中只有高四位[7:4]才有效),而M0+所支持的动态优先级范围则为 0~3 (8位中只有高两位[7:6]才有效),而且秉承着号越小优先级越高的原则(0最高,15或3为最小) ,同时也间接解释了为什么复位(-3)、NMI(-2)和HardFault(-1)优先级最高的原因,很简单,人家都是负的了,谁还能比他们高,呵呵,而且这三位中复位优先级最高,NMI其次,HardFault最低(这个最低仅限于这三者)。 下面给出个ARM CMSIS库中关于M0+和M4中断优先级设置的API函数 NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) 实现供大家来参考: M0+: NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) {   if(IRQn < 0) {     SCB->SHP[_SHP_IDX(IRQn)] = (SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFF << _BIT_SHIFT(IRQn))) |         (((priority << (8 - __NVIC_PRIO_BITS)) & 0xFF) << _BIT_SHIFT(IRQn)); }  /* set Priority for Cortex-M  System Interrupts */   else {     NVIC->IP[_IP_IDX(IRQn)] = (NVIC->IP[_IP_IDX(IRQn)] & ~(0xFF << _BIT_SHIFT(IRQn))) |         (((priority << (8 - __NVIC_PRIO_BITS)) & 0xFF) << _BIT_SHIFT(IRQn)); }   /* set Priority for device specific Interrupts  */ } M4: void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) {   if(IRQn < 0) {     SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for Cortex-M  System Interrupts */   else {     NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff);    }        /* set Priority for device specific Interrupts  */ }
View full article
Using five channels from FTM2 module of the KE02 microcontroller included on the FRDM-KE02Z board for controlling a robotic arm powered by five servomotors. Each servomotor is controlled by a couple of buttons of a matrix keyboard, which is connected to eigth GPIOs. Interrupts are not used in this example. The code was generated and compiled on CodeWarrior for Microcontrollers v10.5.
View full article
作者 Sam Wang & River Liang    说明 , 本文对比 8 位 MCU 的位操作在系统升级到 M0+内核的MCU 后所带来的影响 , 可以作为客户对升级 MCU 时 , 对代码及 RAM 上资源的评估使用 . 一 ) 简单的 I/O 翻转对比 . 对比条件 :MCU 为 MC9S08PT 与 KE02, 开发平台 CW10.3                   1. 使用 PT 的代码如下 :          if (!PORT_PTAD_PTAD0){             PORT_PTAD_PTAD0=1;         } else {             PORT_PTAD_PTAD0=0;}       PT的 代码编译后占用 9 个 Byte 。                000002D4 000004   BRSET  0,PORT_PTAD,PORT_PTAD                000002D7 1000     BSET   0,PORT_PTAD                000002D9 202E     BRA    *+48       ;abs = 0x0309                000002DB 1100     BCLR   0,PORT_PTAD       2.KE是基于ARM的M0+内核,使用的代码如下                  if(GPIOA_PDOR & 0x1)                     { GPIOA_PCOR = 0x1;}                  else                     { GPIOA_PSOR = 0X1;}       编译后结果为                00000706:   ldr r3,[pc,#24]                00000708:   ldr r2,[r3,#0]                0000070a:   movs r3,#1                0000070c:   ands r3,r2                0000070e:   beq main+0x6c (0x718)       ; 0x00000718                00000710:   ldr r3,[pc,#12]                00000712:   movs r2,#1                00000714:   str r2,[r3,#8]                00000716:   b main+0x20 (0x6cc)       ; 0x000006cc                00000718:   ldr r3,[pc,#4]                0000071a:   movs r2,#1                0000071c:   str r2,[r3,#4]       这段M0+内核的代码编译后占用 24个Byte       3.KE系列是Freescale在M0+的基础上加入了位操作引擎BME,用以优化ARM内核的位操作性能,使用BME功能的代码如下                     #define PTA0_SET   (void) (*((volatile unsigned char *)(0x4C000000+(0<<21)+0xF004))) //?==0                                                       //LAS1      第 0 位        GPIOA_PSOR 地址的 A0-A19                     #define PTA0_CLR   (void)(*((volatile unsigned char *)(0x4C000000+(0<<21)+0xFF008)))                                                      //LAS1      第 0 位        GPIOA_PCOR 地址的 A0-A19                     #define PTA0                *((volatile unsigned char *)(0x50000000+(0<<23)+(0<<19)+0xF000))                                                     //UBFX           第 0 位     1 位            GPIOA_PDOR 地址的 A0-A18                if (!(PTA0))                     { PTA0_SET; }                else                     { PTA0_CLR;}           KE的BME代码编译结果如下:                    165                if (!(PTA0)){                 00000998:   ldr r3,[pc,#24]                0000099a:   ldrb r3,[r3,#0]                0000099c:   uxtb r3,r3                0000099e:   cmp r3,#0                000009a0:   bne RTC_IRQHandler+0x18 (0x9a8); 0x000009a8                  166                PTA0_SET;                                             //Using BME                000009a2:   ldr r3,[pc,#20]                000009a4:   ldrb r3,[r3,#0]                000009a6:   b RTC_IRQHandler+0x1c (0x9ac); 0x000009ac                  168                PTA0_CLR;      //Using FASTER GPIO                000009a8:   ldr r3,[pc,#16 ]                000009aa:   ldrb r3,[r3,#0]       代码编译后占用 20个Byte         4, CW里面有 设置可以优化C编译器,具体路径在Project->Proteries->C/C++ Build->Setting->GCC C Complier->Optimization           优化后 共用 16 个Byte                  165         if (!(PTA0)){                 0000091e:   ldr r3,[pc,#20]                00000920:   ldrb r3,[r3,#0]                00000922:   cmp r3,#0                00000924:   bne RTC_IRQHandler+0x12 (0x92a); 0x0000092a                  166                         PTA0_SET;                                             //Using BME                00000926:   ldr r3,[pc,#16]                00000928:   b RTC_IRQHandler+0x12 (0x92c); 0x0000092c                  168                         PTA0_CLR;      //Using FASTER GPIO                0000092a:   ldr r3,[pc,#16]                0000092c:   ldrb r3,[r3,#0]       5, 结果     如果单纯靠M0+内核访问寄存器, KE 代码的占用空间与 PT 的比为 24 :9        如果使用KE的BME功能, 代码与 PT 的比为 16:9(使用了BME)        在判断 Bit 时 , KE 使用代码与 PT 的比为 8:3        单单设置一个Bit时KE与PT代码占比为 4:2 因此在M0+等ARM核上进行位操作,其效率比8位单片机低,使用了BME功能后,可以有效提高位操作的性能。 二 ) 典型变量的位操作 . 对比条件 :MCU 为 MC9S08PT 与 KE02, 开发平台 CW10.3                测试代码 : if (xx&1){              xx&=0xFE;       } else {             xx|=1; }       1, 设置 XX 在 0 page 时 , 其与上面的 I/O 翻转结果一样 , 代码为 9 个 BYTES    2, 在 KE 中, 编译结果如下 , 设置优化前 , 需要 52 个 Bytes 的代码量 ,26 个执行周期 .                                                     if (xx&1){                00000a52:   ldr r3,[pc,#64]                00000a54:   ldrb r3,[r3,#0]                00000a56:   uxtb r3,r3                00000a58:   mov r2,r3                00000a5a:   movs r3,#1                00000a5c:   ands r3,r2                00000a5e:   uxtb r3,r3                00000a60:   cmp r3,#0                00000a62:   beq main+0x5a (0xa76)       ; 0x00000a76                     200                         xx&=0xFe;                00000a64:   ldr r3,[pc,#44]                00000a66:   ldrb r3,[r3,#0]                00000a68:   uxtb r3,r3                00000a6a:   movs r2,#1                00000a6c:   bics r3,r2                00000a6e:   uxtb r2,r3                00000a70:   ldr r3,[pc,#32]                00000a72:   strb r2,[r3,#0]                     203         }}                00000a74:   b main+0x28 (0xa44)       ; 0x00000a44                     202                         xx|=1;                00000a76:   ldr r3,[pc,#28]                00000a78:   ldrb r3,[r3,#0]                00000a7a:   uxtb r3,r3                00000a7c:   movs r2,#1                00000a7e:   orrs r3,r2                00000a80:   uxtb r2,r3                00000a82:   ldr r3,[pc,#16]                00000a84:   strb r2,[r3,#0]                     203         }}       3, 设置优化后 , 需要 22/20 个 Bytes 的代码量 ,11/10 个执行周期 .                ldr r3,[pc,#40]                     199         if (xx&1){                0000095e:   movs r2,#1                     197         xx++;                00000960:   ldrb r1,[r3,#0]                00000962:   adds r1,#1                00000964:   uxtb r1,r1                00000966:   strb r1,[r3,#0]                     199         if (xx&1){                00000968:   ldrb r1,[r3,#0]                0000096a:   tst r1,r2                0000096c:   beq main+0x34 (0x974)       ; 0x00000974                     200                         xx&=0xFe;                0000096e:   ldrb r1,[r3,#0]                00000970:   bics r1,r2                00000972:   b main+0x34 (0x978)       ; 0x00000978                     202                         xx|=1;                00000974:   ldrb r1,[r3,#0]                00000976:   orrs r1,r2                00000978:   strb r1,[r3,#0]                0000097a:   b main+0x20 (0x960)       ; 0x00000960 如果采用以空间换时间的话 , 其参考代码如下 .                 if (xx==0){                                 xx=1;                 }else{                                 xx=0;   }       4, 如考虑中断嵌套的话 , 还令需要 4 个 Byte 代码。       5, 结果 KE 使用代码与 PT 的比为至少为 20:9 。      在判断 Bit 时 , KE 使用代码与 PT 的比为 8:3 .       6, 使用 BYTE 替换 Bit, 编译结果 , 设置优化前 , 需要 22 个 BYTES.                     197         if (xx==0){                000009e8:   ldr r3,[pc,#44]                000009ea:   ldrb r3,[r3,#0]                000009ec:   cmp r3,#0                000009ee:   bne main+0x38 (0x9f8)       ; 0x000009f8                     198                         xx=1;                000009f0:   ldr r3,[pc,#36]                000009f2:   movs r2,#1                000009f4:   strb r2,[r3,#0]                000009f6:   b main+0x3e (0x9fe)       ; 0x000009fe                     200                         xx=0;                000009f8:   ldr r3,[pc,#28]                000009fa:   movs r2,#0                000009fc:   strb r2,[r3,#0]    7, 设置优化后 , 需要 16/14 个 BYTES 的代码量 .                     197         xx++;                0000095c:   ldr r3,[pc,#36]                     202                         xx=1;                0000095e:   movs r1,#1                     197         xx++;                00000960:   ldrb r0,[r3,#0]                00000962:   adds r0,#1                00000964:   uxtb r0,r0                00000966:   strb r0,[r3,#0]                     199         if (xx){                00000968:   ldrb r0,[r3,#0]                0000096a:   cmp r0,#0                0000096c:   beq main+0x32 (0x972)       ; 0x00000972                     200                         xx=0;                0000096e:   strb r2,[r3,#0]                00000970:   b main+0x20 (0x960)       ; 0x00000960                     202                         xx=1;                00000972:   strb r1,[r3,#0]                00000974:   b main+0x20 (0x960)       ; 0x00000960       8, 结果 , 在 RAM 的空间允许的情况下 , KE 使用代码与 PT 的比为至少为 12:9 . 三 ) 8 bit 变量加1       1,在PT中对8 bit 变量加 1, 只需要 4 个 BYTES .    24:                 XX++; 00000014 450000   LDHX   #XX       00000017 7C       INC    ,X       2,M0+ 的 8 bit 变量加 1, 设置优化前 , 需要 14 个 BYTES                     197         xx++;                00000a44:   ldr r3,[pc,#48]                00000a46:   ldrb r3,[r3,#0]                00000a48:   uxtb r3,r3                00000a4a:   adds r3,#1                00000a4c:   uxtb r2,r3                00000a4e:   ldr r3,[pc,#40]                00000a50:   strb r2,[r3,#0]       3,而如果使用优化设置,那么 要 12 个 BYTES                     197         xx++;                0000095c:   ldr r3,[pc,#36]                     202                         xx=1;                0000095e:   movs r1,#1                     197         xx++;                00000960:   ldrb r0,[r3,#0]                00000962:   adds r0,#1                00000964:   uxtb r0,r0                00000966:   strb r0,[r3,#0]       4, 结果 , 在8 bit 变量加 1时,KE 使用代码与 PT 的比为至少为 12:4,但这是32bitARM内核操作8bit变量都普遍存在效率变低的现象 。 四 ) 16 位 +8 位加法       1, 8 bit 编译结果 , 需要 8 个 BYTES .                0000008 320000    LDHX   xx                0000000B AF01     AIX    #1                0000000D 960000   STHX   xx       2, M0+ 编译结果 , 设置优化前 , 需要 10 个 BYTES .                00000a44:   ldr r3,[pc,#44]                00000a46:   ldr r3,[r3,#0]                00000a48:   adds r2,r3,#1                00000a4a:   ldr r3,[pc,#40]                00000a4c:   str r2,[r3,#0].       3, M0+ 编译结果 , 设置优化后 , 需要 8 个 BYTES .                0000095c:   ldr r3,[pc,#20]                0000095c:   ldr r3,[pc,#20]                0000095e:   ldr r2,[r3,#0]                00000960:   adds r2,#1                00000962:   str r2,[r3,#0]       4, 结果 , M0+在16位加法时能够达到8bit单片机的效率,结果相同 . 五 ) 结论     因此用户 在移植 PT( 或其它 8 bit MCU) 代码到 KE02 时 , 要选型时需要充分考虑客户原先代码具体运算情况,理论上存在使用KE后代码变大的情况.   但是使用KE等32bitM0+内核时可以在 16bit或以上的乘、加运算时获得更好的效率 ,占用更小的代码空间和运算时间。   另外 KE 对 GPIO 的控制寄存器比 PT 多了一些功能 , 可以一次操作多个 I/O, 是不错的功能 .
View full article