tag 标签: RT-Thread

相关帖子
相关博文
  • 热度 2
    2023-12-15 17:57
    394 次阅读|
    0 个评论
      SD NAND 也称之为贴片式TF卡,贴片式SD卡,采用标准的SDIO接口,兼容SPI接口。下图所示为CS 新一代CS SD NAND NP1GCR01-AOW 大小为128M,对比128M的SD卡,可以看到贴片SD卡尺寸更小,不要SD卡座,占用更小的PCB面积;也可以节省PCB板层数,2层板即可使用。而且兼容可替代普通TF卡/SD卡,硬件电路软件程序通用。本案例基于RT-Thread物联网操作系统,更是不需要编写任何复杂的驱动代码就可以SD NAND读写操作。    (文末提供,STM32驱动代码下载连接,需要可以自行下载)   将SD NAND插入SD卡卡座。首先,新建一个RT-Thread项目工程,这里基于Draco开发板创建。   完整的RT-thread项目默认是开启虚拟文件系统组件,RT-Thread DFS 组件的主要功能特点有:   为应用程序提供统一的 POSIX 文件和目录操作接口:read、write、poll/select 等。   支持多种类型的文件系统,如 FatFS、RomFS、DevFS 等,并提供普通文件、设备文件、网络文件描述符的管理。这里默认开启FatFS.   支持多种类型的存储设备,如 SD Card、SPI Flash、Nand Flash 等。   在 RT-Thread 中,我们要访问存储设备中的文件,必须将文件所在的分区挂载到一个已存在的路径上,然后通过这个路径来访问存储设备。在应用程序文件夹下可找到mnt.c源程序。可以看到挂载文件系统的代码如下所示。   上图通过自动化初始化代码实现文件系统挂载。挂载成功dfs_mount函数返回0.通过调试串口可以看到打印信息。Mount "/dev/sd0" on "/":0 done,说明SD NAND挂载成功。   读写文件测试:文件系统正常工作后,就可以运行应用示例,在该示例代码中,首先会使用 open() 函数创建一个文件 text.txt,并使用 write() 函数在文件中写入字符串 “RT-Thread Programmer!\n”,然后关闭文件。再次使用 open() 函数打开 text.txt 文件,读出其中的内容并打印出来,最后关闭该文件。   测试结果:在调试中断输入msh 命令readwrite_sample,即可运行案例。可以看到成功创建了文本,并写入了数据。    STM32驱动下载链接:https://pan.baidu.com/s/1t9Bd3YUNtQmgpyQbmOIMEA?pwd=8051   提取码:8051
  • 热度 2
    2023-4-22 18:26
    6031 次阅读|
    0 个评论
    《RT-Thread设备驱动开发指南》+熟悉RT-Thread PIN 设备驱动详情
    首次接触RT-Thread 也是在大学的时候,如今工作了,也经常用到RT-Thread。这里也十分感谢面包板社区提供的测评机会。 大部分工程师接触RT-Thread的入门学习都是从《RT-Thread设计与实现》或者官网开始的,这里不得不说RT-Thread 官网的资料市真的全啊。RT-Thread 设备驱动这本书主要为我们讲解了在RTT下面设备驱动的模型,作为一个应用开发工程师而已,如何实现应用层代码,在不同的设备上面去实现,是一个很头疼的问题。利用RT-Thread 设备驱动我们减少设备驱动移植的困难,加快应用的开发。 回归整体,《RT-Thread设备驱动开发指南》这本书不管是从外观、质量还是内容都是一流的。 PIN设备驱动作为GPIO的一个上层应用接口,是嵌入式开发中经常用到的一个基本外设,书中对PIN的层次结构、PIN的设备驱动实现方法做了详细的阐述。通过阅读可以让读者都底层动的实现方法有了大致了解,读者也可以修改RTT的底层,来实现自己的设备驱动或者移植到一个全新的MCU设备上面。同时书中最后给出了点亮LED的代码案例,使得读者心中豁然开朗,收益匪浅。
  • 热度 18
    2023-4-18 14:14
    6894 次阅读|
    0 个评论
    《RT-Thread设备驱动开发指南》--一本适合RT-Thread初学者的好书
    前段时间开始自学rt-thread,刚开始的时候我参考的教程是《 RT-Thread 内核实现与应用开发实战》,这是一份非常好的资料,围绕代码和试验现象详细讲解了每一个函数的作用,但,正是因为它太过事无巨细的讲解,导致我对整个rtt没有一个成体系的概念印象,也可能是因为它比较生涩,初学者看起来有点费劲。所以后来学习进程暂时搁置了。 直到这次有幸获得了《RT-Thread 设备驱动开发指南》的评测机会,只翻看了第一章我就认为《RT-Thread 设备驱动开发指南》是一本非常适合初学者的技术指南,该指南清晰地讲述了 RT-Thread 设备框架结构的概念,从而可以让人更好地理解 RT-Thread 的结构。在这个框架概念的基础上,该指南由浅入深地讲解了从常见的 pin、I2C、SPI 到复杂一些的 SDIO、触摸屏等设备驱动的开发。 首先,该指南的一个主要优点是它清晰地讲解了 RT-Thread 设备框架结构的概念。这个概念对于初学者来说非常重要,因为它可以帮助他们更好地理解 RT-Thread 操作系统的结构和工作原理。通过深入了解 RT-Thread 设备框架结构,开发人员可以更加清晰地了解设备驱动程序在 RT-Thread 中的角色和作用,从而更好地开发他们的应用程序。 其次,该指南围绕 RT-Thread 设备框架结构,由浅入深地讲解了从常见的 pin、I2C、SPI 到复杂一些的 SDIO、触摸屏等设备驱动的开发。这种基于实例的学习方式非常适合初学者,因为它可以帮助他们从实际问题中学习,提高他们的学习效率。通过在实际项目中演示如何开发各种类型的设备驱动,该指南可以让初学者更好地理解每个设备的特点和要求,并帮助他们开发高质量的设备驱动程序。 由于该指南以简单易懂的语言和实际项目为例进行讲解,结合详细的注释和解释,因此可以让初学者轻松理解和掌握书中的内容。此外,该指南在讲解设备驱动开发的过程中,也给出了很多实用的建议和技巧,可以让初学者更加高效地进行设备驱动开发。 总之,《RT-Thread 设备驱动开发指南》是一本非常优秀的技术指南,它清晰地讲解了 RT-Thread 设备框架结构的概念,并且围绕这个概念由浅入深地讲解了从常见的 pin、I2C、SPI 到复杂一些的 SDIO、触摸屏等设备驱动的开发。对于初学者来说,该指南是一本非常适合他们的案头书,常读常新。
  • 热度 10
    2020-4-18 17:39
    4136 次阅读|
    1 个评论
    rtthread移植到nios ii中
    上次参加面板版社区评测的活动,获得了一本 《RT_Thread内核实现与应用开发实战指南》 ,看完了这本书之后,因为我手上有fpga的开发板一直就想把rt_thread移植到fpga中。看了RT-Theread源码BSP文件夹中nios的readme_cn.txt的介绍尝试了之后编译不通过,总是提示缺少各种头文件。我手上的fpga开发板是 小梅哥 的AC620,正好在网上找到了小梅哥的文章进行学习参考尝试 http://www.elecfans.com/d/593679.html ,也是编译不过去。期间又在rt-thread nano学习群里请教了" rt_thread小师弟 ",他建议我在编译时提示缺什么文件就添加什么文件,最终我调试成功了。 1.根据小梅哥的文章先把fpga工程和硬件平台搭建好,并创建好nios ii eclipse工程。小梅哥写的很详细了,我就不在这里啰嗦了。 2.我先创建好rt_thread文件夹,并在文件夹里把RT_THREAD的bsp文件夹中nios文件全部拷入,include文件夹、libcpu文件夹、src文件夹和文件内容。然后整个rt-thread文件夹拖入工程中。如图 不用按照readme.txt文件中介绍的添加那一点文件 ,后面编译时还会报错添加好几个文件,不如现在一次把能添加进去的都添加进去。 根据小梅哥的提示把application文件从bsp中拖出到工程根目录中。在 设置中添加头文件搜索路径,选中工程,鼠标右击选择Properties选项,在弹出的对话框中选中Nios II Application Paths选项,添加include和bsp文件夹道头文件路径中,然后确认关闭。 如图 此时选中的路径是工程文件夹下include 和bsp路径。这一点我试了好久。 3.然后开始编译工程,当提示缺少什么文件时就从rt-thread源码文件中找相应的文件添加到工程文件夹中。我么在搭建硬件平台时我 么给各个接口取得名字还会和软件本身定义有出入对应不上,这里也会报错,我们要在system.h代码中找到自己定义的接口名称复制下来,把报错找不到的接口名称修改。 4.最后编译出错的地方是startup.c中一个地址定义 “_alt_partition_sdram_load_addr”,没有找到好的办法我就把这个功能屏蔽了,如图 最终编译通过下载到AC620 FPGA开发板中led灯正常闪烁 。
  • 热度 6
    2020-3-27 16:48
    11975 次阅读|
    1 个评论
    【RT-Thread学习笔记】11.线程的工作机制
    线程控制块 在RT-Thread中,线程控制块由结构体struct rt_thread表示,线程控制块是操作系统用于管理线程的一个数据结构,它会存放线程的一些信息,例如优先级、线程名称、线程状态等,也包含了线程与线程之间连接用的链表结构,线程等待事件集合等,详细定义如下: /* 线程控制块 */ struct rt_thread { /* rt 对象 */ char name ; /* 线程名称 */ rt_uint8_t type; /* 对象类型 */ rt_uint8_t flags; /* 标志位 */ rt_list_t list; /* 对象列表 */ rt_list_t tlist; /* 线程列表 */ /* 栈指针与入口指针 */ void *sp; /* 栈指针 */ void *entry; /* 入口函数指针 */ void *parameter; /* 参数 */ void *stack_addr; /* 栈地址指针 */ rt_uint32_t stack_size; /* 栈大小 */ /* 错误代码 */ rt_err_t error; /* 线程错误代码 */ rt_uint8_t stat; /* 线程状态 */ /* 优先级 */ rt_uint8_t current_priority; /* 当前优先级 */ rt_uint8_t init_priority; /* 初始优先级 */ rt_uint32_t number_mask; ...... rt_ubase_t init_tick; /* 线程初始化计数值 */ rt_ubase_t remaining_tick; /* 线程剩余计数值 */ struct rt_timer thread_timer; /* 内置线程定时器 */ void (*cleanup)(struct rt_thread *tid); /* 线程退出清除函数 */ rt_uint32_t user_data; /* 用户数据 */ }; 其中init_priority是线程创建时指定的线程优先级,在线程运行过程当中是不会被改变的(除非用户执行线程控制函数进行手动调整线程优先级)。cleanup会在线程退出时,被空闲线程回调一次以执行用户设置的清理现场等工作。最后一个成员user_data可由用户挂接一些数据信息到线程控制块中,以提供类似线程私有数据的实现。 线程重要属性 --线程栈 RT-Thread线程具有独立的栈,当进行线程切换时,会将当前线程的上下文存在栈中,当线程要恢复运行时,再从栈中读取上下文信息,进行恢复。 线程栈还用来存放函数中的局部变量:函数中的局部变量从线程栈空间中申请;函数中局部变量初始时从寄存器中分配(ARM架构),当这个函数再调用另一个函数时,这些局部变量将放入栈中。 对于线程第一次运行,可以以手动的方式构造这个上下文来设置一些初始的环境:入口函数(PC寄存器)、入口参数(R0寄存器)、返回位置(LR寄存器)、当前机器运行状态(CPSR寄存器)。 线程栈的增长方向是芯片架构密切相关的,RT-Thread 3.1.0以前的版本,均只支持栈由高地址向低地址增长的方式,对于ARM Cortex-M架构,线程栈构造如下图所示: 线程栈大小可以这样设定,对于资源相对较大的MCU,可以适当设计较大的线程栈;也可以在初始化时设置较大的栈,例如指定大小为1K或者2K字节,然后在FinSH中用list_thread命令查看线程运行的过程中线程所使用的栈的大小,通过此命令,能够看到从线程启动运行时,到当前时刻点,线程使用的最大栈深度,而后加上适当的余量形成最终的线程栈大小,最后对栈空间大小加以修改。 --线程状态 线程运行的过程中,同一时间内只允许一个线程在处理器中运行,从运行的过程上划分,线程有多种不同的运行状态,如初始状态、挂起状态、就绪状态等。在RT-Thread中,线程包含五种状态,操作系统会自动根据它运行的情况来动态调整它的状态。RT-Thread中线程的五种状态,如下表所示: 状态 描述 初始状态 当线程刚开始创建还没开始运行时就处于初始状态;在初始状态下,线程不参与调度。此状态在 RT-Thread 中的宏定义为 RT_THREAD_INIT 就绪状态 在就绪状态下,线程按照优先级排队,等待被执行;一旦当前线程运行完毕让出处理器,操作系统会马上寻找最高优先级的就绪态线程运行。此状态在 RT-Thread 中的宏定义为 RT_THREAD_READY 运行状态 线程当前正在运行。在单核系统中,只有 rt_thread_self() 函数返回的线程处于运行状态;在多核系统中,可能就不止这一个线程处于运行状态。此状态在 RT-Thread 中的宏定义为 RT_THREAD_RUNNING 挂起状态 也称阻塞态。它可能因为资源不可用而挂起等待,或线程主动延时一段时间而挂起。在挂起状态下,线程不参与调度。此状态在 RT-Thread 中的宏定义为 RT_THREAD_SUSPEND 关闭状态 当线程运行结束时将处于关闭状态。关闭状态的线程不参与线程的调度。此状态在 RT-Thread 中的宏定义为 RT_THREAD_CLOSE --线程优先级 RT-Thread线程的优先级是表示线程被调度的优先程度。每个线程都具有优先级,线程越重要,赋予的优先级就应越高,线程被调度的可能才会越大。 RT-Thread最大支持256个线程优先级(0~255),数值越小的优先级越高,0为最高优先级。在一些资源比较紧张的系统中,可以根据实际情况选择只支持8个或者32个优先级的系统配置;对于ARM Cortex-M系列,普遍采用32个优先级。最低优先级默认分配给空闲线程使用,用户一般不使用。在系统中,当有比当前线程优先级更高的线程就绪时,当前线程将立刻被换出,高优先级线程抢占处理器运行。 --时间片 每个线程都有时间片这个参数,但时间片仅对优先级相同的就绪状态的线程有效。系统对优先级相同的就绪态线程采用时间片轮转的调度方式时行调度时,时间片起到约束线程单次运行时长的作用,其单位是一个系统节拍(OS Tick),详见后面章节介绍。假设有2个优先级相同的就绪态线程A和B,A线程的时间片设置为10,B线程的时间片设置为5,那么当系统中不存在比A优先级高的就绪态线程时,系统会在A、B线程间来回切换执行,并且每次A线程执行10个节拍的时长,对B线程执行5个节拍的时长,如下图: --线程的入口函数 线程控制块中的entry是线程的入口函数,它是线程实现预期功能的函数。线程的入口函数由用户设计实现,一般有以下两种代码形式: ----无限循环模式: 在实时系统中,线程通常是被动式的:这个是由实时系统的特性所决定的,实时系统通常总是等待外界事件的发生,而后进行相应的服务: void thread_entry(void* paramenter) { while (1) { /* 等待事件的发生 */ /* 对事件进行服务、进行处理 */ } } 线程看似没有什么限制程序执行的因素,似乎所有的操作都可以执行。但是作为一个实时系统,一个优先级明确的实时系统,如果一个线程中的程序陷入了死循环操作,那么比它优先级低的线程都将不能够得到执行。所以在实时操作系统中必须注意的一点就是:线程中不能陷入死循环操作,必须要有让出CPU使用权的动作,如循环中调用延时函数或者主动挂起。用户设计这种无限循环的线程的目的,就是为了让这个线程一直被系统循环调度运行,永不删除。 ----顺序执行或有限次循环模式: 如简单的顺序语句、do while或for循环等,此类线程不会循环或者不会永久循环,可谓是一次性线程,一定会被执行完毕。在执行完毕后,线程将被系统自动删除。 static void thread_entry(void* parameter) { /* 处理事务 #1 */ … /* 处理事务 #2 */ … /* 处理事务 #3 */ } --线程错误码 一个线程就是一个执行场景,错误码是与执行环境密切相关的,所以每个线程配备了一个变量用于保存错误码,线程的错误码有以下几种: #define RT_EOK 0 /* 无错误 */ #define RT_ERROR 1 /* 普通错误 */ #define RT_ETIMEOUT 2 /* 超时错误 */ #define RT_EFULL 3 /* 资源已满 */ #define RT_EEMPTY 4 /* 无资源 */ #define RT_ENOMEM 5 /* 无内存 */ #define RT_ENOSYS 6 /* 系统不支持 */ #define RT_EBUSY 7 /* 系统忙 */ #define RT_EIO 8 /* IO 错误 */ #define RT_EINTR 9 /* 中断系统调用 */ #define RT_EINVAL 10 /* 非法参数 */ 线程状态切换 RT-Thread提供一系列的操作系统调用接口,使得线程的状态在这五个状态之间来回切换。几种状态间的转换关系如下图所示: 线程通过调用函数rt_thread_create()/rt_thread_init()进入到初始化状态(RT_THREAD_INIT);初始状态的线程通过调用rt_thread_startup()进入到就绪状态(RT_THREAD_READY);就绪状态的线程被调度器调度后进入运行状态(RT_THREAD_RUNNING);当处于运行状态的线程调用rt_thread_delay(),rt_sem_take(),rt_mutex_take(),rt_mb_recv()等函数或者获取不到资源时,将进入到挂起状态(RT_THREAD_SUSPEND);处于挂起状态的线程,如果等待超时依然未能获得资源或者由于其它线程释放了资源,那么它将返回到就绪状态。挂起状态的线程,如果调用rt_thread_delete()/rt_thread_detach()函数,将更改为关闭状态(RT_THREAD_CLOSE);而运行状态的线程,如果运行结束,就会在线程的最后部分执行rt_thread_exit()函数,将状态更改为关闭状态。 注意: RT-Thread中,实际上线程并不存在运行状态,就绪状态和运行状态是等同的。 系统线程 前文中已经提到,系统线程是指由系统创建的线程,用户线程是由用户程序调用线程管理接口创建的线程,在RT-Thread内核中的系统线程有空闲线程和主线程。 --空闲线程 空闲线程是系统创建的最低优先级的线程,线程状态永远为就绪状态。当系统中无其它就绪线程存在时,调度器将调度到空闲线程,它通常是一个死循环,且永远不能被挂起。另外,空闲线程在RT-Thread也有着它的特殊用途: 在某个线程运行完毕,系统将自动删除线程:自动执行rt_thread_exit()函数,先将该线程从系统就绪队列中删除,再将该线程的状态更改为关闭状态,不再参与系统调度,然后挂入rt_thread_defunct僵尸队列(资源未回收、处于关闭状态的线程队列)中,最后空闲线程会回收被删除线程的资源。 空闲线程也提供了接口来运行用户设置的钩子函数,在空闲线程运行时会调用该钩子函数,适合钩入功耗管理、看门狗喂狗等工作。 --主线程 在系统启动时,系统会创建main线程,它的入口函数为main_thread_entry(),用户的应用入口函数main()就是从这里真正开始的,系统调度器启动后,main线程就开始运行,过程如下图,用户可以在main()函数里添加自己的应用程序初始化代码。
相关资源