whj467467222
whj467467222 - 认证专家
开源,分享,交流,共同进步

注册于 3 years ago

回答
385
文章
28
关注者
24

先说结论: 可以。

modbus 是一种主从模型的通讯协议,每次通讯都是由主机发起,从机回复,从机不会主动发送数据。从机的协议栈在接收到自己的报文之后,经过解析并不是自己对应 ID 的报文,那么就不会响应主机的报文,所以同一时刻总线上只有一个 ID 在发送报文。

如果我的答案帮到你了,请点个采纳,这是我继续回答问题的动力。

两种方法你都可以试一下,第二种方法有几率不成功:

第一种:修改 MDK 的配置文件,http://www.openedv.com/forum.php?mod=viewthread&tid=279161

第二种:升级 ST_LINK 固件,https://github.com/armink/HackSTLinkUpgrade

这题我正好测试过,请楼主确定几个点:

  1. SPI 轮训是正常的
  2. SPI 请使用 DMA1 或者 DMA2
  3. SPI 会使用到 rt_malloc , heap 确保是 AXI SRAM
  4. MPU 配置的 cache 策略
  5. drv_spi.c 中在开启 DMA 之后,对应的 SPI 外设中断是否开启了.

如果 SPI 轮训是正常的,请使用 DMA1 或者 DMA2.
因为 DMA1 DMA2 无法访问到 TCM,如果确保 rt_malloc 是从 AXI SRAM 申请的内存.
cache这里,如果你参考的 ART-Pi 或者 STM32H743-ATK-APLLO 那么这里就不需要修改.
检查是否对用的 外设中断函数是否有.

当然可以的。

提交到 gitee 的时候请选择分支为 gitee_master 这个分支。

image.png

出现这种情况,可以这样检查:

  1. 检查对应的宏是否打开;

stm32f4xx_hal_conf.h 中检查 HAL_SDRAM_MODULE_ENABLED 是否取消了注释。

  1. 检查对应的源文件是否参与了构建

image.png

如图所示,在导航器中查看对应的文件,这个文件如果打了一个斜线,表示这个文件没有参与到构建。

如果没有导航器,可以在 窗口 -> 显示视图 -> 导航器 来调出这个选项

一个线程最小需要的栈空间,可以在 cpuport.c 查看并获取到。

在 RTOS 进行线程切换的时候,必须要为每个线程保护现场,保护现场就是把寄存器压入栈,具体压多少,这个取决于你的架构,常见的 cortex_M 需要保存的栈大小由结构体,struct stack_frame 来决定,如果你开启了 FPU 那么最小需要的栈空间就又会变大了。

回到楼主的问题:

  1. 请教一下具体要怎么计算?

答:使用 sizeof(struct stack_frame) 求出最小的栈空间,根据你实际使用的局部变量,最好再加一点。另外你也可以通过终端上的 ps 命令查看每个线程的栈使用百分比

  1. 假设函数里面全部用静态变量和全局变量,是不是只需要设置一个最小栈,最小栈是多大呢?

答:你强迫症的一定要使用最小栈运行系统,你还要保证你这个线程不要调用任何函数,因为函数也会压栈。

  1. 是什么占用了?

答:RTOS 为了保护现场保存的系统寄存器的值

关于如何让出线程楼主已经提到了 rt_thread_delay 或者 sleep 等接口,实际上在 RT-Thread 让出线程的操作其他的形式,比如:获取信号量而又拿不到的时候。

finsh_thread_entry 中实现线程让出的函数是

以下函数有删减

static int finsh_getchar(void)
{
    char ch = 0;

    RT_ASSERT(shell != RT_NULL);
    while (rt_device_read(shell->device, -1, &ch, 1) != 1)
        rt_sem_take(&shell->rx_sem, RT_WAITING_FOREVER);

    return (int)ch;
}

从上面的函数不难看出,如果 rt_device_read 不能从串口中读取到至少一个字节的数据,那么 finsh 线程将会获取信号量,如果获取不到信号量就会导致线程的挂起操作。

那既然知道了 finsh 线程会被挂起,那他又是怎么被唤醒的呢?

static rt_err_t finsh_rx_ind(rt_device_t dev, rt_size_t size)
{
    RT_ASSERT(shell != RT_NULL);

    /* release semaphore to let finsh thread rx data */
    rt_sem_release(&shell->rx_sem);

    return RT_EOK;
}

可以看到在 finsh 的接收中断里面实现信号量的释放。

总结:finsh 线程的唤醒是通过信号量的方式来实现线程的挂起与恢复。

如果帮到你了,请点个采纳!!!

这里有一个基于 MDK 可以运行的 LED 工程,改成了具有 RTT 的工程

在 HK32F030 上移植 RT-Thread Nano

先不评级你说的对与不对。先看看 drv_spi.c 当时的设计意图, 当时设计通用的驱动的时候, ST 推出了 HAL 库,在 F 系列上适配的确实非常好,但是随着型号越来越多,有些就不是那么通用了,典型的就是时钟源的问题。

下图是 STM32F4 系列的时钟图:

image.png

从上图可以看出来,外设时钟基本是由 APB1 和 APB2 提供, 这样在写驱动的时候,就比较方便的去动态的计算分频系数。

再看下 H7 的时钟图,太多了,只能截图部分:

image.png

从图中明确的可以看到 SPI4 的时钟源有 6 种提供方式。具体用户使用哪一种这是一个哲学问题了。

然后来总结一下前面的问题:

  • 当时 H7 的 SPI 驱动是我对接的,因为考虑到 H7 SPI 都是多路可选择的(SPI1 2 3 也是多路 上图能看到),我没有办法去确定用户用哪个时钟源,一千个用户就有一千个哈姆雷特。
  • 竟然这个驱动灵活性这么大,还要上传提交了,因为玩 H7 的用户都是高手,这么简单的调节问题应该难不到他们。

最后说结论:

你的理解是错的,请根据你的实际情况来设置不同的时钟源获取函数来进行分频计算。当你的程序中存在多个 SPI 的时候,可以采用一个取巧的方式就是把所有 SPI 的时钟源的频率设置成一样的,聪明如你,应该就知道该怎么办了。

码字不易,帮到你了,请点一下采纳。

问题1 :请你仔细看,是16M 还是 8M,你的图中很明显的写的是 8M
希望你注意看看,逐字母对比查看
image.png

问题2: FTP 是以库的方式提供的。因为不可描述的原因没有提供源码,实际上软件包已经开源,希望不要纠结这个问题。

问题3:系统重启后 bootloader 会从 download 分区读取出来,并写入指定的地址,具体实现请自行查看源码

问题4: H7的 RAM 的一些情况,看下图
image.png

对于一些外设总线就不再贴图了,聪明的你,应该能找到 ST 手册中的描述

问题5:H7 就是这么热,为什么热,你应该去问 ST

问题6: https://art-pi.gitee.io/website/

最后想说一句,一口气解答了你这么多问题,能够多赞赏一些积分给我,这也是我回答问题的动力。

rtt-studio修改lds链接文件

举个栗子,

#elif defined ( __GNUC__ )
uint16_t ADCxValues[3] __attribute__((section(".ADCArraySection")));
#endif

rtt-studio 用的是 GCC 编译器, 所以前面增加 GNUC

下面描述就是将 ADC 的数组指定到某个区域去,这个区域的指定,需要修改链接文件 lds。

/* Program Entry, set to mark it as "used" and avoid gc */
MEMORY
{
ROM (rx) : ORIGIN =0x08000000,LENGTH =2048k
RAM (rw) : ORIGIN =0x24000000,LENGTH =512k
ADCArraySection (rw) : ORIGIN =0x30020000,LENGTH =128k
}

这样还不够,在修改一下

    .ADCArraySection (NOLOAD) : ALIGN(4)
    {
    . = ALIGN(4);
    *(.ADCArraySection)
    *(.ADCArraySection.*)
    . = ALIGN(4);
    __ADCArraySection_free__ = .;
    } > ADCArraySection

这样就可以了,楼主赶紧去试试吧。

另外也可以参考一下 ART-Pi 以太网描述符的方法。

驱动

链接文件

问题的原因在与:

ulog_formater 里面是没有对 传递进来的数据进行补 \0
开启了 RT_USING_DEVICE 之后使用的是

rt_device_write(dev, 0, log, len); 

这个会发送指定的长度, 未开启的情况下使用的是 rt_hw_console_output(log); 这个里面使用了 strlen 来判断字符串的长度,
因为前面没有 \0,所以他每次都会查找到 log_buf_th[ULOG_LINE_BUF_SIZE + 1] 历史最长的字符串的 \0

解决办法:

需要在

RT_WEAK rt_size_t ulog_formater(char *log_buf, rt_uint32_t level, const char *tag, rt_bool_t newline,const char *format, va_list args)

这个函数 return 的上一句增加 log_buf[log_len] = '\0'; 即可。

如果我的回答解答了你的疑惑,请帮忙点个采纳,你的采纳是我继续回答的动力。

修改路径:art_pi_factory/packages/btstack-v0.0.1/rtt_adapter/rtt_btstack_gatt_blufi.c

const uint8_t adv_data[] = {
    // Flags general discoverable, BR/EDR not supported
    0x02, BLUETOOTH_DATA_TYPE_FLAGS, 0x05,
    // Name
    0x0b, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, 'A', 'R', 'T', '-', 'P', 'i', ' ', ' ', ' ', ' ',
    // Incomplete List of 16-bit Service Class UUIDs -- FF10 - only valid for testing!
};

如果我的回答解答了你的疑惑,请帮忙点个采纳,你的采纳是我继续回答的动力。

建议楼主参考 ART-Pi 的工程,ART-Pi 的示例工程都是放在 QSPI FLASH W25Q64 。

第一步,修改链接文件的地址,如下图所示:

image.png

第二步,重新 rebuild 工程,或者 clean 之后在编译一次,编译器检查文件没有修改过,所以不会重新链接。

第三步,检查 DEBUG 目录下的 map 文件或者 解析 elf 文件,就能看到程序的地址已经不是 0x0800 0000 的地址段了

第四步,准备一个 从 0x0800 0000 到 0x9000 0000 的 bootloader 工程,注意开启 QSPI FLASH 的内存映射模式,这个可以参考 ART-Pi 的实现

第五步,准备一个合适的下载算法,目前 RTT Studio 集成的 JLINK 和 STLINK 所需的下载算法不一样,如何制作下载算法可以百度一下,或者去 ART-Pi 的 QQ 技术交流群下载

第六步,根据你使用的仿真器不同在追问把,或者重新发贴,请教专家 @rcp

回到
顶部

发布
问题

投诉
建议