SmartFusion从FPGA到ARM(三)——SysTick延时函数和GPIO位带操作

    技术2023-11-12  101

    文章目录

    1.SysTick定时器简介2.精确延时函数的实现3.GPIO位带操作4.实际使用 系列教程: SmartFusion从FPGA到ARM系列教程

    1.SysTick定时器简介

    SysTick定时器是存在于ARM Cortex-M内核的一个滴答定时器,只要是ARM Cortex-M0/M3/M4/M7内核的MCU都包含这个定时器。

    它是一个24位的递减定时器,当计数到 0 时,将从RELOAD 寄存器中自动重装载定时初值,开始新一轮计数。

    使用内核的SysTick定时器来实现延时,可以不占用系统定时器,由于和MCU外设无关,所以代码的移植,在不同厂家的Cortex-M内核MCU之间,可以很方便的实现。

    Microsemi SmartFusion系列的FPGA芯片,内部就有一个ARM Cortex-M3内核的MCU,可以利用这个定时器,实现一个精确延时毫秒和微妙的函数。

    2.精确延时函数的实现

    在core_cm3.h文件中,有这样一个SysTick_Config函数:

    __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) { if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) { return (1UL); /* Reload value impossible */ } SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk;/* Enable SysTick IRQ and SysTick Timer */ return (0UL); /* Function successful */ }

    通过后面的注释也可以看出,这是对SysTick定时器进行初始化,配置初始计数值,使能中断,使能定时器等。对应的中断函数为:

    void SysTick_Handler(void) {

    这个默认是空的,需要我们自己来实现。

    如果SysTick初始化为:

    SysTick_Config(SystemCoreClock / 1000); //定时1ms

    即SysTick定时器每1ms中断一次,如果我们定义全局变量,然后在中断函数中,让此变量递减,而在延时函数中,一直判断此变量是否减到了0,那么这样就实现了一个延时毫秒的函数。同理改变定时器的计数值为:

    SysTick_Config(SystemCoreClock / 1000000); //定时1us

    那么就实现了每1us中断一次,所以延时微秒和延时毫秒函数的实现:

    uint32_t fac_us=0; //us延时倍乘数 uint32_t fac_ms=0; //ms延时倍乘数,在ucos下,代表每个节拍的ms数 void delay_init(void) { SystemCoreClockUpdate(); } void SysTick_Handler(void) { if(fac_us) fac_us--; if(fac_ms) fac_ms--; } void delay_us(uint32_t nus) { SysTick_Config(SystemCoreClock / 1000000); //定时1us fac_us = nus; while(fac_us != 0); } void delay_ms(uint32_t nms) { SysTick_Config(SystemCoreClock / 1000); //定时1ms fac_ms = nms; while(fac_ms != 0); }

    在使用延时函数之前,只需要进行系统时钟的更新即可。

    3.GPIO位带操作

    从MSS_GPIO库函数中,可找到对单个GPIO进行控制的实现:

    void MSS_GPIO_set_output ( mss_gpio_id_t port_id, uint8_t value ) { uint32_t gpio_idx = (uint32_t)port_id; ASSERT( gpio_idx < NB_OF_GPIO ); if ( gpio_idx < NB_OF_GPIO ) { GPIO_BITBAND->GPIO_OUT[gpio_idx] = (uint32_t)value; } }

    可以看到,最终是可以简化为GPIO_BITBAND->GPIO_OUT[gpio_idx] = value;

    在a2fxxxm3.h头文件中有一个结构体的定义:

    typedef struct { __IO uint32_t GPIO_0_CFG; ............ __IO uint32_t GPIO_31_CFG; __IO uint32_t GPIO_IRQ; __I uint32_t GPIO_IN; __IO uint32_t GPIO_OUT; } GPIO_TypeDef; typedef struct { __IO uint32_t GPIO_0_CFG[32]; ............ __IO uint32_t GPIO_31_CFG[32]; __IO uint32_t GPIO_IRQ[32]; __I uint32_t GPIO_IN[32]; __IO uint32_t GPIO_OUT[32]; } GPIO_BitBand_TypeDef;

    也就是说,最终的GPIO控制和读取,操作的其实是结构体成员GPIO_IN[32]和GPIO_OUT[32]这两个数组。

    可以用一个带参数的宏来实现:

    /* GPIO输出 */ #define MSS_IO_OUT(n) GPIO_BITBAND->GPIO_OUT[n] /* 读取输入 */ #define MSS_IO_IN(n) GPIO_BITBAND->GPIO_IN[n] /* 示例 */ MSS_IO_OUT(0) = 0; //GPIO_0输出0 MSS_IO_OUT(3) = 1; //GPIO_3输入1 uint8_t sw1_in = MSS_IO_IN(2);//读取GPIO_2输入 uint8_t sw2_in = MSS_IO_IN(3);//读取GPIO_3输入

    4.实际使用

    所以GPIO的控制和延时函数的实际调用:

    #include "main.h" int main() { delay_init(); /* 更新系统时钟 */ MSS_WD_disable(); MSS_GPIO_init(); /* GPIO_0 & GPIO_1 配置成输出模式 */ MSS_GPIO_config(MSS_GPIO_0, MSS_GPIO_OUTPUT_MODE); MSS_GPIO_config(MSS_GPIO_1, MSS_GPIO_OUTPUT_MODE); /* GPIO_2配置成输入模式*/ MSS_GPIO_config(MSS_GPIO_2, MSS_GPIO_INPUT_MODE); while(1) { /* GPIO_0闪烁 */ MSS_IO_OUT(0) = 0; delay_ms(500); MSS_IO_OUT(0) = 1; delay_ms(500); /* 读取GPIO_2输入 */ if(MSS_IO_IN(2) == 0) MSS_IO_OUT(1) = 0; else MSS_IO_OUT(1) = 1; } }

    delay.c文件的内容:

    #include "delay.h" uint32_t fac_us = 0; uint32_t fac_ms = 0; void delay_init(void) { SystemCoreClockUpdate(); } void SysTick_Handler(void) { if(fac_us) fac_us--; if(fac_ms) fac_ms--; } void delay_us(uint32_t nus) { SysTick_Config(SystemCoreClock / 1000000); fac_us = nus; while(fac_us != 0); } void delay_ms(uint32_t nms) { SysTick_Config(SystemCoreClock / 1000); fac_ms = nms; while(fac_ms != 0); }

    delay.h文件的内容:

    #ifndef __DELAY_H__ #define __DELAY_H__ #include "a2fxxxm3.h" extern uint32_t fac_us; extern uint32_t fac_ms; void delay_init(void); void delay_ms(uint32_t nms); void delay_us(uint32_t nus); #endif

    sys.h文件的内容:

    #ifndef __SYS_H__ #define __SYS_H__ #include "a2fxxxm3.h" /* GPIO输出 */ #define MSS_IO_OUT(n) GPIO_BITBAND->GPIO_OUT[n] /* 读取输入 */ #define MSS_IO_IN(n) GPIO_BITBAND->GPIO_IN[n] #endif
    Processed: 0.023, SQL: 10