自学内容网 自学内容网

RP2040 C SDK SysTick滴答定时器功能使用

RP2040 C SDK SysTick滴答定时器功能使用


  • ✨更好的阅读体验请移步到:飞书-云文档https://u1etqmuwl9z.feishu.cn/wiki/VkoHwPGqHierOEkY651cZvaOntg?from=from_copylink
  • RP2040的SysTick滴答定时器为24位的,计数方式为倒计时,扩展了处理器和NVIC的功能,并提供:
  • 一个24位的系统计时器(SysTick)
  • 附加的可配置优先级SysTick中断。
    SysTick计时器使用1μs脉冲作为时钟启用。这是在监视器块中作为timer_tick中生成的。SysTick计时的准确性取决于这个计时器的准确性。SysTick计时器也可以从系统时钟开始运行(参见SYST_CALIB)。

📗有关寄存器介绍

  • SYST_CSR Register:使用SysTick控制器和状态寄存器来启用SysTick功能。
  • 偏移地址:0xe010
    在这里插入图片描述
  • SYST_RVR Register:
  • Offset: 0xe014
    Use the SysTick Reload Value Register to specify the start value to load into the current value register when the counter reaches 0. It can be any value between 0 and 0x00FFFFFF. A start value of 0 is possible, but has no effect because the SysTick interrupt and COUNTFLAG are activated when counting from 1 to 0. The reset value of this register is UNKNOWN.
    To generate a multi-shot timer with a period of N processor clock cycles, use a RELOAD value of N-1. For example, if the SysTick interrupt is required every 100 clock pulses, set RELOAD to 99.

在这里插入图片描述

  • SYST_CVR Register
  • Offset: 0xe018
    Use the SysTick Current Value Register to find the current value in the register. The reset value of this register is UNKNOWN.
    在这里插入图片描述
  • SYST_CALIB Register
  • Offset: 0xe01c

Use the SysTick Calibration Value Register to enable software to scale to any required speed using divide and multiply
在这里插入图片描述

📘滴答定时器作为非阻塞定时任务调度使用


/*
 CMSIS-DAP烧录命令:openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c  "adapter speed 5000"-c "program RP2040_ticks.elf verify reset exit"

 jlink命令: openocd -f interface/jlink.cfg -f target/rp2040.cfg  -c  "adapter speed 2000" -c  "program RP2040_ticks.elf verify reset exit"


*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/timer.h"
#include "hardware/structs/systick.h"
#include "hardware/clocks.h"
//#include "hardware/uart.h"
//#include "hardware/irq.h"
//#include "hardware/structs/scb.h"
#include <tusb.h>



#define BUILTIN_LED PICO_DEFAULT_LED_PIN // LED is on the same pin as the default LED 25

void measure_freqs(void);
void MicrosBlink(uint32_t currentTime);
uint32_t previousBlinkTime;
uint32_t blinkInterval = 1000000; //LED闪烁时间间隔
bool toggle;

int main()
{

    // set_sys_clock_khz(133000, true); // 325us
   // set_sys_clock_khz(270000, true);
    stdio_init_all();
    // GPIO initialisation.
    gpio_init(BUILTIN_LED);
    gpio_set_dir(BUILTIN_LED, GPIO_OUT);
    gpio_pull_up(BUILTIN_LED);
    sleep_ms(1);

    while (!tud_cdc_connected()) { sleep_ms(100);  }//等待USB CDC打开
    printf("tud_cdc_connected()\n");

    systick_hw->csr = 0x5;
    systick_hw->rvr = 0x00FFFFFF;

    uint32_t new, old, t0, t1;
    old=systick_hw->cvr;

    t0=time_us_32();
    sleep_us(49999);
    new=systick_hw->cvr;
    t1=time_us_32();

    printf("\n          old_cvr=%d,new_cvr=%d\n",old,new);
    printf("\n          old-new=%d\n",old-new);
    printf("            t1-t0=%d\n",t1-t0);
    printf("(old-new)/(t1-t0)=%.1f\n",(old-new)/(t1-t0*1.0));//频率
    measure_freqs();

    while (true)
    {
     // tight_loop_contents();
        // sleep_ms(1000);
        // gpio_xor_mask(1ul << BUILTIN_LED); // Toggle the LED

        uint32_t currentMillis = time_us_32(); // 获取当前时间

        MicrosBlink(currentMillis);
    }

    return 0;
}


void measure_freqs(void) {
    uint f_pll_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_SYS_CLKSRC_PRIMARY);
    uint f_pll_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_USB_CLKSRC_PRIMARY);
    uint f_rosc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC);
    uint f_clk_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS);
    uint f_clk_peri = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_PERI);
    uint f_clk_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_USB);
    uint f_clk_adc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_ADC);
    uint f_clk_rtc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_RTC);

    printf("pll_sys  = %dkHz\n", f_pll_sys);
    printf("pll_usb  = %dkHz\n", f_pll_usb);
    printf("rosc     = %dkHz\n", f_rosc);
    printf("clk_sys  = %dkHz\n", f_clk_sys);
    printf("clk_peri = %dkHz\n", f_clk_peri);
    printf("clk_usb  = %dkHz\n", f_clk_usb);
    printf("clk_adc  = %dkHz\n", f_clk_adc);
    printf("clk_rtc  = %dkHz\n", f_clk_rtc);

    // Can't measure clk_ref / xosc as it is the ref
}

void MicrosBlink(uint32_t currentTime) {
  //检查是否到达时间间隔
  if (currentTime-previousBlinkTime  >= blinkInterval) {    //如果时间间隔达到了
    toggle = (toggle == 1) ? 0 : 1;
 gpio_put(BUILTIN_LED, toggle);
    previousBlinkTime = currentTime;  // 将上一次时间复位

  printf("toggle = %d\n",toggle);
  }

}

在这里插入图片描述

📙利用库实现

  • 📍https://github.com/Blimp01/pico_non_blocking_timer
/*
 CMSIS-DAP烧录命令:openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c  "adapter speed 5000"-c "program example.elf verify reset exit"

 jlink命令: openocd -f interface/jlink.cfg -f target/rp2040.cfg  -c  "adapter speed 2000" -c  "program example.elf verify reset exit"


*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "pico/binary_info.h"
#include "non_blocking_timer.h"

const uint LED_PIN = 25;

non_blocking_timer_handler led_timer; // create user timer struct

void toggle_led()
{
        gpio_put(LED_PIN, !gpio_get(LED_PIN));
}

int main()
{
        stdio_init_all();
        init_non_blocking_timer(&led_timer, 1000,0); //initalise ledtimer for a 1second period
        init_systick();                            //init and enable systick

        gpio_init(LED_PIN);
        gpio_set_dir(LED_PIN,GPIO_OUT);
        start_non_blocking_timer(&led_timer);
        while(1)
        {
                if(non_blocking_timer_expired(&led_timer) == TIMER_EXPIRED)
                {
                        printf("systick %ld\r\n",get_systick()); //Print out systick value
                        toggle_led();                            //Toggle LED 1s On 1s OFF
                        start_non_blocking_timer(&led_timer);    //restart 1s timer
                }
        }
}

📗使用滴答定时器中断

  • ✨滴答定时器中断号没有在常规的0 - 25号中断序列(interrupt_nums)中,而是另外的exception_number中,以负数表现形式,被定义在exception.h文件中。
/*! \brief  Exception number definitions
 *
 * Note for consistency with irq numbers, these numbers are defined to be negative. The VTABLE index is
 * the number here plus 16.
 *
 * Name                 | Value | Exception
 * ---------------------|-------|----------
 * NMI_EXCEPTION        |  -14  | Non Maskable Interrupt
 * HARDFAULT_EXCEPTION  |  -13  | HardFault
 * SVCALL_EXCEPTION     |   -5  | SV Call
 * PENDSV_EXCEPTION     |   -2  | Pend SV
 * SYSTICK_EXCEPTION    |   -1  | System Tick
 *
 * \ingroup hardware_exception
 */
enum exception_number {
    NMI_EXCEPTION        = -14,     /* Non Maskable Interrupt */
    HARDFAULT_EXCEPTION  = -13,     /* HardFault Interrupt */
    SVCALL_EXCEPTION     =  -5,     /* SV Call Interrupt */
    PENDSV_EXCEPTION     =  -2,     /* Pend SV Interrupt */
    SYSTICK_EXCEPTION    =  -1,     /* System Tick Interrupt */
};
  • 例程代码

/*
 CMSIS-DAP烧录命令:openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c  "adapter speed 5000"-c "program RP2040_ticks.elf verify reset exit"

 jlink命令: openocd -f interface/jlink.cfg -f target/rp2040.cfg  -c  "adapter speed 2000" -c  "program RP2040_ticks.elf verify reset exit"

*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/exception.h"
#include "hardware/timer.h"
#include "hardware/structs/systick.h"
#include "hardware/clocks.h"
// #include "hardware/uart.h"
// #include "hardware/irq.h"

#include <tusb.h>


#define BUILTIN_LED PICO_DEFAULT_LED_PIN // LED is on the same pin as the default LED 25

void measure_freqs(void);
void MicrosBlink(uint32_t currentTime);
void disableAllInts();
uint32_t previousBlinkTime;
uint32_t blinkInterval = 1000000; // LED闪烁时间间隔
bool toggle;
uint32_t ST_period = 1000000 - 1;


void enableSysTick()
{
                                                                             // 1mS
  systick_hw->rvr = ST_period;                                                                                   // 24 bits
 // systick_hw->csr = M0PLUS_SYST_CSR_CLKSOURCE_BITS | M0PLUS_SYST_CSR_ENABLE_BITS | M0PLUS_SYST_CSR_TICKINT_BITS; // enable with processor clock
    systick_hw->csr = 0x07;  //Enable timer with interrupt
}

void Systick_Handler_Callback(void)
{
    systick_hw->csr = 0x00; // Disable systick
     systick_hw->rvr = ST_period ; // reload the systick counter
    systick_hw->cvr = 0; // Clear the count to force reload
  toggle = (toggle == 1) ? 0 : 1;
  gpio_put(BUILTIN_LED, toggle); // toggle LED
  printf("toggle = %d\n", toggle);
    systick_hw->csr = 0x03; // Enable timer with interrupt
}

int main()
{

  // set_sys_clock_khz(133000, true); // 325us
  // set_sys_clock_khz(270000, true);
  set_sys_clock_khz(125000, 0);   //clk_sys125MHz
  stdio_init_all();
  // GPIO initialisation.
  gpio_init(BUILTIN_LED);
  gpio_set_dir(BUILTIN_LED, GPIO_OUT);
  gpio_pull_up(BUILTIN_LED);
  sleep_ms(1);

  uint32_t fcpu = clock_get_hz(clk_sys);
  while (!tud_cdc_connected())
  {
    sleep_ms(100);
  }
  printf("tud_cdc_connected()\n");

  systick_hw->csr = 0x5;

  systick_hw->rvr = 0x00FFFFFF;

  uint32_t new, old, t0, t1;
  old = systick_hw->cvr;

  t0 = time_us_32();
  sleep_us(49999);
  new = systick_hw->cvr;
  t1 = time_us_32();

  printf("\n          old_cvr=%d,new_cvr=%d\n", old, new);
  printf("\n          old-new=%d\n", old - new);
  printf("            t1-t0=%d\n", t1 - t0);
  printf("(old-new)/(t1-t0)=%.1f\n", (old - new) / (t1 - t0 * 1.0)); // 频率
  measure_freqs();

   enableSysTick();
  // register the Systick Handler
  exception_set_exclusive_handler(SYSTICK_EXCEPTION, Systick_Handler_Callback);
  irq_set_priority(SYSTICK_EXCEPTION, PICO_HIGHEST_IRQ_PRIORITY); // set systick highest priority

  while (true)
  {
    // tight_loop_contents();
    // sleep_ms(1000);
    // gpio_xor_mask(1ul << BUILTIN_LED); // Toggle the LED

    //    uint32_t currentMillis = time_us_32(); // 获取当前时间

    //  MicrosBlink(currentMillis);

    // measure_freqs();
  }

  return 0;
}

void measure_freqs(void)
{
  uint f_pll_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_SYS_CLKSRC_PRIMARY);
  uint f_pll_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_USB_CLKSRC_PRIMARY);
  uint f_rosc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC);
  uint f_clk_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS);
  uint f_clk_peri = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_PERI);
  uint f_clk_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_USB);
  uint f_clk_adc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_ADC);
  uint f_clk_rtc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_RTC);

  printf("pll_sys  = %dkHz\n", f_pll_sys);
  printf("pll_usb  = %dkHz\n", f_pll_usb);
  printf("rosc     = %dkHz\n", f_rosc);
  printf("clk_sys  = %dkHz\n", f_clk_sys);
  printf("clk_peri = %dkHz\n", f_clk_peri);
  printf("clk_usb  = %dkHz\n", f_clk_usb);
  printf("clk_adc  = %dkHz\n", f_clk_adc);
  printf("clk_rtc  = %dkHz\n", f_clk_rtc);

  // Can't measure clk_ref / xosc as it is the ref
}

void MicrosBlink(uint32_t currentTime)
{
  // 检查是否到达时间间隔
  if (currentTime - previousBlinkTime >= blinkInterval)
  { // 如果时间间隔达到了
    toggle = (toggle == 1) ? 0 : 1;
    gpio_put(BUILTIN_LED, toggle);
    previousBlinkTime = currentTime; // 将上一次时间复位

    printf("toggle = %d\n", toggle);
  }
  // else if (currentTime-previousBlinkTime <= 0) {   // 如果时间间隔小于0时间溢出
  //   previousBlinkTime = currentTime;
  // }
}

void disableAllInts()
{
  int i;
  for (i = 0; i < 32; i++)
  { // 32 interrupts on NVIC
    irq_set_enabled(i, false);
  }
}


原文地址:https://blog.csdn.net/weixin_42880082/article/details/142267991

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!