查看: 3134|回复: 3

ATSAM4S学习系列2:PIO详解

[复制链接]
  • TA的每日心情
    擦汗
    2024-5-31 10:44
  • 签到天数: 1492 天

    连续签到: 1 天

    [LV.10]以坛为家III

    发表于 2014-11-10 10:52:45 | 显示全部楼层 |阅读模式
    分享到:
    这几天仔细看了看芯片datasheet的PIO部分说明,SAM4S的PIO功能很强大,
    1.jpg
    2.jpg

    每个IO口都具有中断功能,可以选择边沿触发或电平触发。具有滤波功能,要滤除杂波的宽度可以设置。具有多种输出驱动模式。具有上下拉选择功能。具有并行捕获模式。具有施密特输出功能。等等。功能很多。
    IO口内部数据图
    3.jpg
    IO口内部控制逻辑图
    4.jpg
    所有的这些功能都需要靠寄存器来实现,所以SAM4S的IO口方面的寄存器也很多,配置很强大,来看看寄存器列表
    5.jpg 6.jpg 7.jpg


    下面是我写的有关寄存器的一点说明,也就是datasheet上的部分翻译,大家凑活看看。
    PIO_PER:PIO使能寄存器,选择是为IO口功能还是其他外设功能。1使能为PIO口功能。
    PIO_PDR:PIO禁能寄存器。1禁能为PIO口功能,选择为外设功能。
    PIO_PSR:PIO状态寄存器。0为PIO_ABCDSR1和PIO_ABCDSR2控制,1为PIO控制器。上电默认是PIO口功能。
    PIO_OER:输出使能寄存器。1为使能输出。
    PIO_ODR:输出禁能寄存器。1为禁止输出,实际上也就是为输入。
    PIO_OSR:输出状态寄存器。0为输入,1为输出
    PIO_IFER:PIO输入滤波使能存器。1为使能IO口的故障输入滤波。该设置不影响外设的输入,只影响PIO_PDSR的读取。
    PIO_IFDR:PIO输入滤波禁能存器。1为禁止IO口的故障输入滤波。
    PIO_IFSR:PIO输入滤波状态寄存器。0为IO口故障输入滤波禁止,1为IO口故障输入滤波使能。
    PIO_SODR:置位输出数据寄存器。1为输出置高。
    PIO_CODR:清零输出数据寄存器。1为输出置低。
    PIO_ODSR:输出数据状态寄存器。0为输出低电平,1为输出高电平。这个寄存器可以直接写。
    PIO_PDSR:引脚数据状态寄存器。0为当前IO口为低电平,1为当前IO口为高电平。用于读引脚电平状态。
    PIO_IER:中断使能存器。1为使能IO口输入中断。用于引脚中断,可以边沿或电平触发中断。
    PIO_IDR:中断禁能存器。1为禁止IO口输入中断。
    PIO_IMR:中断屏蔽寄存器。0为IO口输入中断禁止,1为IO口输入中断使能。
    PIO_ISR:中断状态寄存器。0未检测到IO口中断,1为检测到IO口有中断发生了。有中断发生时,本寄存器对应位置1,如果PIO_IMR中的对应位置位的话(中断使能了),PIO控制中断则发生。软件读PIO_ISR后,所有中断自动清除。
    PIO_MDER:多驱动使能寄存器。1为使能IO口多驱动。
    PIO_MDDR:多驱动禁能寄存器。1为禁止IO口多驱动。
    PIO_MDSR:多驱动状态寄存器。0为IO口多驱动禁止,引脚只能被高和低电平驱动。1为IO口多驱动施恩给你,引脚只能低电平驱动。无论端口是PIO控制器还是外设功能控制器,都可以设置为开漏输出,
    PIO_PUDR:上拉禁能寄存器。1为IO口禁止上拉。
    PIO_PUER:上拉使能寄存器。1为IO口使能上拉。
    PIO_PUSR:上拉状态寄存器。0为上拉使能,1为上拉禁能。上电后默认所有上拉使能
    PIO_ABCDSR1:外设选择寄存器1。
    PIO_ABCDSR2:外设选择寄存器2。PIO_ABCDSR1和PIO_ABCDSR2对应位组合来选择外设,如PIO_ABCDSR2的bit0和PIO_ABCDSR1的bit0组合00:外设A,01:外设B,10:外设C,11:外设D。上电默认选择外设A
    PIO_IFSCDR:输入滤波慢时钟禁能寄存器。1为滤除小于1/2主时钟周期的杂波(Tmck/2)。
    PIO_IFSCER:输入滤波慢时钟使能寄存器。1为滤除小于1/2编程周期的杂波(Tdiv_slclk/2)。在PIO_SCDR寄存器中编程分频数。
    PIO_IFSCSR:输入滤波慢时钟状态寄存器。0为设置可以滤掉小于1/2主时钟周期的故障,1为设置设置可以滤掉小于1/2编程周期的抖动。
    PIO_SCDR:慢时钟分频消抖寄存器。DIV编程要消除的杂波的频率。Tdiv_slclk = 2*(DIV+1)*Tslow_clock.
    PIO_PPDDR:下拉禁能寄存器。1为禁止IO口下拉电阻。
    PIO_PPDER:下拉使能寄存器。1为使能IO口下拉电阻。
    PIO_PPDSR:下拉状态寄存器。0为使能IO口下拉电阻,1为禁止IO口下拉电阻。
    PIO_OWER:输出写使能寄存器。1为使能寄存器PIO_ODSR的写操作。
    PIO_OWDR:输出写禁能寄存器。1为禁止寄存器PIO_ODSR的写操作。
    PIO_OWSR:输出写状态寄存器。0为禁止寄存器PIO_ODSR的写操作。1为使能寄存器PIO_ODSR的写操作。
    PIO_AIMER:额外中断模式使能存器。1为使能PIO_ELSR和PIO_FRLHSR寄存器设置的中断源动作模式。这些模式包括上升沿下降沿检测,低电平高电平检测。
    PIO_AIMDR:额外中断模式禁能存器。1为设置中断模式为默认的上升沿和下降沿双边沿中断模式。
    PIO_AIMMR:额外中断模式屏蔽寄存器。0为设置中断模式为默认的上升沿和下降沿双边沿中断模式。1为设置为PIO_ELSR和PIO_FRLHSR寄存器设置的中断源动作模式。
    PIO_ESR:边沿选择寄存器。1为中断源为边沿检测中断。这个用作引脚中断用。
    PIO_LSR:电平选择寄存器。1为中断源为电平检测中断。
    PIO_ELSR:边沿/电平状态寄存器。0为中断源为边沿检测中断。1为中断源为电平检测中断。
    PIO_FELLSR:下降沿/低电平选择寄存器。1为下降沿或低电平中断检测。这个用作引脚中断用。
    PIO_REHLSR:上升沿/高电平选择寄存器。1为上升沿或高电平中断检测。
    PIO_FRLHSR:下降沿/上升沿 - 低电平/高电平状态寄存器。0为下降沿或低电平中断检测,1为上升沿或高电平中断检测。
    PIO_LOCKSR:PIO锁定状态寄存器。1为IO口锁定。锁定后只能硬件复位来解锁。
    PIO_WPMR:写保护模式寄存器。WPEN位 0为禁止写保护,1为写保护。WPKEY为校验密码,密码对了以后写WPEN位才有效。
    PIO_WPSR:写保护状态寄存器。WPVS位 0为没有对保护的寄存器写动作发生,1为对被保护的寄存器发生写动作。WPVS为1时WPVSRC指出哪个寄存器发生了写动作。读PIO_WPSR后,WPVS位自动清零。
    PIO_SCHMITT:施密特触发寄存器。0为施密特触发使能,1为施密特触发禁止。
    PIO_PCMR:并行捕获模式寄存器。
      PCEN位0为禁止并行捕获模式,1为使能并行捕获模式。
      DSIZE位为编程数据宽度,0为8为宽度,1为16为宽度,2为32为宽度。
      ALWYS位为并行捕获模式全速采样位,0为只有数据使能时采样,1为一直采样。
      HALFS位为并行捕获模式半速采样位,0为采样所有数据,1为采样特定时间的数据。
      FRSRS位为并行捕获模式首次采样。HALFS位为1时本位才有用。0为数据在计数值为奇数时采样,1为数据计数值在为偶数时采样。
    PIO_PCIER:并行捕获中断使能存器。RXBUFFENDRX OVRE DRDY位中断使能。
    PIO_PCIDR:并行捕获中断禁能存器。RXBUFFENDRX OVRE DRDY位中断禁止。
    PIO_PCIMR:并行捕获中断屏蔽寄存器。RXBUFFENDRX OVRE DRDY位中断屏蔽。
    PIO_PCISR:并行捕获中断状态寄存器。
      DRDY位为0 PIO_PCRHR没有读到新的数据,DRDY位为1 PIO_PCRHR读到新的数据了。PIO_PCRHR后读取后DRDY位自动清零。
      OVER位为0没有发生溢出错误,OVER位为1至少发生一个溢出错误。OVER位在寄存器读取或并行捕获模式禁止后自动复位。
      ENDRX位为0 PDC通道还没有结束传输。ENDRX位为1 PDC通道结束传输发生了。
      RXBUFF位为0 PDC通道接收缓冲满信号无效,RXBUFF位为0 PDC通道接收缓冲满信号有效。
    PIO_PCRHR:并行捕获接收保持寄存器。读到的数据内容。如果DSIZE为0,RDATA的低8位有效。如果DSIZE为1,RDATA的低16位有效。
    配置寄存器有锁定功能,锁定后寄存区无法进行写操作。以下寄存器可以被写保护
    “PIO Enable Register” PIO_PER
    “PIO Disable Register” PIO_PDR
    “PIO Output Enable Register” PIO_OER
    “PIO Output Disable Register” PIO_ODR
    “PIO Input Filter Enable Register” PIO_IFER
    “PIO Input Filter Disable Register” PIO_IFDR
    “PIO Multi-driver Enable Register” PIO_MDER
    “PIO Multi-driver Disable Register” PIO_MDDR
    “PIO Pull-Up Disable Register” PIO_PUDR
    “PIO Pull-Up Enable Register” PIO_PUER
    “PIO Peripheral ABCD Select Register 1” PIO_ABCDSR1
    “PIO Peripheral ABCD Select Register 2” PIO_ABCDSR2
    “PIO Output Write Enable Register” PIO_OWER
    “PIO Output Write Disable Register” PIO_OWDR
    “PIO Pad Pull-Down Disable Register” PIO_PPDDR
    “PIO Pad Pull-Down Status Register” PIO_PPDSR
    “PIO Parallel Capture Mode Register” PIO_PCMR
    IO口配置流程:
    先选择为IO口控制器,再选择输入输出,然后选择上下拉,输出置高置低
    IO口中断配置流程:
    先选择为IO口控制器-》再选择输入模式-》引脚中断使能PIO_IER-》然后开启额外中断PIO_AIMER-》选择边沿触发还是电平触发PIO_ESR-》然后选择上升沿/下降沿 或 高点电平中断PIO_FELLSR
    直接使用寄存器编程的话对编程者的要求比较高,难度比较大,关键的就是寄存器太多,要对那么多寄存器直接配置而不出错很困难。因为有这样的问题,所以也有解决的方法,库就是解决这个问题的良器,使用库函数可以很方面的进行各种功能配置而不要对寄存器进行深入的去了解,大大加快了开发的过程。
    但我个人认为要想深入的了解一个功能的话还是看寄存器配置比较好,大概看下,也不需要去记住,太多了也无法记住。
    AS6.2里自带的例程Start Kit Demo里有相关的应用,大家可以去看看,这里就不详细介绍了,例程里的外扩的三个按键使用的是中断功能,指示灯使用的是普通输出端口功能,可以自己研究下。 例程中的按键初始化static void configure_buttons(void){    /* ConfigurePushbutton 1. */    pmc_enable_periph_clk(PIN_PUSHBUTTON_1_ID);    pio_set_debounce_filter(PIN_PUSHBUTTON_1_PIO,PIN_PUSHBUTTON_1_MASK, 10);    pio_handler_set(PIN_PUSHBUTTON_1_PIO,PIN_PUSHBUTTON_1_ID,           PIN_PUSHBUTTON_1_MASK,PIN_PUSHBUTTON_1_ATTR, Button1_Handler);    NVIC_EnableIRQ((IRQn_Type)PIN_PUSHBUTTON_1_ID);    pio_handler_set_priority(PIN_PUSHBUTTON_1_PIO,(IRQn_Type) PIN_PUSHBUTTON_1_ID, IRQ_PRIOR_PIO);    pio_enable_interrupt(PIN_PUSHBUTTON_1_PIO,PIN_PUSHBUTTON_1_MASK);     /* ConfigurePushbutton 2. */    pmc_enable_periph_clk(PIN_PUSHBUTTON_2_ID);    pio_set_debounce_filter(PIN_PUSHBUTTON_2_PIO,PIN_PUSHBUTTON_2_MASK, 10);    pio_handler_set(PIN_PUSHBUTTON_2_PIO,PIN_PUSHBUTTON_2_ID,           PIN_PUSHBUTTON_2_MASK,PIN_PUSHBUTTON_2_ATTR, Button2_Handler);    NVIC_EnableIRQ((IRQn_Type)PIN_PUSHBUTTON_2_ID);    pio_handler_set_priority(PIN_PUSHBUTTON_2_PIO,(IRQn_Type) PIN_PUSHBUTTON_2_ID, IRQ_PRIOR_PIO);    pio_enable_interrupt(PIN_PUSHBUTTON_2_PIO,PIN_PUSHBUTTON_2_MASK);     /* ConfigurePushbutton 3. */    pmc_enable_periph_clk(PIN_PUSHBUTTON_3_ID);    pio_set_debounce_filter(PIN_PUSHBUTTON_3_PIO,PIN_PUSHBUTTON_3_MASK, 10);    pio_handler_set(PIN_PUSHBUTTON_3_PIO,PIN_PUSHBUTTON_3_ID,           PIN_PUSHBUTTON_3_MASK,PIN_PUSHBUTTON_3_ATTR, Button3_Handler);    NVIC_EnableIRQ((IRQn_Type)PIN_PUSHBUTTON_3_ID);    pio_handler_set_priority(PIN_PUSHBUTTON_3_PIO,(IRQn_Type) PIN_PUSHBUTTON_3_ID, IRQ_PRIOR_PIO);    pio_enable_interrupt(PIN_PUSHBUTTON_3_PIO,PIN_PUSHBUTTON_3_MASK);     /* Configure SDcard detection. */    pmc_enable_periph_clk(SD_MMC_0_CD_ID);    pio_set_debounce_filter(SD_MMC_0_CD_PIO,SD_MMC_0_CD_MASK, 10);    pio_handler_set(SD_MMC_0_CD_PIO,SD_MMC_0_CD_ID, SD_MMC_0_CD_MASK,           SD_MMC_0_CD_ATTR,SD_Detect_Handler);    NVIC_EnableIRQ((IRQn_Type)SD_MMC_0_CD_ID);    pio_handler_set_priority(SD_MMC_0_CD_PIO,(IRQn_Type) SD_MMC_0_CD_ID, IRQ_PRIOR_PIO);    pio_enable_interrupt(SD_MMC_0_CD_PIO,SD_MMC_0_CD_MASK);} 中断服务程序/** * \brief Handler forButton 1 rising edge interrupt. * \param id Thebutton ID. * \param mask Thebutton mask. */static void Button1_Handler(uint32_t id, uint32_t mask){    if((PIN_PUSHBUTTON_1_ID == id) && (PIN_PUSHBUTTON_1_MASK == mask))       ProcessButtonEvt(1);} 本文就写到这里,希望大家能一起交流!

    回复

    使用道具 举报

  • TA的每日心情

    2016-10-4 00:31
  • 签到天数: 173 天

    连续签到: 1 天

    [LV.7]常住居民III

    发表于 2014-11-10 12:30:23 | 显示全部楼层
    这寄存器,真是多如牛毛啊
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2024-5-31 10:44
  • 签到天数: 1492 天

    连续签到: 1 天

    [LV.10]以坛为家III

     楼主| 发表于 2014-11-10 12:49:18 | 显示全部楼层
    绳精 发表于 2014-11-10 12:30
    这寄存器,真是多如牛毛啊

    所以还是用库好
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2014-11-14 13:36
  • 签到天数: 2 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2014-11-13 11:16:46 | 显示全部楼层
    本人自己写的,请指正

    #define OUT     0         
    #define IN      1     
    #define QB      2   

    #define UP     0         
    #define DOWN   1     
    #define VAC    2   // vacancy



    void Set_IO_Mode(Pio *piox,unsigned char pinx,unsigned char mode,unsigned char R)//
    {       
            if(mode==OUT)//
            {
            piox->PIO_OER|=(1<<pinx);                        //
            piox->PIO_MDDR|=(0<<pinx);
            }
            else
            if(mode==IN)//
            {

            piox->PIO_ODR|=(1<<pinx);
            }
            else               
            if(mode==QB)//
            {

            piox->PIO_MDER|=(1<<pinx);         
            piox->PIO_OER|=(1<<pinx);                        //
           
            }
           
           
            piox->PIO_OWER|=(1<<pinx);                        //
           
            ////////////////////////
            if(R==UP)//
            {
            piox->PIO_PPDDR|=(1<<pinx);
            piox->PIO_PUER|=(1<<pinx);       
            }
            else
            if(R==DOWN)//                  
            {
            piox->PIO_PUDR|=(1<<pinx);
            piox->PIO_PPDER|=(1<<pinx);       
            }
            else               
            if(R==VAC)//
            {
            piox->PIO_PUDR|=(1<<pinx);
            piox->PIO_PPDDR|=(1<<pinx);
            }
           
           
    }

    单独端口设定:
            Set_IO_Mode(PIOA,0,OUT,UP);
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /5 下一条

    手机版|小黑屋|与非网

    GMT+8, 2024-12-23 02:29 , Processed in 0.149798 second(s), 22 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.