[活动] 极海半导体APM32F411开发板评测 移植RT-Thread

[复制链接]
4993|4
 楼主| lemonhub 发表于 2024-5-13 20:32 | 显示全部楼层 |阅读模式
极海半导体APM32F411开发板评测  移植RT-Thread1. 软硬件平台
  • APM32F411Tiny Board开发板
  • MDK-ARM Keil

2. 物联网RTOS—RT-Thread
RT-Thread Nano 是一个极简版的硬实时内核,它是由 C 语言开发,采用面向对象的编程思维,具有良好的代码风格,是一款可裁剪的、抢占式实时多任务的 RTOS。其内存资源占用极小,功能包括任务处理、软件定时器、信号量、邮箱和实时调度等相对完整的实时操作系统特性。适用于大量使用的 32 位 ARM 入门级 MCU 的场合。
下图是 RT-Thread Nano 的软件框图,包含支持的 CPU 架构与内核源码,还有可拆卸的 FinSH 组件:
apm32-rtt-00.jpg
支持架构:ARM:Cortex M0/ M3/ M4/ M7 等、RISC-V 及其他。
功能:线程管理、线程间同步与通信、时钟管理、中断管理、内存管理。
RT-Thread Nano的特点
  • 下载简单
    RT-Thread Nano 以软件包的方式集成在 Keil MDK 与 CubeMX 中,可以直接在软件中下载 Nano 软件包获取源码,获取方式详见 基于 Keil MDK 移植 RT-Thread Nano 与 基于 CubeMX 移植 RT-Thread Nano 。同时也提供 下载 Nano 源码压缩包 的途径,方便在其他开发环境移植 RT-Thread Nano,如 基于 IAR 移植 RT-Thread Nano。
  • 代码简单 与RT-Thread 完整版不同的是,Nano 不含 Scons 构建系统,不需要 Kconfig 以及 Env 配置工具,也去除了完整版特有的 device 框架和组件,仅是一个纯净的内核。
  • 移植简单 由于 Nano 的极简特性,使 Nano 的移植过程变得极为简单。添加 Nano 源码到工程,就已完成 90% 的移植工作。
  • 易裁剪:Nano 的配置文件为 rtconfig.h,该文件中列出了内核中的所有宏定义,有些默认没有打开,如需使用,打开即可。
  • 易添加 FinSH 组件:FinSH 组件 可以很方便的在 Nano 上进行移植,而不再依赖 device 框架,只需要对接两个必要的函数即可完成 FinSH 移植。
  • 资源占用小:对 RAM 与 ROM 的开销非常小,在支持 semaphore 和 mailbox 特性,并运行两个线程 (main 线程 + idle 线程) 情况下,ROM 和 RAM 依然保持着极小的尺寸,RAM 占用约 1K 左右,ROM 占用 4K 左右。

移植过程
  • RT-Thread Nano 内核移植
    RT-Thread Nano移植较为简单,参考官方教程。我这里里面可能有少步骤的,大体也差不多。其实我实际对接内核就改了一个SystemClock_Config()函数的实现,其他的基本上没有太大变化,然后就是一些宏定义的打开,特别是你需要使用FINSH组件的时候。
    官方移植教程 基于 Keil MDK 移植 RT-Thread Nano

    • 在之前的工程模板基础上,添加RT-Thread Nano代码文件。在keil里面添加文件即可。
      apm32-rtt-01.jpg
    • 需要注意是,RT-Thread/port里面需要选择与芯片匹配的文件,APM32F411是Cortex-M4内核的芯片,选择添加相关文件。Cortex-M 芯片内核移植文件如下:
    • 将SysTick_Handler移到RTOS目录下的board.c内,并添加回调函数rt_os_tick_callback();复制例程中相关堆栈初始化的代码。
      由于 SysTick_Handler() 中断服务例程由用户在 board.c 中重新实现,做了系统 OS Tick,所以还需要删除工程里中原本已经实现的 SysTick_Handler() ,避免在编译时产生重复定义。如果此时对工程进行编译,没有出现函数重复定义的错误,则不用做修改.
      apm32-rtt-02.jpg
      apm32-rtt-03.jpg
    • RT-Thread 会接管异常处理函数 HardFault_Handler() 和悬挂处理函数 PendSV_Handler(),这两个函数已由 RT-Thread 实现,所以需要删除工程里中断服务例程文件中的这两个函数,避免在编译时产生重复定义。如果此时对工程进行编译,没有出现函数重复定义的错误,则不用做修改。因此在我们的工程里面需要把apm32f4xx_int.c文件中的HardFault_Handler、PendSV_Handler、SysTick_Handler函数注释掉。
      apm32-rtt-04.jpg
    • 尝试移植中景园OLED代码。修改对应GPIO代码后,将延时改为RTT的延时函数后,正常使用。
      1. #include "main.h"
      2. #include "oled.h"
      3. #include <stdlib.h>
      4. #include "oledfont.h"
      5. #include "Bsp_delay.h"

      6. //OLED的显存
      7. //存放格式如下.
      8. //[0]0 1 2 3 ... 127       
      9. //[1]0 1 2 3 ... 127       
      10. //[2]0 1 2 3 ... 127       
      11. //[3]0 1 2 3 ... 127       
      12. //[4]0 1 2 3 ... 127       
      13. //[5]0 1 2 3 ... 127       
      14. //[6]0 1 2 3 ... 127       
      15. //[7]0 1 2 3 ... 127

      16. #define SIZE 8
      17. #define XLevelL                0x00
      18. #define XLevelH                0x10
      19. #define Max_Column        128
      20. #define Max_Row                64
      21. #define        Brightness        0xFF
      22. #define X_WIDTH         128
      23. #define Y_WIDTH         64                                                              
      24. //-----------------OLED IIC端口定义----------------                                            

      25. #define OLED_SCLK_Clr() GPIO_ResetBit(GPIOB,GPIO_PIN_8) //CLK
      26. #define OLED_SCLK_Set() GPIO_SetBit(GPIOB,GPIO_PIN_8)

      27. #define OLED_SDIN_Clr() GPIO_ResetBit(GPIOB,GPIO_PIN_9)//SDA
      28. #define OLED_SDIN_Set() GPIO_SetBit(GPIOB,GPIO_PIN_9)

      29. #define OLED_CMD  0        //写命令
      30. #define OLED_DATA 1        //写数据


      31. /**********************************************
      32. //IIC Start
      33. **********************************************/
      34. void IIC_Start()
      35. {
      36.         OLED_SCLK_Set() ;
      37.         OLED_SDIN_Set();
      38.         OLED_SDIN_Clr();
      39.         OLED_SCLK_Clr();
      40. }
      41. /**********************************************
      42. //IIC Stop
      43. **********************************************/
      44. void IIC_Stop()
      45. {
      46.         OLED_SCLK_Set() ;
      47. //        OLED_SCLK_Clr();
      48.         OLED_SDIN_Clr();
      49.         OLED_SDIN_Set();
      50. }

      51. void IIC_Wait_Ack()
      52. {
      53.         OLED_SCLK_Set() ;
      54.         OLED_SCLK_Clr();
      55. }

      56. /**********************************************
      57. // IIC Write byte
      58. **********************************************/

      59. void Write_IIC_Byte(unsigned char IIC_Byte)
      60. {
      61.         unsigned char i;
      62.         unsigned char m,da;
      63.         da=IIC_Byte;
      64.         OLED_SCLK_Clr();
      65.         for(i=0;i<8;i++)               
      66.         {
      67.                 m=da;

      68.                 m=m&0x80;
      69.                 if(m==0x80)
      70.                 {OLED_SDIN_Set();}
      71.                 else OLED_SDIN_Clr();
      72.                         da=da<<1;
      73.                 OLED_SCLK_Set();
      74.                 OLED_SCLK_Clr();
      75.         }
      76. }

      77. /**********************************************
      78. // IIC Write Command
      79. **********************************************/
      80. void Write_IIC_Command(unsigned char IIC_Command)
      81. {
      82.         IIC_Start();
      83.         Write_IIC_Byte(0x78);            //Slave address,SA0=0
      84.         IIC_Wait_Ack();       
      85.         Write_IIC_Byte(0x00);                        //write command
      86.         IIC_Wait_Ack();       
      87.         Write_IIC_Byte(IIC_Command);
      88.         IIC_Wait_Ack();       
      89.         IIC_Stop();
      90. }

      91. /**********************************************
      92. // IIC Write Data
      93. **********************************************/
      94. void Write_IIC_Data(unsigned char IIC_Data)
      95. {
      96.         IIC_Start();
      97.         Write_IIC_Byte(0x78);                        //D/C#=0; R/W#=0
      98.         IIC_Wait_Ack();       
      99.         Write_IIC_Byte(0x40);                        //write data
      100.         IIC_Wait_Ack();       
      101.         Write_IIC_Byte(IIC_Data);
      102.         IIC_Wait_Ack();       
      103.         IIC_Stop();
      104. }
      105. void OLED_WR_Byte(unsigned dat,unsigned cmd)
      106. {
      107.         if(cmd)
      108.         {
      109.                 Write_IIC_Data(dat);
      110.         }
      111.         else
      112.         {
      113.                 Write_IIC_Command(dat);
      114.         }
      115. }

      116. /********************************************
      117. // fill_Picture
      118. ********************************************/
      119. void fill_picture(unsigned char fill_Data)
      120. {
      121.         unsigned char m,n;
      122.         for(m=0;m<8;m++)
      123.         {
      124.                 OLED_WR_Byte(0xb0+m,0);                //page0-page1
      125.                 OLED_WR_Byte(0x00,0);                //low column start address
      126.                 OLED_WR_Byte(0x10,0);                //high column start address
      127.                 for(n=0;n<128;n++)
      128.                 {
      129.                         OLED_WR_Byte(fill_Data,1);
      130.                 }
      131.         }
      132. }

      133. //坐标设置

      134. void OLED_Set_Pos(unsigned char x, unsigned char y)
      135. {         OLED_WR_Byte(0xb0+y,OLED_CMD);
      136.         OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
      137.         OLED_WR_Byte((x&0x0f),OLED_CMD);
      138. }             
      139. //开启OLED显示   
      140. void OLED_Display_On(void)
      141. {
      142.         OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
      143.         OLED_WR_Byte(0X14,OLED_CMD);  //DCDC ON
      144.         OLED_WR_Byte(0XAF,OLED_CMD);  //DISPLAY ON
      145. }
      146. //关闭OLED显示     
      147. void OLED_Display_Off(void)
      148. {
      149.         OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
      150.         OLED_WR_Byte(0X10,OLED_CMD);  //DCDC OFF
      151.         OLED_WR_Byte(0XAE,OLED_CMD);  //DISPLAY OFF
      152. }                                            
      153. //清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!          
      154. void OLED_Clear(void)  
      155. {  
      156.         u8 i,n;                    
      157.         for(i=0;i<8;i++)  
      158.         {  
      159.                 OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
      160.                 OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
      161.                 OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址   
      162.                 for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA);
      163.         } //更新显示
      164. }
      165. void OLED_On(void)  
      166. {  
      167.         u8 i,n;                    
      168.         for(i=0;i<8;i++)  
      169.         {  
      170.                 OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
      171.                 OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
      172.                 OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址   
      173.                 for(n=0;n<128;n++)OLED_WR_Byte(1,OLED_DATA);
      174.         } //更新显示
      175. }
      176. //在指定位置显示一个字符,包括部分字符
      177. //x:0~127
      178. //y:0~63
      179. //mode:0,反白显示;1,正常显示                                 
      180. //size:选择字体 16/12
      181. void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size)
      182. {             
      183.         unsigned char c=0,i=0;       
      184.                 c=chr-' ';//得到偏移后的值                       
      185.                 if(x>Max_Column-1){x=0;y=y+2;}
      186.                 if(Char_Size ==16)
      187.                         {
      188.                         OLED_Set_Pos(x,y);       
      189.                         for(i=0;i<8;i++)
      190.                         OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);
      191.                         OLED_Set_Pos(x,y+1);
      192.                         for(i=0;i<8;i++)
      193.                         OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);
      194.                         }
      195.                         else {       
      196.                                 OLED_Set_Pos(x,y);
      197.                                 for(i=0;i<6;i++)
      198.                                 OLED_WR_Byte(F6x8[c][i],OLED_DATA);
      199.                                
      200.                         }
      201. }
      202. //m^n函数
      203. u32 oled_pow(u8 m,u8 n)
      204. {
      205.         u32 result=1;         
      206.         while(n--)result*=m;   
      207.         return result;
      208. }                                  
      209. //显示2个数字
      210. //x,y :起点坐标         
      211. //len :数字的位数
      212. //size:字体大小
      213. //mode:模式        0,填充模式;1,叠加模式
      214. //num:数值(0~4294967295);                           
      215. void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size2)
      216. {                
      217.         u8 t,temp;
      218.         u8 enshow=0;                                                  
      219.         for(t=0;t<len;t++)
      220.         {
      221.                 temp=(num/oled_pow(10,len-t-1))%10;
      222.                 if(enshow==0&&t<(len-1))
      223.                 {
      224.                         if(temp==0)
      225.                         {
      226.                                 OLED_ShowChar(x+(size2/2)*t,y,' ',size2);
      227.                                 continue;
      228.                         }else enshow=1;
      229.                           
      230.                 }
      231.                  OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2);
      232.         }
      233. }
      234. //显示一个字符号串
      235. void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size)
      236. {
      237.         unsigned char j=0;
      238.         while (chr[j]!='\0')
      239.         {
      240.                 OLED_ShowChar(x,y,chr[j],Char_Size);
      241.                 x+=8;
      242.                 if(x>120){x=0;y+=2;}
      243.                         j++;
      244.         }
      245. }
      246. //显示汉字
      247. void OLED_ShowCHinese(u8 x,u8 y,u8 no)
      248. {                                  
      249.         u8 t,adder=0;
      250.         OLED_Set_Pos(x,y);       
      251.     for(t=0;t<16;t++)
      252.         {
      253.                 OLED_WR_Byte(Hzk[2*no][t],OLED_DATA);
      254.                 adder+=1;
      255.      }       
      256.         OLED_Set_Pos(x,y+1);       
      257.     for(t=0;t<16;t++)
      258.         {       
      259.                 OLED_WR_Byte(Hzk[2*no+1][t],OLED_DATA);
      260.                 adder+=1;
      261.       }                                       
      262. }
      263. /***********功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/
      264. void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[])
      265. {        
      266. unsigned int j=0;
      267. unsigned char x,y;
      268.   
      269.   if(y1%8==0) y=y1/8;      
      270.   else y=y1/8+1;
      271.         for(y=y0;y<y1;y++)
      272.         {
      273.                 OLED_Set_Pos(x0,y);
      274.     for(x=x0;x<x1;x++)
      275.             {      
      276.                     OLED_WR_Byte(BMP[j++],OLED_DATA);                   
      277.             }
      278.         }
      279. }

      280. //初始化SSD1306                                            
      281. void OLED_Init(void)
      282. {       
      283.         GPIO_Config_T  configStruct;
      284.          /* Enable the GPIO_LED Clock */
      285.     RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOB);
      286.        
      287.     GPIO_ConfigStructInit(&configStruct);
      288.     configStruct.pin = GPIO_PIN_8|GPIO_PIN_9;
      289.     configStruct.mode = GPIO_MODE_OUT;
      290.         configStruct.otype = GPIO_OTYPE_PP;
      291.         configStruct.pupd = GPIO_PUPD_UP;
      292.     configStruct.speed = GPIO_SPEED_50MHz;
      293.         GPIO_Config(GPIOB, &configStruct);
      294.         GPIO_SetBit(GPIOB,GPIO_PIN_8);
      295.         GPIO_SetBit(GPIOB,GPIO_PIN_9);
      296.        
      297.         rt_thread_delay(200);

      298.         OLED_WR_Byte(0xAE,OLED_CMD);//--display off
      299.         OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
      300.         OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
      301.         OLED_WR_Byte(0x40,OLED_CMD);//--set start line address  
      302.         OLED_WR_Byte(0xB0,OLED_CMD);//--set page address
      303.         OLED_WR_Byte(0x81,OLED_CMD); // contract control
      304.         OLED_WR_Byte(0xFF,OLED_CMD);//--128   
      305.         OLED_WR_Byte(0xA1,OLED_CMD);//set segment remap
      306.         OLED_WR_Byte(0xA6,OLED_CMD);//--normal / reverse
      307.         OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
      308.         OLED_WR_Byte(0x3F,OLED_CMD);//--1/32 duty
      309.         OLED_WR_Byte(0xC8,OLED_CMD);//Com scan direction
      310.         OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset
      311.         OLED_WR_Byte(0x00,OLED_CMD);//
      312.        
      313.         OLED_WR_Byte(0xD5,OLED_CMD);//set osc division
      314.         OLED_WR_Byte(0x80,OLED_CMD);//
      315.        
      316.         OLED_WR_Byte(0xD8,OLED_CMD);//set area color mode off
      317.         OLED_WR_Byte(0x05,OLED_CMD);//
      318.        
      319.         OLED_WR_Byte(0xD9,OLED_CMD);//Set Pre-Charge Period
      320.         OLED_WR_Byte(0xF1,OLED_CMD);//
      321.        
      322.         OLED_WR_Byte(0xDA,OLED_CMD);//set com pin configuartion
      323.         OLED_WR_Byte(0x12,OLED_CMD);//
      324.        
      325.         OLED_WR_Byte(0xDB,OLED_CMD);//set Vcomh
      326.         OLED_WR_Byte(0x30,OLED_CMD);//
      327.        
      328.         OLED_WR_Byte(0x8D,OLED_CMD);//set charge pump enable
      329.         OLED_WR_Byte(0x14,OLED_CMD);//
      330.        
      331.         OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
      332. }  

    • apm32-rtt-05.jpg


szt1993 发表于 2024-5-23 18:00 | 显示全部楼层
显示屏是IIC通信,刷新速率如何?
钓鱼大师 发表于 2025-5-26 17:21 | 显示全部楼层
HardFault_Handler函数屏蔽了之后,在RT-THREAD中是在 context_rvds.S  中用汇编语言实现的吗?
分形梦想家 发表于 2025-5-30 17:44 | 显示全部楼层
Cortex-M4内核跑这个RT-Tread是不是轻松的狠啊
涡流远见者 发表于 2025-5-31 08:52 | 显示全部楼层
OLED屏刷新使用DMA的优势在哪里呢?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

20

主题

80

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部