ベガ開発ボードRISC-Vカーネル実装マイクロ秒の精度の遅延

序文

VEGAベガは、開発ボードは、いくつかの時間のために、長い時間のためにプレーし、OLEDスクリーンをドライブしたいが、私たちは最初にIICプロトコルを実現しなければならない、IICプロトコルを実装し、最も基本的には正確な時間遅延機能が必要なので、少し勉強しなかったた受信しましたどのように正確な遅延機能を書き込みます。既知の、ARMのCortex-Mコアは24ビットのSysTickシステムティックタイマを有し、それは主にオペレーティング・システムによって、タイムベースを提供するための単純サイクルタイマーです。RISC-VのRV32M1コアものSysTickタイマーを持っていますが、それはコアに属していないが、外部の汎用タイマの使用は、LPIT0(低消費電力の周期的インターバルタイマー)タイマ・チャネル0を達成することを、私たちは、から学ぶことができますsystem_RV32M1_ri5cy.cファイルには、いくつかの情報を取得します:


/* Use LIPT0 channel 0 for systick. */
#define SYSTICK_LPIT LPIT0
#define SYSTICK_LPIT_CH 0
#define SYSTICK_LPIT_IRQn LPIT0_IRQn

/* Leverage LPIT0 to provide Systick */
void SystemSetupSystick(uint32_t tickRateHz, uint32_t intPriority)
{
    /* Init pit module */
    CLOCK_EnableClock(kCLOCK_Lpit0);

    /* Reset the timer channels and registers except the MCR register */
    SYSTICK_LPIT->MCR |= LPIT_MCR_SW_RST_MASK;
    SYSTICK_LPIT->MCR &= ~LPIT_MCR_SW_RST_MASK;

    /* Setup timer operation in debug and doze modes and enable the module */
    SYSTICK_LPIT->MCR = LPIT_MCR_DBG_EN_MASK | LPIT_MCR_DOZE_EN_MASK | LPIT_MCR_M_CEN_MASK;

    /* Set timer period for channel 0 */
    SYSTICK_LPIT->CHANNEL[SYSTICK_LPIT_CH].TVAL = (CLOCK_GetIpFreq(kCLOCK_Lpit0) / tickRateHz) - 1;

    /* Enable timer interrupts for channel 0 */
    SYSTICK_LPIT->MIER |= (1U << SYSTICK_LPIT_CH);

    /* Set interrupt priority. */
    EVENT_SetIRQPriority(SYSTICK_LPIT_IRQn, intPriority);

    /* Enable interrupt at the EVENT unit */
    EnableIRQ(SYSTICK_LPIT_IRQn);

    /* Start channel 0 */
    SYSTICK_LPIT->SETTEN |= (LPIT_SETTEN_SET_T_EN_0_MASK << SYSTICK_LPIT_CH);
}

void SystemClearSystickFlag(void)
{
    /* Channel 0. */
    SYSTICK_LPIT->MSR = (1U << SYSTICK_LPIT_CH);
}

system_RV32M1_ri5cy.hファイルのSysTick割り込みサービス機能:


#define SysTick_Handler LPIT0_IRQHandler

LPIT0について

LPIT0各チャネルは、カウントダウンがゼロに達すると、ロード後1つの32ビットカウンタ、カウントダウンのカウント値が含まれている割り込みフラグがセットされ、割り込みフラグビットに1を書き込むことによってクリアします。関数の実行によって消費される時間を最小化するために、遅延機能の遅延は、レジスタのように直接使用しました。読み取ることによりRV32M1リファレンスマニュアル [第50章低消費電力割り込みタイマ(LPIT ) ]セクションに、そしてfsl_lpit.hライブラリ関数を達成するため、我々は以下のレジスタの機能を理解することができます:

レジスタ名 フルネーム 読み取り/書き込み 意味
TVAL タイマー値レジスタ 読み取り/書き込み タイマーの初期値を設定します
CVAL 現在のタイマ値 リードオンリー 現在のカウント値を取得します。
セット 登録を有効にするタイマーを設定 読み取りと書き込み タイマ制御を可能にします
CLRTEN クリアタイマーイネーブルレジスタ のみ書きます カウント値をクリアします。
MCR モジュールの制御レジスタ 読み取りと書き込み タイマクロックイネーブル
MSR モジュールステータスレジスタ 読み取りと書き込み オーバーフロー割り込みフラグ、割り込みをクリアするために1を書きます

上記リファレンスマニュアル関連のレジスタを導入することにより、我々は、タイマ・オーバフローかどうかを取得するには、2つの方法があります。

  • 取得0である、すなわち、現在のカウント値の値がCVALを登録
  • 取得レジスタオーバーフロー状態か否か、すなわち、MSRレジスタの値。

これらのレジスタは32ビットであり、それぞれの具体的な意味は、見つけることができるRV32M1リファレンスマニュアル

delay.cファイル


#include "delay.h"

static uint8_t  fac_us=0;                           //us延时倍乘数
static uint16_t fac_ms=0;                           //ms延时倍乘数,在ucos下,代表每个节拍的ms数

void Delay_Init(void)
{
    CLOCK_SetIpSrc(kCLOCK_Lpit0, kCLOCK_IpSrcFircAsync);    //设置定时器时钟48MHz
    LOG("LPIT0: %ld \r\n", CLOCK_GetIpFreq(kCLOCK_Lpit0));  //输出LPIT0时钟

    CLOCK_EnableClock(kCLOCK_Lpit0);    //使能时钟
    LPIT_Reset(LPIT0);                  //复位定时器
    LPIT0->MCR = LPIT_MCR_M_CEN_MASK;   //使能定时器

    fac_us = CLOCK_GetIpFreq(kCLOCK_Lpit0)/1000000;
    fac_ms = fac_us*1000;
}
//基于SysTick即LPIT0实现的延时微秒函数
void Delay_us(uint32_t Nus)
{
    LPIT0->CHANNEL[kLPIT_Chnl_0].TVAL =  48 * Nus - 1;                  //加载时间
    LPIT0->SETTEN |= (LPIT_SETTEN_SET_T_EN_0_MASK << kLPIT_Chnl_0);     //启动定时器
    while(LPIT0->CHANNEL[kLPIT_Chnl_0].CVAL);                           //等待计数值到0
//  while((LPIT0->MSR & 0x0001) != 0x01);                               //等待溢出
//  LPIT0->MSR |= (1U << kLPIT_Chnl_0);                                 //写1,清除中断
    LPIT0->CLRTEN |= (LPIT_CLRTEN_CLR_T_EN_0_MASK << kLPIT_Chnl_0);     //清除计数器
}

//基于SysTick即LPIT0实现的延时毫秒函数
void Delay_ms(uint32_t Nms)
{
    LPIT0->CHANNEL[kLPIT_Chnl_0].TVAL = Nms * fac_ms  - 1;          //加载时间
    LPIT0->SETTEN |= (LPIT_SETTEN_SET_T_EN_0_MASK << kLPIT_Chnl_0); //启动定时器
    while(LPIT0->CHANNEL[kLPIT_Chnl_0].CVAL);                       //等待计数到0
//  while((LPIT0->MSR & 0x0001) != 0x0001);                         //等待产生中断
//  LPIT0->MSR |= (1U << kLPIT_Chnl_0);                             //向中断标志位写1,清除中断
    LPIT0->CLRTEN |= (LPIT_CLRTEN_CLR_T_EN_0_MASK << kLPIT_Chnl_0); //清除计数器
}

delay.hファイル


#ifndef __DELAY_H__
#define __DELAY_H__

#include "fsl_lpit.h"
#include "fsl_lpit.h"
#include "fsl_debug_console.h"
#include "sys.h"

void Delay_Init(void);      //SysTick定时器,即LPIT0,时钟可设置
void Delay_ms(uint32_t Nms);
void Delay_us(uint32_t Nus);

#endif

実際の検証


...

#include "delay.h"
...

int main(void)
{
    ...
    Delay_Init();
    ...
    while(1)
    {
        GPIOA->PTOR = 1 << 24;  //寄存器方式操作,减小误差
        Delay_ms(100);  //延时微秒函数验证
//      Delay_us(5);    //延时微秒函数验证              
    }
}

実際のオシロスコープのテストとDelay_usマイクロ秒の遅延機能を発見し、関係なく遅延が、私はこれがある理由がわからないけど、IICプロトコルドライバのOLED画面は影響を受けません達成するためにどのくらい2usのエラーについてはありません。

IICインタフェースOLEDドライブ

  • ロゴ画像のコミュニティホーム

  • 実際のOLEDディスプレイ:

概要

正確な遅延機能を実現するので、その後、さまざまなプロトコルのセンサー、ディスプレイモジュール、ドライバの通信モジュールを容易に達成し、何人かの友人が助けコミュニティを与えるBenpian投稿を共有したいことができ、私はあなたがお互いに投稿することを願っています学習の交換を。

参考資料

歴史特集


私に注意を歓迎個人のブログwww.wangchaochao.top

私の電話番号に関する公開懸念のマイクロチャンネルスキャンコードまたは

おすすめ

転載: www.cnblogs.com/whik/p/11105346.html