hichard
hichard - 认证专家

注册于 5 years ago

回答
31
文章
0
关注者
1

在启动代码里,楼上这种这是rtt向厂商妥协的结果。事实上启动向量表应该在libcpu下,和厂商无关的。厂商的启动代码应该干掉。

楼上不能误导人,改掩码就失去分网段的意义了。这种应该是三层交换机通过VLAN划分网段的,你跟着看看设备收到的IP包是否是带VLAN TAG的,是否做了正确处理?多年前,处理过这个,之前lwip对VLAN支持不好,或者说处理是错的,当时打了一个patch,现在的lwip处理是对的,看看打开了没有。

https://club.rt-thread.org/ask/question/428671.html
这个帖子 看看专家的答复
没按照专家做的 都是投机
不挂是运气 挂了是正常

这个要清除中断pend标记。你关闭了中断,但是仍然会产生pend标记,下次开中断,早就直接执行中断服务函数。

tinyGPSPlus是最好的gps解析库,没有之一!支持任意指令的定制,扩展性好的也是最好,没有之一

都可以。fopen是c库标准,open是posix标准。open的应用也很广,但是c库支持的函数功能更多,这个要看自己的选择了。

上报的phy状态,这不是错误信息。具体可以去看看phy芯片的phy状态寄存器

你的接受缓冲区配置大,才可以接受更大的数据。记得默认是4096

下面的流程基本适用于所有的处理器,具体代码实现以Cortex-M为例。
在Cortex-M处理器上,Bootloader程序可以使用RTOS,也可以裸机实现,但是都要遵循以下流程。现在总结如下:
1.内核级,实现堆栈切换,跳转指令
2.NVIC级别,关闭所有的NVIC中断,清空所有pend的中断
3.具体芯片级,复位必要的外设,尤其是EXTI这类。SDRAM QSPI FLASH这类不需要复位,也不能复位。
下面着重讲解上面三级代码的具体实现,这3步是相互嵌套是关系。最终用户调用的都具体芯片级别的跳转函数。
1.内核级
实现函数__hal_app_jump,该函数的C语言声明为:extern void __hal_app_jump(rt_uint32_t u32AppAddr);
具体源码是汇编语言实现的,如下:

__hal_app_jump
    CPSID   I                       ;  关闭中断

    LDR     R1, =0xE000ED08         ;  切换向量表到应用程序的起始地址
    STR     R0, [R1]

    MOV     R2, #0x00               ;  切换工作模式,工作到特权级的线程模式  使用MSP
    MSR     CONTROL, R2

    LDR     R1, [R0]                ;  设置堆栈指针
    MOV     SP, R1

    CPSIE   I                       ;  使能中断
    LDR        R0, [R0, #4]        ;  设置当前PC的值,开始运行新的应用程序
    BX      R0

通过注释,可以很清晰的明白本函数的功能,该函数完整实现了bootloader的跳转流程,一些裸机场合,有些可能就不需要实现。
2.NVIC级别
先上代码,在根据代码来讲解。

void hal_app_jump(rt_uint32_t u32AppAddr)
{
          /**
          * Step1, 关闭中断
          */
          __asm("  CPSID   I\n");
          
          /**
          * Step2, 关闭NVIC中的所有中断
          */
          memset((void *)HAL_NVIC_DIS_BASE, 0, sizeof(rt_uint32_t) * 8);
          
            /**
          * Step3, 清空NVIC中已经Pending中的所有中断
          */
          memset((void *)HAL_NVIC_PEND_CLEAR_BASE, 0, sizeof(rt_uint32_t) * 8);
          
          /**
          * Step4, 清空Systick中断及已经挂起的中断
          */
          HWREG32(HAL_NVIC_ST_CTRL) = 0;
          HWREG32(HAL_NVIC_INT_CTRL) |= ((1UL << 25) | (1UL << 27));
          
          /**
          * Step5, 执行跳转流程
          */
          __hal_app_jump(u32AppAddr);
}

可以看到NVIC级别,分5步,如果是非Cortex-M处理器,也是这5步,主要是对中断控制器清零,复位操作,避免在跳转的瞬间正好遇上了中断,造成乱跳转,跑飞。第五步
调用了步骤1的函数,执行真正的跳转。

3.具体芯片级别,
先上代码,再来谈具体实现。

void rt_hw_app_jump(rt_uint32_t u32AppAddr)
{
          /**
          * Step1, 关闭中断
          */
          rt_hw_interrupt_disable();
          
          /**
          * Step2, 如果需要的话,复位除GPIO、SYSCFG、PWR和QSPI外的所有外设
          */ 
          //SystemPeripheralAllReset();
          HWREG32(RCC_BASE + RCC_AHB3RSTR) = 0x7FFFBFFF;
          HWREG32(RCC_BASE + RCC_AHB1RSTR) = 0xFFFFFFFF;
          HWREG32(RCC_BASE + RCC_AHB2RSTR) = 0xFFFFFFFF;
          HWREG32(RCC_BASE + RCC_AHB4RSTR) = 0xFFFF0000;
          HWREG32(RCC_BASE + RCC_APB3RSTR) = 0xEFFFFFFF;
          HWREG32(RCC_BASE + RCC_APB1LRSTR) = 0xFFFFFFFF;
          HWREG32(RCC_BASE + RCC_APB1HRSTR) = 0xEFFFFFFF;
          HWREG32(RCC_BASE + RCC_APB2RSTR) = 0xFFFFFFFF;
          HWREG32(RCC_BASE + RCC_APB4RSTR) = 0xEFFFFFFD;
          
          HWREG32(RCC_BASE + RCC_AHB3RSTR) = 0;
          HWREG32(RCC_BASE + RCC_AHB1RSTR) = 0;
          HWREG32(RCC_BASE + RCC_AHB2RSTR) = 0;
          HWREG32(RCC_BASE + RCC_AHB4RSTR) = 0;
          HWREG32(RCC_BASE + RCC_APB3RSTR) = 0;
          HWREG32(RCC_BASE + RCC_APB1LRSTR) = 0;
          HWREG32(RCC_BASE + RCC_APB1HRSTR) = 0;
          HWREG32(RCC_BASE + RCC_APB2RSTR) = 0;
          HWREG32(RCC_BASE + RCC_APB4RSTR) = 0;
          
          /**
          * Step3, 执行跳转
          */
          rt_hw_cpu_icache_disable();
          rt_hw_cpu_dcache_disable();
          HWREG32(HAL_ACCESS_CACR) &= ~(((rt_uint32_t)1) << 2); //  禁止D-CACHE透写
          hal_app_jump(u32AppAddr);
}

具体芯片级别分了3步,该函数是H7下的例子。该步骤主要就是清除具体是外设,让CPU恢复到最初上电时的状态。第三步执行了NVIC级别的跳转函数。应用层只要调用该函数即可实现跳转。
如,如果要跳转到0x08020000处执行代码,则可以运行代码:rt_hw_app_jump(0x08020000),,严谨一点,跳转代码写如下:

 if((HWREG32(0x08020000) != 0xFFFFFFFF) && 
     (HWREG32(0x08020000) >= 0x20000000) && 
       (HWREG32(0x08020000) < STM32_HEAP_END) && 
         (HWREG32(0x08020000 + 4) != 0xFFFFFFFF) && 
           (HWREG32(0x08020000 + 4) >= 0x08020000))
  {
    rt_hw_app_jump(HN_APP_ADDR);
  }

4.其他问题
上面描述基本已经可以实现一个完整的BootLoader跳转了。细心的读者可能发现,复位外设,缺没有复位GPIO等外设,这里其实可能一些潜在隐患。如果BootLoader里面使用了GPIO中断,
在跳转的瞬间,由于静电干扰造成触发了中断信号,也可能造成跳转失败。这里比较妥当的做法当然的将EXIT的GPIO中断关闭,这通常是在按键驱动实现的。建议的是,如果在BootLoader中open了某个
外设,那么跳转前,请先close掉,在跳转。其它特殊的硬件,如有存在外部看门狗,不能关闭,在跳转前最好先喂狗一次,避免跳转的时候发生看门狗溢出,造成跳转不成功。

读完本文,读者是不是发现跳转没有那么简单。跳转异常基本都是跳转瞬间发生中断引起,只要控制好中断,就能控制好跳转流程。

hichard

VPN并无绝对的标准。你要移植openVPN的话,资源需求大,一般MCU应该难以实现。但是自定义一种VPN就容易了,需求资源少,实现可以非常简单,但是服务器端也要自己写。既然自定义,服务器端肯定不是什么问题了

推荐一个比较简单的,可以使能lo回环网卡,采用本地回环网卡UDP的方式实现通信。

查看micropy目录的doc下的文档,有详细的说明,很容易学会

多看大神的代码!rt-thread内核就是一个架构非常优秀的代码,多阅读内核,多阅读设备框架。

发布
问题

分享
好友