打印

如何在firmware中控制PSoC3 GPIO

[复制链接]
1847|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Go_PSoC|  楼主 | 2011-12-19 22:34 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
这个问题很多朋友都曾经关注过,这篇博文也有不少人推荐过,再次拿出来分享给大家。

[url=]Writing to a PSoC3 GPIO – Various options[/url]
By M Ganesh Raaja
Any microcontroller project will have the need to control a GPIO pin using a CPU.  Applications could be simple ones like switching On/Off an LED, a relay, a buzzer etc to complex ones like generating a software PWM, bit-banging I2C protocol etc.
There are many options to control a PSoC3 GPIO in firmware.  Let us take a look at some of these options and their pros and cons.
Option-1: Use Port in APIs
When a Digital Output Port component is placed in the project, the PSoC Creator generates API functions to control the port pin.  The function used to write to the pin is <Pin Name>_Write.  For example, for a Port Pin component named Out1,
Out1_Write(1);   // Set the pin
Out1_Write(0);  // Clear the pin

Pros: The advantage of using the API function is the ease of programming and portability.
Cons: The disadvantage of using this method is the high number of processor cycles taken to update the pin.    Following is the listing of the Output1_Write function.
; void Out1_Write(uint8 value)

    RSEG  ?PR?_Out1_Write?OUT1
_Out1_Write:
    USING    0
            ; SOURCE LINE # 34
    MOV      DPTR,#value?040
    MOV      A,R7
    MOVX     @DPTR,A
; {
            ; SOURCE LINE # 35
;     uint8 staticBits = Out1_DR & ~Out1_MASK;
            ; SOURCE LINE # 36
    MOV      DPTR,#05100H
    MOVX     A,@DPTR
    MOV      R7,A
    MOV      A,R7
    ANL      A,#0EFH
    MOV      R7,A
    MOV      DPTR,#staticBits?041
    MOV      A,R7
    MOVX     @DPTR,A
;     Out1_DR = staticBits | ((value << Out1_SHIFT) & Out1_MASK);
            ; SOURCE LINE # 37
    MOV      DPTR,#value?040
    MOVX     A,@DPTR
    MOV      R7,A
    MOV      A,R7
    SWAP     A
    ANL      A,#0F0H
    MOV      R7,A
    MOV      A,R7
    ANL      A,#010H
    MOV      R7,A
    MOV      DPTR,#staticBits?041
    MOVX     A,@DPTR
    MOV      R6,A
    MOV      A,R7
    ORL      A,R6
    MOV      R7,A
    MOV      DPTR,#05100H
    MOV      A,R7
    MOVX     @DPTR,A
; }
            ; SOURCE LINE # 38
?C0001:
    RET      

The above code takes 58 CPU cycles including the call and return.

Option-2: Use Port Data Register and Mask
In this method, the port data register is accessed in the external data memory space using the PHUB.   For every Port Pin placed in the schematic, a header file <Pin Name>.h has the declarations for the Port data register and the mask.  For a Port Pin named Out1, the Port data register and the mask are Out1_DR Out1_MASK respectively.  For example:
Out1_DR |= Out1_MASK;  // Set the pin
Out1_DR &= ~Out1_MASK; // Clear the pin
Pros: This type of access takes less processor cycles than the API function call.  The example code #1 above results in the below compiled code.
;         Out1_DR |= Out1_MASK;

            ; SOURCE LINE # 41
    MOV      DPTR,#05100H
    MOVX     A,@DPTR
    MOV      R7,A
    MOV      A,R7
    ORL      A,#010H
    MOV      R7,A
    MOV      A,R7
    MOVX     @DPTR,A

This takes 13 CPU cycles, about 4 times faster than the Port pin API function call.
Cons: There isn’t any great disadvantage of using this method other than the fact that this method is still slower than Option-3 below, and sacrifices some amount of readability compared to Option-1.
Option-3: Control the pin using the SFR register space
In this method, the port data register is accessed directly in the SFR register space.  There are two SFRs that need to be controlled.
SFRPRTxDR: The register bits control the bits of the corresponding port.  For example the value in Bit5 of SFRPRT0DR register controls the state of P0[5].
SFRPRTxSEL: Setting the corresponding bit in this register, enables the control of the port pin through the SFRPRTxDR register.  For example, if Bit5 of SFRPRT0SEL is set, then the state of P0[5] is controlled by the value of Bit5 of SFRPRT0DR register.  If the bit is cleared, the port can be controlled only through the PHUB interface.
These registers are declared in PSoC3_8051.h header file under the cy_boot folder in the workspace explorer.  Details of these registers may be found in PSoC3 Technical Reference Manual under Section 4.6.4 – I/O Port Access SFRs.
For example, to switch On/Off P1[5]
// First enable SFR access for P1[5].  This has to be done only once in the beginning of code
SFRPRT1SEL |= 0x20;

// To switch on
SFRPRT1DR |= 0x20;

// To switch off
SFRPRT1DR &= ~0x20;

// To toggle
SFRPRT1DR ^= 0x20;

Pros: This is the fastest way to modify the port pin state.  This takes  a single direct memory access instruction and takes 3 CPU cycles to execute.
Cons: Not portable.  If you relocate a Port Pin component in the schematic to a different GPIO port, then all the code that access the pin through SFRs have to be rewritten.
Summary:
1. If the project does not have any timing restrictions and you prefer readability over execution time, use Option-1
2. If you are working on time critical application where every processor cycle counts, and readability or portability is not important, use Option-3.
3. Option-2 is the ideal solution where it has 4x speed over Option-1 and does not sacrifice portability.
沙发
G21372| | 2011-12-19 22:38 | 只看该作者
OMG,英文的,有点困难

使用特权

评论回复
板凳
浏览器123| | 2011-12-19 22:42 | 只看该作者
读了一下,也不是很难理解吗

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

898

主题

5336

帖子

15

粉丝