ARM Cordio WSF(三)——WSF在nRF52840平台移植

前文介绍了WSF架构及其WSF API,本文将介绍如何在一个硬件平台上使用WSF,这里基于stack项目下的nRF52840平台进行介绍。

3、PAL实现

对于要在一个处理器上运行WSF(逻辑情况),需要处理系统的调度、系统SysTick、中断上下文(Critical Section)、平台定时器相关,主要涉及内容如下:

  • timer移植,这里在平台相关的文件:pal_timer.c/h中实现;
  • 中断,Critical Section相关处理,避免中断执行上下文的破坏,平台相关文件:pal_sys.c/h;
  • 若需要使用NVM,则需要pal_flash.h/c
  • 对于wsf_heap相关操作,必要也需要在pal_sys.c/h中进行适配。

在WSF的架构中,均以PAL_*的形式来定义,即以平台抽象层(PAL,Platform Abstraction Layer)形式实现。

3.1 pal_sys

对于系统相关的PAL实现,关键接口如下(pal_sys.h):

/* Initialization */
void PalSysInit(void);/* Diagnostics */
void PalSysAssertTrap(void);
void PalSysSetTrap(bool_t enable);
uint32_t PalSysGetAssertCount(void);
uint32_t PalSysGetStackUsage(void);/* Power Management */
void PalSysSleep(void);  //休眠相关处理
bool_t PalSysIsBusy(void);
void PalSysSetBusy(void);
void PalSysSetIdle(void);/* Critical Section */
void PalEnterCs(void);
void PalExitCs(void);

包括系统初始、诊断相关、功耗管理相关、以及Critical Section的处理。

/*! \brief      Free memory for pool buffers (align to word boundary). */
uint32_t palSysFreeMem[FREE_MEM_SIZE/sizeof(uint32_t)];uint8_t *SystemHeapStart = (uint8_t *) palSysFreeMem;
uint32_t SystemHeapSize = FREE_MEM_SIZE;

关于Critical Section的处理,主要为中断的开启与关闭:

void PalEnterCs(void)
{#ifdef __IAR_SYSTEMS_ICC____disable_interrupt();#endif#ifdef __GNUC____asm volatile ("cpsid i");#endif#ifdef __CC_ARM__disable_irq();#endif
}
void PalSysInit(void)
{/* Enable Flash cache */NRF_NVMC->ICACHECNF |= (NVMC_ICACHECNF_CACHEEN_Enabled << NVMC_ICACHECNF_CACHEEN_Pos);/* Use 16 MHz crystal oscillator (system starts up using 16MHz RC oscillator). */NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;NRF_CLOCK->TASKS_HFCLKSTART    = 1;while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) { }palSysAssertCount = 0;PalSysAssertTrapEnable = TRUE;palSysBusyCount = 0;PalRtcInit();
}

在平台初始化函数中,完成RTC初始化、系统相关设置,配置时钟等操作。

3.2 pal_timer

platform/pal_timer.c中,实现定时器驱动程序,用于调度程序和其他低功耗相关任务。其在实现时依赖于pal_rtc.c和一些调度程序以及nRF528**基带相关API。

对于一个调度定时器而言,通常需要实现以下相关接口(pal_timer.h):

/* Initialization */
void PalTimerInit(PalTimerCompCback_t expCback);
void PalTimerDeInit(void);/* Control and Status */
PalTimerState_t PalTimerGetState(void);
void PalTimerStart(uint32_t expUsec);
void PalTimerStop(void);
uint32_t PalTimerGetCurrentTime(void);

以下为在NRF处理器上实现调度定时器,包括控制块、调度定时器初始化等。

/*! \brief      Scheduler timer driver control block. */
static struct
{PalTimerState_t    state;            /*!< State. */uint32_t           compareVal;       /*!<  Absolute compare value for timer expiry interrupt. */PalTimerCompCback_t expCback;         /*!< Timer expiry call back function. */
} palTimerCb;

调度定时器初始化:

void PalTimerInit(PalTimerCompCback_t expCback)
{#if SCH_TIMER_REQUIRED == TRUE#if BB_CLK_RATE_HZ == 32768PalRtcIrqRegister(RTC_CHANNEL_START_BB, palTimerRtcIrqHandler);#else/* Give scheduler timer the highest priority. */NVIC_SetPriority(TIMER1_IRQn, 0);  /* highest priority */NVIC_DisableIRQ(TIMER1_IRQn);/* stop timer if it was somehow running (timer must be stopped for configuration) */NRF_TIMER1->TASKS_STOP  = 1;/* clear timer to zero count */NRF_TIMER1->TASKS_CLEAR = 1;/* configure timer */NRF_TIMER1->MODE      = TIMER_MODE_MODE_Timer;NRF_TIMER1->BITMODE   = TIMER_BITMODE_BITMODE_32Bit;NRF_TIMER1->PRESCALER = PAL_TIMER_1MHZ_PRESCALER;  /* f = 16MHz / (2 ^ TIMER_PRESCALER) *//* timer1 is a free running clock. */NRF_TIMER1->TASKS_START = 1;/* Clear out and enable timer1 interrupt at system level. */NRF_TIMER1->INTENCLR = 0xFFFFFFFF;NRF_TIMER1->EVENTS_COMPARE[TIMER_CHANNEL_START_BB] = 0;NVIC_ClearPendingIRQ(TIMER1_IRQn);NVIC_EnableIRQ(TIMER1_IRQn);#endif#endifpalTimerCb.compareVal = 0;palTimerCb.expCback = expCback;palTimerCb.state = PAL_TIMER_STATE_READY;
}

调度定时器的源根据宏定义,可以设置两种 :一种是RTC 32.768kHz的源;另一种是基于定时器Timer1来实现。

通过void PalTimerStart(uint32_t expTimeUsec)void PalTimerStop()来实现定时器的开启与停止。

相应的,根据设置情况,需要在palTimerRtcIrqHandlerTIMER1_IRQn中断中处理定时器相关。

void TIMER1_IRQHandler(void)
{/* Callback function could restart timer1. However, we blindly stop timer1 first. */NRF_TIMER1->INTENCLR = TIMER_INTENCLR_COMPARE0_Msk;/* Clear event again just in case. */NRF_TIMER1->EVENTS_COMPARE[TIMER_CHANNEL_START_BB] = 0;palTimerCb.state = PAL_TIMER_STATE_READY;if (palTimerCb.expCback)  //初始化中设定的定时器回调函数{palTimerCb.expCback();  }
}

3.3 pal_flash

对于平台上Flash相关操作,提供NVM的使用,通过pal_flash.h来实现。

/* Initialization */
void PalFlashInit(PalFlashCback_t actCback);
void PalFlashDeInit(void);/* Control and Status */
PalFlashState_t PalNvmGetState(void);
uint32_t PalNvmGetTotalSize(void);
uint32_t PalNvmGetSectorSize(void);/* Data Transfer */
void PalFlashRead(void *pBuf, uint32_t size, uint32_t srcAddr);
void PalFlashWrite(void *pBuf, uint32_t size, uint32_t dstAddr);
void PalFlashEraseSector(uint32_t size, uint32_t startAddr);
void PalFlashEraseChip(void);

以nRF52840为例,为QSPI Flash,其实现上,通过完成对底层驱动的初始化,进而可实现对Flash的访问。

void PalFlashInit(PalFlashCback_t actCback)
{uint32_t status;uint8_t  temp = 0x40;(void)actCback;nrfx_qspi_config_t config ={                                                                       \.xip_offset  = NRFX_QSPI_CONFIG_XIP_OFFSET,                         \.pins = {                                                           \.sck_pin     = BSP_QSPI_SCK_PIN,                                 \.csn_pin     = BSP_QSPI_CSN_PIN,                                 \.io0_pin     = BSP_QSPI_IO0_PIN,                                 \.io1_pin     = BSP_QSPI_IO1_PIN,                                 \.io2_pin     = BSP_QSPI_IO2_PIN,                                 \.io3_pin     = BSP_QSPI_IO3_PIN,                                 \},                                                                  \.irq_priority   = (uint8_t)NRFX_QSPI_CONFIG_IRQ_PRIORITY,           \.prot_if = {                                                        \.readoc     = (nrf_qspi_readoc_t)NRFX_QSPI_CONFIG_READOC,       \.writeoc    = (nrf_qspi_writeoc_t)NRFX_QSPI_CONFIG_WRITEOC,     \.addrmode   = (nrf_qspi_addrmode_t)NRFX_QSPI_CONFIG_ADDRMODE,   \.dpmconfig  = false,                                            \},                                                                  \.phy_if = {                                                         \.sck_freq   = (nrf_qspi_frequency_t)NRFX_QSPI_CONFIG_FREQUENCY, \.sck_delay  = (uint8_t)NRFX_QSPI_CONFIG_SCK_DELAY,              \.spi_mode   = (nrf_qspi_spi_mode_t)NRFX_QSPI_CONFIG_MODE,       \.dpmen      = false                                             \},                                                                  \};/* Verify palFlashCacheBuf size is at least 2. */PAL_FLASH_PARAM_CHECK(PAL_FLASH_CACHE_BUF_SIZE >= 2);status = nrfx_qspi_init(&config, NULL, NULL);PAL_FLASH_PARAM_CHECK(status == NRFX_SUCCESS);nrf_qspi_cinstr_conf_t cinstr_cfg = {.opcode    = QSPI_STD_CMD_RSTEN,.length    = NRF_QSPI_CINSTR_LEN_1B,.io2_level = 1,.io3_level = 1,.wipwait   = 1,.wren      = 1};/* Send reset enable. */status = nrfx_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);/* Send reset command */cinstr_cfg.opcode = QSPI_STD_CMD_RST;status = nrfx_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);PAL_FLASH_PARAM_CHECK(status == NRFX_SUCCESS);/* Switch to qspi mode */cinstr_cfg.opcode = QSPI_STD_CMD_WRSR;cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_2B;status = nrfx_qspi_cinstr_xfer(&cinstr_cfg, &temp, NULL);PAL_FLASH_PARAM_CHECK(status == NRFX_SUCCESS);memset(&palFlashCb, 0, sizeof(palFlashCb));palFlashCb.state = PAL_FLASH_STATE_READY;(void)status;}

对于Flash的读与写实现:

void PalFlashRead(void *pBuf, uint32_t size, uint32_t srcAddr)
{uint32_t readSize = PAL_FLASH_WORD_ALIGN(size);uint32_t actualSize = size;uint32_t status;uint16_t addrOffset = 0;do{if (readSize <= sizeof(palFlashCacheBuf)){/* Read data. */status = nrfx_qspi_read(palFlashCacheBuf, readSize, srcAddr + addrOffset);memcpy((uint8_t*)pBuf + addrOffset, palFlashCacheBuf, actualSize);readSize = 0;}else{/* Read data. */status = nrfx_qspi_read(palFlashCacheBuf, sizeof(palFlashCacheBuf), srcAddr + addrOffset);memcpy((uint8_t*)pBuf + addrOffset, palFlashCacheBuf, sizeof(palFlashCacheBuf));addrOffset += sizeof(palFlashCacheBuf);readSize -= sizeof(palFlashCacheBuf);actualSize -= sizeof(palFlashCacheBuf);}} while (readSize != 0);(void)status;
}
void PalFlashWrite(void *pBuf, uint32_t size, uint32_t dstAddr)
{uint32_t writeSize = PAL_FLASH_WORD_ALIGN(size);uint32_t actualSize = size;uint32_t status;uint16_t addrOffset = 0;do{if (writeSize <= sizeof(palFlashCacheBuf)){memcpy(palFlashCacheBuf, (uint8_t*)pBuf + addrOffset, actualSize);memset((uint8_t*)palFlashCacheBuf + actualSize, 0xFF, sizeof(palFlashCacheBuf) - actualSize);/* Write data. */status = nrfx_qspi_write(palFlashCacheBuf, writeSize, dstAddr + addrOffset);writeSize = 0;}else{memcpy(palFlashCacheBuf, (uint8_t*)pBuf + addrOffset, sizeof(palFlashCacheBuf));/* Write data. */status = nrfx_qspi_write(palFlashCacheBuf, sizeof(palFlashCacheBuf), dstAddr + addrOffset);addrOffset += sizeof(palFlashCacheBuf);writeSize -= sizeof(palFlashCacheBuf);actualSize -= sizeof(palFlashCacheBuf);}} while (writeSize != 0);(void)status;
}

3.4 SysTick实现

对于Cortex-M系列的处理器,都可以使用SysTick_Handler来实现系统的tick,这样更具有移植性。
对于SysTick_Handler的处理,
1)关键管理一个系统的tick,这里的示例使用32bit全局变量来实现;
2)调用WSF中的Timer来更新Tick,对于设置的wsf_timer,超时的,将触发定时器任务,进而触发相应的事件。

//由于在中断上下文处理,使用volatile关键字
volatile uint32_t g_sys_tick_count = 0;void SysTick_Handler(void)  
{g_sys_tick_count++;WsfTimerUpdateTicks();
}

关于SysTick时钟的设备,则,根据系统期望的tick情况(如10ms)来设置。

    /* Configure SysTick to generate an interrupt every millisecond */SysTick_Config(WSF_MS_PER_TICK * GetSystemCoreClock() / 1000);     

其中,GetSystemCoreClock获取系统时钟情况,不同平台根据设置的系统时钟来设置。

基本调用逻辑与思路如下图所示:
在这里插入图片描述
WsfTimerUpdate中,将已经超时的Task设置定时器事件。

/* timer expired; set task for this timer as ready */
WsfTaskSetReady(pElem->handlerId, WSF_TIMER_EVENT);void WsfTaskSetReady(wsfHandlerId_t handlerId, wsfTaskEvent_t event)
{/* Unused parameter */(void)handlerId;WSF_CS_INIT(cs);uint32_t lock = WSF_CS_ENTER();wsfOs.task.taskEventMask |= event;WSF_CS_EXIT(lock);/* set event in OS */
}

最终,在wsfOsDispatcher中调用。

    /*--- Start OS Dispatcher in a loop ---*/while(1){wsfOsDispatcher();}

持续更新,系列文章,收藏关注吧!

1、ARM Cordio WSF(一)——架构介绍
2、ARM Cordio WSF(二)——API接口介绍

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/807975.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

征程 5 芯片架构

文章目录 简介图像处理升级丰富异构计算自动驾驶 I/O 接口功能安全和信息安全保障征程 5 架构性能指标简介 征程5 是地平线第三代车规级产品,也是国内首颗遵循 ISO 26262 功能安全认证流程开发,并通过ASIL-B 认证的车载智能计算方案;⁣基于最新的地平线BPU 贝叶斯架构设计,…

Excel 防止数字变为E+的技巧

方式一&#xff1a;开始选项卡 ⇒ 分数 方式二&#xff1a;设置单元格格式 ⇒ 自定义 ⇒ 0 方式三 设置单元格格式为纯文本后&#xff0c;在粘贴数据当数字过长的时候(例如身份证号)&#xff0c;超过15位之后的数字都会变成0。 此时可以在数字前添加一个符号&#xff0c;例如 …

润色问题解惑

上博士为了毕业写学术论文头都大了&#xff0c;但更难受的是英语不咋地&#xff0c;投稿后经常会因为语言问题而惨遭拒稿&#xff0c;每每想起就令人心情郁郁&#xff0c;天台可期。有些审稿人也会直接告知需要专业的修改&#xff0c;那咋整呢&#xff0c;让润色呗&#xff0c;…

LeetCode 142.环形链表II(数学公式推导)

给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整…

Navicat的详细下载步骤

第一步&#xff0c;打开百度&#xff0c;找到Navicat官网 第二步&#xff0c;点击产品然后进去 第三步&#xff0c;点击直接下载然后跟着步骤来就OK啦

Centos7配置秘钥实现集群免密登录

设备&#xff1a;MacBook Pro、多台Centos7.4服务器(已开启sshd服务) 大体流程&#xff1a;本机生成秘钥&#xff0c;将秘钥上传至服务器即可实现免密登录 1、本地电脑生成秘钥&#xff1a; ssh-keygen -t rsa -C "邮箱地址 例&#xff1a;*****.163.com"一路回车…

跟TED演讲学英文:The inside story of ChatGPT‘s astonishing potential by Greg Brockman

The inside story of ChatGPT’s astonishing potential Link: https://www.ted.com/talks/greg_brockman_the_inside_story_of_chatgpt_s_astonishing_potential Speaker: Greg Brockman Date:April 2023 文章目录 The inside story of ChatGPTs astonishing potentialIntro…

功能强大的开源数据中台系统 DataCap 2024.03.1 发布

推荐一套基于 SpringBoot 开发的简单、易用的开源权限管理平台&#xff0c;建议下载使用: https://github.com/devlive-community/authx 推荐一套为 Java 开发人员提供方便易用的 SDK 来与目前提供服务的的 Open AI 进行交互组件&#xff1a;https://github.com/devlive-commun…

基于springboot+vue实现的高校宿舍管理系统(界面优美,十分推荐)

一、项目简介 本项目是一套基于springbootvue实现的高校宿舍管理系统设计与实现 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观…

探索 Java 网络爬虫:Jsoup、HtmlUnit 与 WebMagic 的比较分析

1、引言 在当今信息爆炸的时代&#xff0c;网络数据的获取和处理变得至关重要。对于 Java 开发者而言&#xff0c;掌握高效的网页抓取技术是提升数据处理能力的关键。本文将深入探讨三款广受欢迎的 Java 网页抓取工具&#xff1a;Jsoup、HtmlUnit 和 WebMagic&#xff0c;分析…

如何应用电桥电路的原理?

电桥电路是一种常用的测量技术&#xff0c;它利用了四个电阻的网络来检测电路的平衡状态。在平衡状态下&#xff0c;电桥的输出电压为零&#xff0c;这种特性使得电桥电路非常适合于精确测量电阻、电感、电容等电气参数&#xff0c;以及用于传感器和测量设备中。以下是电桥电路…

浏览器输入URL并回车都发生了什么?

浏览器输入URL并回车都发生了什么 **URL 解析****DNS 查询****TCP 连接建立与断开****应用层&#xff1a;发送 HTTP 请求****传输层&#xff1a;TCP 传输报文****网络层&#xff1a;IP 协议查询 MAC 地址****链路层&#xff1a;以太网协议****Mac 地址****三次握手****四次挥手…

C++初阶 | [十二] 模板进阶

摘要&#xff1a;非类型模板参数&#xff0c;类模板的特化&#xff0c;模板的分离编译&#xff0c;模板总结 前言&#xff1a;C初阶终篇 1. 非类型模板参数 类型模板参数&#xff1a;如下代码&#xff0c;T 为模板的类型参数。 #define N 10 template<class T> class …

从开关到模拟量,钡铼IOy系列模块全方位拓展PLC系统的边界

在现代工业自动化系统中&#xff0c;PLC&#xff08;可编程逻辑控制器&#xff09;作为控制核心&#xff0c;起着至关重要的作用。而随着工业自动化的不断发展&#xff0c;对于输入/输出&#xff08;IO&#xff09;模块的需求也日益增加&#xff0c;尤其是从简单的开关量到复杂…

统一处理异常和记录日志

统一处理异常 SpringBoot设计&#xff0c;如果出现错误404或500&#xff0c;自动调用特定路径下的html页面(路径和名字都特定)。/templates/error/404.html、/templates/error/500.html。程序中有错误自动就调用该页面。 但是错误有异步请求错误&#xff0c;也想同时记录日志。…

天诚智慧校园管理系统,变革高校物联网锁数智化通行新模式

三月草长莺飞&#xff0c;四月柳绿莺啼&#xff0c;在万物复苏的美好时节&#xff0c;历经半年的精心酝酿与匠心打磨&#xff0c;全场景AIoT解决方案服务商——江苏新巢天诚智能技术有限公司&#xff08;以下简称“天诚”&#xff09;正式推出新一代高校数智化通行管理平台——…

JavaEE 初阶篇-深入了解定时器、工厂模式和比较器

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 定时器概述 2.0 实现定时器 2.1 实现定时器 - 定义 MyTask 任务类 2.2 实现定时器 - MyTimer 定时器类存放任务的方法 2.3 实现定时器 - MyTimer 定时器类读取任务…

前端开发攻略---根据音频节奏实时绘制不断变化的波形图。深入剖析如何通过代码实现音频数据的可视化。

1、演示 2、代码分析 逐行解析 JavaScript 代码块&#xff1a; const audioEle document.querySelector(audio) const cvs document.querySelector(canvas) const ctx cvs.getContext(2d)这几行代码首先获取了 <audio> 和 <canvas> 元素的引用&#xff0c;并使用…

群晖虚拟机搭建Synology Drive并实现Obsidian笔记异地多端同步

文章目录 一、简介软件特色演示&#xff1a; 二、使用免费群晖虚拟机搭建群晖Synology Drive服务&#xff0c;实现局域网同步1 安装并设置Synology Drive套件2 局域网内同步文件测试 三、内网穿透群晖Synology Drive&#xff0c;实现异地多端同步Windows 安装 Cpolar步骤&#…

微服务-4 Nacos

目录 一、注册中心 二、配置管理 1. 添加配置 2. 配置自动刷新 3. 多环境配置共享​编辑 一、注册中心 服务列表&#xff1a; 服务详情&#xff1a; 二、配置管理 1. 添加配置 (1). 在 nacos 界面中添加配置文件&#xff1a; 配置列表&#xff1a; 配置详情&#xff1a;…