发新帖本帖赏金 6.66元(功能说明)我要提问
返回列表
打印
[STM32H7]

【银杏科技ARM+FPGA】分享iCore4T移植RT-Thread过程的点点滴滴

[复制链接]
12036|373
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 heart蓝色CD 于 2020-2-22 12:33 编辑

分享iCore4T移植RT-Thread过程的点点滴滴——DAY 1
高手请略过,如有错误请多多批评指点!

首先放上iCore4T靓照   
   

一、初识RT-Thread
       RT-Thread,全称是 Real Time-Thread,顾名思义,它是一个嵌入式实时多线程操作系统。以下我们就简称RTT,RTT是一款完全由我们国内团队开发的嵌入式实时操作系统,它诞生于2006年,最初源于对当时小型RTOS现状的诸多不满,RTT要打造一个精致而优雅的操作系统。从最初的V0.0.1发布,历经十几个年头的沉淀到今天的V4.0.0的发布,它正演变成一个功能强大、组件丰富的物联网操作系统。
       RTT支持任务抢占,STM32默认支持优先级范围是32,支持多任务(线程)轮转调度,可以通过信号量、互斥量、事件集进行线程间同步,通过邮箱、消息队列、信号进行线程间的通信。RTT也支持动态内存、中断等管理。

二、辅助工具
2.1、Env简介
     Env是RTT推出的开发辅助工具,针对基于RTT操作系统项目工程,提供编译构建环境、图形化系统配置及软件包管理功能,其内置的menuconfig提供了简单易用的配置剪裁工具,可对内核、组件和软件包进行自由剪裁,使用系统以搭积木的方式进行构建。
2.1.1 准备工作
        在电脑上首先安装好git,软件包管理功能需要git的支持。
        git下载地址:https://git-scm.com/downloads。
        下载后一路next安装,安装完成测试是否安装成功。打开cmd,输入git,如果可以显示版本信息说明安装成功。
        如果安装成功说明git已添加到系统环境变量。
        
        下载Env工具
        Env工具下载地址:https://www.rt-thread.org/page/download.html
        下载后解压,打开Env控制台
        双击Env目录下可执行文件env.exe
        在文件夹中通过右键菜单打开 Env 控制台,添加 Env 至右键菜单。

        
        
2.1.2 如何使用
        现在打开我已经制作好的bsp工程,我们通过Env工具对RTT系统进行菜单配置(制作方法我会在以后详细介绍)
        打开工程文件rt-thread/bsp/stm32/stm32h750-gingko-icore4t,右击鼠标点击ConEmu Here
        输入menuconfig,回车
        
        
        至此我们就可以正确的借助Env来方便快速的对内核进行配置,进入RTT的世界。

2.2 Scons构建工具
        SCons 是一套由 Python 语言编写的开源构建系统,类似于 GNU Make。它采用不同于通常 Makefile 文件的方式,而是使用 SConstruct 和 SConscript 文件来替代。这些文件也是 Python 脚本,能够使用标准的 Python 语法来编写。所以在 SConstruct、SConscript文件中可以调用 Python 标准库进行各类复杂的处理,而不局限于 Makefile 设定的规则。
        上面我们介绍了可以通过Env来完成对内核、组件、BSP的配置,我们还可以通过Scons工具来完成对KEIL、IAR等工程的搭建。通过一条命令"scons --target=mdk5",即可完成KEIL新工程的生成。
        
三、烧录进我们的iCore4T双核心板
        打开我们制作的最简单的BSP工程(在这里我们以MDK5为例),编译、下载。
        iCore4T双核心板自带DEBUG_UART,打开终端Putty,程序运行后我们会发现RT-Thread信息打印在了终端。
        
        我们在终端输入list_device,可以看一下当前已经挂载上的设备。
        

        我将在DAY2里面给大家简单介绍如何制作最简单的BSP工程,也就是RT-Thread的移植过程。








使用特权

评论回复

打赏榜单

王紫豪 打赏了 6.66 元 2020-02-29
理由:非常好呀

评论
pushment 2020-11-26 08:33 回复TA
不错的例子 
heart蓝色CD 2020-3-4 16:56 回复TA
汇总:https://bbs.21ic.com/icview-2922670-1-3.html 
heart蓝色CD 2020-2-24 19:25 回复TA
@21ic小喇叭 :好滴,收到了哦 
21ic小喇叭 2020-2-21 09:55 回复TA
建议您把这个帖子的链接,发到论坛【征集评测贴】的活动里,可以得到奖品哦 
沙发
Cresta| | 2020-2-20 16:49 | 只看该作者
fpga也可以吗

使用特权

评论回复
板凳
Fillmore| | 2020-2-20 17:20 | 只看该作者
楼主,你这篇帖子不错,我可以转载吗?

使用特权

评论回复
地板
aozima| | 2020-2-20 18:23 | 只看该作者
这板子不错!

使用特权

评论回复
5
heart蓝色CD|  楼主 | 2020-2-20 19:13 | 只看该作者
Fillmore 发表于 2020-2-20 17:20
楼主,你这篇帖子不错,我可以转载吗?

感谢支持

使用特权

评论回复
6
heart蓝色CD|  楼主 | 2020-2-20 19:14 | 只看该作者

系统在ARM上跑,FPGA可以做为ARM的一个设备来操作。

使用特权

评论回复
7
pkoko| | 2020-2-20 20:11 | 只看该作者
icore + rt-thread 如虎添翼。

使用特权

评论回复
8
heart蓝色CD|  楼主 | 2020-2-21 13:53 | 只看该作者
分享iCore4T移植RT-Thread过程的点点滴滴——DAY 2

高手请略过,如有错误请多多批评指点!

下面直接划重点
        
一、源代码下载
    下载最新版的RT-Thread源代码:https://www.rt-thread.org/page/download.html
        
二、工程文件简介
        2.1、我们将下载好的源码进行解压,可以看到共有以下文件夹,在这里我们只关注bsp文件夹下的内容。其他文件夹的内容暂时先不理会,有兴趣的伙伴可以先了解一下。
        

        2.2、打开bsp文件夹,我们发现RT-Thread支持n多种厂商的MCU,iCore4T ARM+FPGA双核心板ARM采用的是ST的STM32H750IBK6,因此在这里我们打开stm32的文件夹。
        

        2.3、打开stm32文件夹,可以看到这些文件夹可以大致分为3类,分别为docs文件夹,docs文件夹为官方提供的一些图文教程(相当详细);libraries文件夹,libraries文件夹为STM32的HAL库文件及RTT编写的STM32一些常外设的驱动文件;剩下的为各开发板的最简单的bsp工程。
        

三、BSP工程制作        
    我们今天的任务就是为iCore4T制作最简单的BSP工程,在这里我将文件夹命名为stm32h750-gingko-icore4t。        具体的制作过程我就不在重复介绍,上面介绍的docs文件夹中有非常详细的操作说明。
        
        在这里我仅特别强调几个地方

        1、使用STM32CubeMx(我用的是最新版本5.5.0)配置串口时候,我们配置UART2(iCore4T使用UART2做为DBG)。配置的时候只需要将UART2的两个引脚选择正确就可以了,其他参数我们不用理会,RTT驱动里面已经将其封装好。另:配置完引脚我习惯性将速度等级调至最大,以免会造成不必要的麻烦。
        
        

        2、在../stm32/stm32h750-gingko-icore4t/board/Kconfig里面加入UART2的菜单配置。
        
        
        3、Kconfig修改完成后按照我们在DAY1中的介绍,打开menuconfig,开启UART2,并将UART2做为DBG输出。
        
        
        4、最后通过scons命令生成MDK工程,打开工程,修改main函数中的LED引脚,然后编译、下载,到此我们的BSP工程就制作完毕。我们再次看一下运行结果。
        
        
        
四、源代码
    源代码可以移步这里下载:https://pan.baidu.com/s/1E627EdePeECauvWmAadxHA 提取码:i4wl
        
我将在DAY3里面给大家简单介绍RT-Thread的启动过程        


使用特权

评论回复
9
wangjiahao88| | 2020-2-21 20:06 | 只看该作者
收到 学习学习!看图片以为是linux下面的  没想到是win

使用特权

评论回复
10
heart蓝色CD|  楼主 | 2020-2-22 12:25 | 只看该作者
分享iCore4T移植RT-Thread过程的点点滴滴——DAY 3

高手请略过,如有错误请多多批评指点!       


通过在DAY2移植好的程序进行下载发现,RTT的启动速度还是神速的,那么具体的过程是怎么样的呢?

1、SystemInit()
        和裸机启动一样,第一步仍是先进行系统初始化,调用SystemInit()函数来完成FPU的设置以及向量表位置的配置。
        
        
       
2、$Sub$$main()
        完成系统初始化后,就进入真的main函数开始系统启动,该函数在内核components.c文件中。那么$Sub$$main()函数到底是什么意思呢,我们在.s文件中可以看到,系统完成systeminit之后,就开始执行main函数,其实$Sub$$main()就是在主程序main前插入一段新代码,这段代码可以用来初始化系统,当然也可以做其他事情。在这里我们可以看到,调用了rtthread_startup()函数开始RTT系统启动。
        
       
3、rtthread_startup()
        进入这个函数后就开始进行了真正的系统启动,我们可以看到rtthread_startup()共调用了这么多函数。
        
       
        下面我给大家简单介绍一下这些函数具体做了哪些工作来完成整个系统启动的。
       
        3.1 rt_hw_interrupt_disable()
        该函数的功能就是关闭所有的中断。
        
       
        3.2 rt_hw_board_init()
        该函数的功能是进行板级初始化。使能ICache DCache,进行HAL初始化完成中断优化级配置、SYSTICK滴答定时器的配置,RTT操作系统堆初始化,GPIO时钟使能,UART设备初始化,选择作为终端输出的串口设备,最后进行板底层初始化。
        
        
       
        3.3 rt_show_version()
        该函数的功能是通过串口向终端输出RT-Thread操作系统的版本信息,就是我们在DAY1和DAY2中看到的信息。
        
       
        3.4 rt_system_timer_init()
        该函数的功能是完成系统定时器的初始化。
        
       
        3.5 rt_system_scheduler_init()
        该函数将初始化系统调度程序。
       
        3.6 rt_application_init()
        该函数的功能是创建main线程,并启动该线程,该线程默认优先级为10。
       

        3.7 rt_system_timer_thread_init()
        该函数的功能是创建定时器线程,并启动该线程,该线程的优先级最高,为0。
       
        3.8 rt_thread_idle_init()
        该函数的功能是创建空闲线程,并启动该线程,该线程的优化级最低。
       
        3.9 rt_system_scheduler_start()
        该函数的功能是开启系统调度。
       
        至此系统启动完毕。
       
        源代码可以移步这里下载:
        链接:https://pan.baidu.com/s/1E627EdePeECauvWmAadxHA 提取码:i4wl

        我将在DAY4里面给大家简单介绍RT-Thread添加设备驱动的方法       



使用特权

评论回复
11
cooldog123pp| | 2020-2-23 16:06 | 只看该作者
问下楼主这种解决方案有什么意义嘛,ARM+FPGA 一片zynq就解决,分离的是有成本优势么

使用特权

评论回复
12
heart蓝色CD|  楼主 | 2020-2-23 16:17 | 只看该作者
cooldog123pp 发表于 2020-2-23 16:06
问下楼主这种解决方案有什么意义嘛,ARM+FPGA 一片zynq就解决,分离的是有成本优势么 ...

成本低,上手快

使用特权

评论回复
13
王紫豪| | 2020-2-23 23:37 | 只看该作者
本帖最后由 王紫豪 于 2020-2-23 23:54 编辑
cooldog123pp 发表于 2020-2-23 16:06
问下楼主这种解决方案有什么意义嘛,ARM+FPGA 一片zynq就解决,分离的是有成本优势么 ...

我的理解至少有几种优势:
1、成本优势:这个方案成本比ZYNQ低很多。

2、方案通用性:现在微控制器和FPGA都属于百花齐放的阶段,CPU和FPGA都可以根据自己的需求更换合适的,若成本敏感就换1块钱的M0和几块钱的CPLD,若需要更好的性能就用Cortex-A系列应用处理器加高容量FPGA。伸缩自如。

3、快速开发且更灵活:ZYNQ是 微处理器非控制器,裸奔过于复杂,需要上Linux,两个竞争不再一个段位内。

4、开发工具链优势:STM32在国内有众多的用户支持,且KEILMDK (或IAR )用户广泛,编译器优化的又快又好,而且出现了诸如CubeMX 这么优秀的工具,可以快速上手。

当然说这么多并不是ZYNQ不好,我的理解是任何东西合适就好,也许以后我们也会做ZYNQ的方案,各有千秋。

另外目前国内出现了诸多cortexM的国产芯片和一些国产的FPGA芯片,我认为这些东西目前属于百花齐放的阶段,某一个方案并不能够一统江湖。

以上为鄙人愚见,请多多指教。


使用特权

评论回复
14
heart蓝色CD|  楼主 | 2020-2-25 17:16 | 只看该作者
本帖最后由 heart蓝色CD 于 2020-2-25 17:27 编辑

分享iCore4T移植RT-Thread过程的点点滴滴——DAY 4

高手请略过,如有错误请多多批评指点!

通过前几天的介绍我们制作出了最基础的BSP工程,那么我们想利用更多的外设资源,实现更丰富的功能怎么办呢?今天我给大家分享一下STM32H750 ADC设备驱动的添加方法及使用。

一、配置ADC相应的GPIO,选择ADC时钟源
        1.1 iCore4T ARM+FPGA双核心板共有4路16bit ADC,其中两路用于板载电源监控,两路可供用户使用。分别是为PA0(ADC1_INP6),PA6(ADC12_INP3),PC2(ADC3_INP0),PC3(ADC3_INP1)。然后我们打开../bsp/stm32/stm32h750-gingko-icore4t/board/CubeMX_Config来进行ADC IO配置,注意这里仍然是只配置IO,其他参数不用理会,然后选择ADC的时钟源。配置完成后点击CREATE CODE。
        
        

        1.2 CubeMx生成工程后,我们只保留红色方框内的文件,其他的两个文件夹可以删除掉。
        
        
        1.3 复制刚刚生成的src文件夹maic.c文件中的函数SystemClock_Config(void)到board.c。这里内核初始化时要调用该函数进行时钟配置。
        
二、修改kconfig文件,增加menuconfig菜单配置中ADC选项。
         

三、打开menuconfg,使能ADC1(ADC1_INP16对核心板输入电源进行监控,所以我们以此为例)。
        

四、使用scons命令生成MDK5工程,打开并进行编译。
        我们编译发现会有错误产生,原因为RTT当前版本的ADC驱动对H7系列还不算完善,所以这里我们进行稍稍的修改。
        

        4.1 修改adc_config.h文件中的内容
        
        
        
        4.2 修改adc_config.c文件中 stm32_adc_enable()函数的内容,红色方框为增加的内容。
        
        
        4.3 修改adc_config.c文件中 stm32_adc_get_channel函数的内容。
        
        
        4.4 修改adc_config.c文件中 stm32_get_adc_value()函数的内容。
        
        
        4.5 修改完以上内容,重新编译。
        
        
五、烧录进iCore4T核心板
        烧录进去后我们可以发现能够找到ADC1设备,并读出通道16的值为0x4F1F,我们将其转变成模拟量:(20255/65536)*2.5*6 = 4.63(V)
        
        
六、源代码
        源代码可以移步这里下载:链接:https://pan.baidu.com/s/1ftP8TccWYqYt9GX9Lj6PGQ 提取码:pfqr

        至此,我们的ADC设备驱动已经添加完毕,并且可以正确的读出数据。
        
        我将在DAY5里面为大家分享QSPI驱动的添加过程。

使用特权

评论回复
15
冬瓜盅| | 2020-2-26 20:48 | 只看该作者
iCore4T移植RT-Thread

使用特权

评论回复
16
heart蓝色CD|  楼主 | 2020-2-27 12:30 | 只看该作者
本帖最后由 heart蓝色CD 于 2020-2-29 15:35 编辑

分享iCore4T移植RT-Thread过程的点点滴滴——DAY 5

高手请略过,如有错误请多多批评指点!

iCore4T核心板通过QSPI总线挂有一片 8MB FLASH W25Q64可用于运行程序、存放字库、存放图片、做为文件系统的从设备等,那么我们怎么把它用起来呢,今天给大家分享一下QSPI总线驱动的加载过程及W25Q64的挂载过程。

一、配置QSPI相应的GPIO,选择QSPI的时钟源
        1.1 我们仍然是借助STM32CubeMx工具来完成外设IO的配置,打开../bsp/stm32/stm32h750-gingko-icore4t/board/CubeMX_Config来配置QSPI的IO,从原理图中可以看到我们用的是QSPI的BANK1,它的IO分别是PB2(CLK)、PB6(NCS)、PD11(IO0)、PD12(IO1)、PD13(IO3)、PF7(IO2)。打开QSPI后,默认给出的IO和我们原理图中的并不相符,这里我们手动修改一下,仍然是只配置IO,选择QSPI的时钟源。配置完成点击CREATE CODE。
        
        
        
        1.2 生成工程后,我们只保留红色方框内的文件,其他的两个文夹可以删除掉。
        
        
        1.3 复制刚刚生成的src文件夹maic.c文件中的函数SystemClock_Config(void)到board.c。这里内核初始化时要调用该函数进行时钟配置,我们新加入了QSPI的时钟源。
        
二、修改kconfig文件,增加menuconfig菜单配置中QSPI选项。
        


三、打开menuconfig,使能QSPI。
      

四、使用scons命令生成MDK5工程,编译、烧录。
        启动之后,我们查看设备,可以发现qspi已经做为了个SPI设备添加成功了。
        
        
五、挂载W25Q64
        5.1 修改kconfig文件,在menuconfig中添加配置W25Q64的选项。
        
        
        5.2 添加w25q64的驱动程序drv_qspi_flash.c文件,并将该文件放在../bsp/stm32/libraries/HAL_Drivers,我把源码贴在下面
        
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date           Author       Notes
* 2018-11-27     zylx         first version
*/

#include <board.h>
#include <drv_qspi.h>
#include <rtdevice.h>
#include <rthw.h>
#include <finsh.h>

#ifdef BSP_USING_QSPI_FLASH

#include "spi_flash.h"
#include "spi_flash_sfud.h"

char w25qxx_read_status_register2(struct rt_qspi_device *device)
{
    /* 0x35 read status register2 */
    char instruction = 0x35, status;

    rt_qspi_send_then_recv(device, &instruction, 1, &status, 1);

    return status;
}

void w25qxx_write_enable(struct rt_qspi_device *device)
{
    /* 0x06 write enable */
    char instruction = 0x06;

    rt_qspi_send(device, &instruction, 1);
}

void w25qxx_enter_qspi_mode(struct rt_qspi_device *device)
{
    char status = 0;
    /* 0x38 enter qspi mode */
    char instruction = 0x38;
    char write_status2_buf[2] = {0};

    /* 0x31 write status register2 */
    write_status2_buf[0] = 0x31;

    status = w25qxx_read_status_register2(device);
    if (!(status & 0x02))
    {
        status |= 1 << 1;
        w25qxx_write_enable(device);
        write_status2_buf[1] = status;
        rt_qspi_send(device, &write_status2_buf, 2);
        rt_qspi_send(device, &instruction, 1);
        rt_kprintf("flash already enter qspi mode\n");
        rt_thread_mdelay(10);
    }
}

static int rt_hw_qspi_flash_with_sfud_init(void)
{
    stm32_qspi_bus_attach_device("qspi1", "qspi10", RT_NULL, 4, w25qxx_enter_qspi_mode, RT_NULL);
   
    /* init w25q64 */
    if (RT_NULL == rt_sfud_flash_probe("W25Q64", "qspi10"))
    {
        return -RT_ERROR;
    }

    return RT_EOK;
}
INIT_COMPONENT_EXPORT(rt_hw_qspi_flash_with_sfud_init);

#if defined(RT_USING_DFS_ELMFAT) && !defined(BSP_USING_SDCARD)
#include <dfs_fs.h>

#define BLK_DEV_NAME  "W25Q64"

int mnt_init(void)
{
    rt_thread_delay(RT_TICK_PER_SECOND);

    if (dfs_mount(BLK_DEV_NAME, "/", "elm", 0, 0) == 0)
    {
        rt_kprintf("file system initialization done!\n");
    }
    else
    {
        if(dfs_mkfs("elm", BLK_DEV_NAME) == 0)
        {
            if (dfs_mount(BLK_DEV_NAME, "/", "elm", 0, 0) == 0)
            {
                rt_kprintf("file system initialization done!\n");
            }
            else
            {
                rt_kprintf("file system initialization failed!\n");
            }
        }
    }

    return 0;
}
INIT_ENV_EXPORT(mnt_init);

#endif /* defined(RT_USING_DFS_ELMFAT) && !defined(BSP_USING_SDCARD) */
#endif /* BSP_USING_QSPI_FLASH */


        5.3 添加文件路径,这样生成工程的时候可以自动将该文件加入MDK工程。
        
        
        5.4 打开menuconfig,使能QSPI。
        

        5.5 再次使用scons命令生成MDK5工程,编译、烧录,我们发现W25Q64已经做为块设备成功挂载上了。
        
        
六、源代码
        源代码请移步这里下载:链接:https://pan.baidu.com/s/1ftP8TccWYqYt9GX9Lj6PGQ 提取码:pfqr        

        至此,我们成功的添加了QSPI总线驱动,挂载W25Q64。
        
        我将在DAY6里面为大家分享I2C总线驱动的添加,挂载电源管理芯片,通过menuconfig来对各路电源进行管理。

使用特权

评论回复
17
heart蓝色CD|  楼主 | 2020-2-29 15:53 | 只看该作者
本帖最后由 heart蓝色CD 于 2020-2-29 16:00 编辑

分享iCore4T移植RT-Thread过程的点点滴滴——DAY 6

高手请略过,如有错误请多多批评指点!

iCore4T ARM+FPGA双核心板I2C总线挂有三个设备,分别为AXP152电源管理芯片,LM75A温度传感器,EEPROM存储器,今天给大家分享I2C总线驱动的添加过程及AXP152的挂载过程。

一、修改Kconfig文件
        这里我们采用的是RT-Thread的模拟I2C,使用普通IO就可以了,不再需要通过CubeMx配置I2C引脚。在kconfig文件中增加menuconfig菜单配置中I2C的选项及I2C IO的 选项。这里需要特别说明的是23,24怎么来的。我在DAY2里制作的最简BSP中已经添加了PIN设备,所以这里就可以直接使用GPIO了,从原理图可以看到I2C的两个引脚SDA、SCL分别为PB7、PB8,RT-Thread中对GPIO驱动进行了再封装,对编号也进行了重编。我们知道一组IO是16个,所以RTT把PA0作为引脚0,以此累加进行编号。因此23即PB7,24即PB8。
        
       

二、使用scons命令生成MDK5工程,编译,烧录。
        启动之后,我们查看设备,可以发现i2c1已经做为一个BUS设备添加成功了。
        
       
三、挂载AXP152
        axp152是一款I2C总线接口的电源管理芯片,可输出8路电源,分别为4路DCDC,4路LDO,添加AXP152驱动,然后在menuconfig中添加配置AXP152的选项及各路输出电源的参数,这样就可以直接通过menuconfig方便地管理各路电源的输出电压了。
        3.1 修改kconfig文件,在menuconfig中添加配置AXP152的选项及各路输出电源的参数。
        

        3.2 添加axp152的驱动程序,并将该文件放在../bsp/stm32/libraries/HAL_Drivers,我把源码帖在下面。
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date           Author       Notes
* 2020-02-17     zh.          first version
*/

#include <board.h>
#include <drv_qspi.h>
#include <rtdevice.h>
#include <rthw.h>
#include <finsh.h>

#ifdef BSP_USING_I2C_AXP152

#define        AXP152_CHIP_VERSION                     0x03
#define        AXP152_DCDC1_VOLTAGE                    0x26
#define        AXP152_DCDC2_VOLTAGE                    0x23
#define        AXP152_DCDC3_VOLTAGE                    0x27
#define        AXP152_DCDC4_VOLTAGE                    0x2B
#define        AXP152_DLDO1_VOLTAGE                    0x29
#define        AXP152_DLDO2_VOLTAGE                    0x2A
#define        AXP152_ALDO1_ALD02_VOLTAGE              0x28
#define        AXP152_SHUTDOWN                         0x32

#define AXP152_POWEROFF                         (1 << 7)

/* For axp_gpio.c */
#define AXP152_ADDR                             (0x60 >> 1)
#define AXP_GPIO0_CTRL                          0x90
#define AXP_GPIO1_CTRL                          0x91
#define AXP_GPIO2_CTRL                          0x92
#define AXP_GPIO3_CTRL                          0x93
#define AXP_GPIO_CTRL_OUTPUT_LOW                0x00 /* Drive pin low */
#define AXP_GPIO_CTRL_OUTPUT_HIGH               0x01 /* Drive pin high */
#define AXP_GPIO_CTRL_INPUT                     0x02 /* Input */
#define AXP_GPIO_STATE                          0x97
#define AXP_GPIO_STATE_OFFSET                   0x00

/* For axp152 i2c bus*/
#define AXP152_I2CBUS_NAME     "i2c1"

static struct rt_i2c_bus_device *axp152_i2c_bus = RT_NULL;

static rt_err_t i2c_write_nbyte(rt_uint8_t slave_addr, rt_uint8_t cmd, rt_uint8_t *value, rt_uint32_t len)
{
    rt_uint32_t i;
    rt_uint8_t *buffer;
    rt_size_t result;
       
    buffer = rt_malloc(len + 1);
    buffer[0] = cmd;
        for(i  = 0;i < len;i ++)
        {
                buffer[i+1] = value[i];
        }       
    result = rt_i2c_master_send(axp152_i2c_bus, slave_addr, RT_I2C_WR, buffer, len+1);
        rt_free(buffer);
       
    if (result == (len+1))
    {
        return RT_EOK;      
    }
    else
    {
        return -RT_ERROR;      
    }
}

static rt_err_t i2c_read_nbyte(rt_uint8_t slave_addr, rt_uint8_t cmd, rt_uint8_t *buf, rt_uint32_t len)
{
    rt_i2c_master_send(axp152_i2c_bus, slave_addr, RT_I2C_WR, &cmd, 1);
   
    rt_i2c_master_recv(axp152_i2c_bus, slave_addr, RT_I2C_RD, buf, len);
   
    return RT_EOK;
}

static rt_uint8_t axp152_mvolt_to_target(rt_uint32_t mvolt, rt_uint32_t min, rt_uint32_t max, rt_uint32_t div)
{
    if(mvolt < min)                mvolt = min;
    else if (mvolt > max)                mvolt = max;

    return (mvolt - min) / div;
}

rt_err_t axp152_set_dcdc1(rt_uint32_t mvolt)
{
    rt_uint8_t target = axp152_mvolt_to_target(mvolt, 1700, 3500, 100);
       
    if(mvolt >= 2400 || mvolt <= 2800)target = target - 2;
    if(mvolt >= 3000 || mvolt <= 3500)target = target - 3;

    return i2c_write_nbyte(AXP152_ADDR,AXP152_DCDC1_VOLTAGE,&target,1);
}

rt_err_t axp152_set_dcdc2(rt_uint32_t mvolt)
{
    rt_uint8_t target = axp152_mvolt_to_target(mvolt, 700, 2275, 25);

    return i2c_write_nbyte(AXP152_ADDR,AXP152_DCDC2_VOLTAGE,&target,1);
}

rt_err_t axp152_set_dcdc3(rt_uint32_t mvolt)
{
     rt_uint8_t target = axp152_mvolt_to_target(mvolt, 700, 3500, 50);

     return i2c_write_nbyte(AXP152_ADDR,AXP152_DCDC3_VOLTAGE,&target,1);
}

rt_err_t axp152_set_dcdc4(rt_uint32_t mvolt)
{
    rt_uint8_t target = axp152_mvolt_to_target(mvolt, 700, 3500, 25);

    return i2c_write_nbyte(AXP152_ADDR,AXP152_DCDC4_VOLTAGE,&target,1);
}

rt_err_t axp152_set_dldo1(rt_uint32_t mvolt)
{
    rt_uint8_t target = axp152_mvolt_to_target(mvolt, 700, 3500, 100);

    return i2c_write_nbyte(AXP152_ADDR,AXP152_DLDO1_VOLTAGE,&target,1);       
}

rt_err_t axp152_set_dldo2(rt_uint32_t mvolt)
{
    rt_uint8_t target = axp152_mvolt_to_target(mvolt, 700, 3500, 100);

    return i2c_write_nbyte(AXP152_ADDR,AXP152_DLDO2_VOLTAGE,&target,1);
}

rt_err_t axp152_set_aldo1(rt_uint32_t mvolt)
{
    rt_uint8_t data;
    rt_uint8_t target;

    if(mvolt >= 1200 && mvolt <= 2000)
    {
        target = axp152_mvolt_to_target(mvolt, 1200, 2000, 100);
    }
    else if(mvolt == 2500)
    {
        target = 0x09;
    }
    else if(mvolt == 2700)
    {
        target = 0x0A;
    }
    else if(mvolt == 2800)
    {
        target = 0x0B;
    }
    else if(mvolt >= 3000 || mvolt <= 3300)
    {
        target = axp152_mvolt_to_target(mvolt, 3000, 3300, 100);
        target += 0x0C;
    }

    i2c_read_nbyte(AXP152_ADDR,AXP152_ALDO1_ALD02_VOLTAGE,&data,1);

    data &= 0x0F;
    target = target << 4;
    target &= 0xF0;
    target = data | target;

    return i2c_write_nbyte(AXP152_ADDR,AXP152_ALDO1_ALD02_VOLTAGE,&target,1);
}

rt_err_t axp152_set_aldo2(rt_uint32_t mvolt)
{
    rt_uint8_t data;
    rt_uint8_t target;

    if(mvolt >= 1200 && mvolt <= 2000)
    {
        target = axp152_mvolt_to_target(mvolt, 1200, 2000, 100);
    }
    else if(mvolt == 2500)
    {
        target = 0x09;
    }
    else if(mvolt == 2700)
    {
        target = 0x0A;
    }
    else if(mvolt == 2800)
    {
        target = 0x0B;
    }
    else if(mvolt >= 3000 || mvolt <= 3300)
    {
        target = axp152_mvolt_to_target(mvolt, 3000, 3300, 100);
        target += 0x0C;
    }

    i2c_read_nbyte(AXP152_ADDR,AXP152_ALDO1_ALD02_VOLTAGE,&data,1);
    data &= 0xF0;
    target = target & 0x0F;
    target = data | target;
    return i2c_write_nbyte(AXP152_ADDR,AXP152_ALDO1_ALD02_VOLTAGE,&target,1);
}

int axp152_init(void)
{
    rt_uint8_t version;

    axp152_i2c_bus = rt_i2c_bus_device_find(AXP152_I2CBUS_NAME);

    if(axp152_i2c_bus == RT_NULL)
    {
        rt_kprintf("i2c_bus %s for axp152 not found!\n", axp152_i2c_bus);
        return -RT_ERROR;                       
    }
    /* detect axp152 */
    i2c_read_nbyte(AXP152_ADDR, AXP152_CHIP_VERSION, &version, 1);
    if(version != 0x05)
    {
        rt_kprintf("[AXP152] probe fail!\n");
                return -RT_ERROR;
    }
    else
    {
        rt_kprintf("[AXP152] probe ok! Version is 0x%02X\n",version);
    }

    /* config axp152 */
    axp152_set_dcdc1(AXP_DCDC1_VOLT);
    axp152_set_dcdc2(AXP_DCDC2_VOLT);
    axp152_set_dcdc3(AXP_DCDC3_VOLT);
    axp152_set_dcdc4(AXP_DCDC4_VOLT);
    axp152_set_dldo1(AXP_DLDO1_VOLT);
    axp152_set_dldo2(AXP_DLDO2_VOLT);
    axp152_set_aldo1(AXP_ALDO1_VOLT);
    axp152_set_aldo2(AXP_ALDO2_VOLT);
               
    return RT_EOK;
}
INIT_DEVICE_EXPORT(axp152_init);

#endif /* BSP_USING_I2C_AXP152 */



        3.3 添加文件路径,这样生成工程的时候可以自动将该文件加入MDK工程。
        

        3.4 打开menuconfig,配置AXP152,这里直接用默认的配置参数即可,当然如果有其他的需求也可以进行修改。
        

        3.5 再次使用scons命令生成MDK5工程,编译、烧录,我们可以看到已经探测到了AXP152,并对其各路电压进行了配置
        

四、源代码
        源代码可以移步这里下载:链接:https://pan.baidu.com/s/1ftP8TccWYqYt9GX9Lj6PGQ 提取码:pfqr  
       
        至此,我们成功的添加了I2C总线驱动,添加了AXP152设备。
       
        我将在DAY7里面为大家分享温度传感器LM75A的挂载过程。

使用特权

评论回复
18
heart蓝色CD|  楼主 | 2020-3-4 11:09 | 只看该作者
本帖最后由 heart蓝色CD 于 2020-4-20 10:28 编辑

分享iCore4T移植RT-Thread过程的点点滴滴——DAY 7

高手请略过,如有错误请多多批评指点!
        
iCore4T ARM+FPGA双核心板I2C总线挂有三个设备,分别为AXP152电源管理芯片,LM75A温度传感器,EEPROM存储器,在DAY 6里我已经给大家分享了I2C总线驱动的添加过程,今天直接给大家分享LM75A的挂载过程。

LM75A 是一个使用了内置带隙温度传感器和Σ-△模数转换技术的温度-数字转换器,可用于iCore4T核心板温度监控,如果温度过高可以输出报警信息。

1、修改kconfig文件,在menuconfig中添加配置LM75A的选项


2、添加lm75a驱动程序,并将该文件放在../bsp/stm32/libraries/HAL_Drivers,我把源码贴在下面
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date           Author       Notes
* 2020-02-17     zh.          first version
*/

#include <board.h>
#include <drv_qspi.h>
#include <rtdevice.h>
#include <rthw.h>
#include <finsh.h>

#ifdef BSP_USING_I2C_LM75A

#define LM75A_ADDR                                                            (0x90 >> 1)

/* For lm75a i2c bus*/
#define LM75A_I2CBUS_NAME     "i2c1"

static struct rt_i2c_bus_device *lm75a_i2c_bus = RT_NULL;

static rt_err_t i2c_read_nbyte(rt_uint8_t slave_addr, rt_uint8_t cmd, rt_uint8_t *buf, rt_uint32_t len)
{
    rt_i2c_master_send(lm75a_i2c_bus, slave_addr, RT_I2C_WR, &cmd, 1);
   
    rt_i2c_master_recv(lm75a_i2c_bus, slave_addr, RT_I2C_RD, buf, len);
   
    return RT_EOK;
}

float lm75a_read(void)
{
        union
        {
                unsigned char buf[2];
                short int value;
        }temp;
        float f;
        unsigned char c;
        
    lm75a_i2c_bus = rt_i2c_bus_device_find(LM75A_I2CBUS_NAME);

    if(lm75a_i2c_bus == RT_NULL)
    {
        rt_kprintf("i2c_bus %s for lm75a not found!\n", lm75a_i2c_bus);
        return -RT_ERROR;                        
    }
        
        i2c_read_nbyte(LM75A_ADDR,0,temp.buf,2);

        c = temp.buf[0];
        temp.buf[0] = temp.buf[1];
        temp.buf[1] = c;

        f = temp.value;
        f /= (float)32.0;
        f *= (float)0.125;
        
        return f;
}
static int lm75a(int argc, char **argv)
{
        float tempture;
        int temp;
        
        tempture = lm75a_read();
        
        temp = tempture * 100;
        rt_kprintf("The current temperature is: %d.%02d°\n",temp/100,temp%100);
        
    return RT_EOK;
}
MSH_CMD_EXPORT(lm75a, show current temperature);
#endif /* BSP_USING_I2C_LM75A */


3、添加文件路径,这样生成工程的时候可以自动将该文件加入MDK工程


4、打开menuconfig,配置LM75A


5、使用scons命令生成MDK5工程,编译,烧录,就可以获取温度信息了


6、源代码
        源代码可以移步这里下载:链接:https://pan.baidu.com/s/1ftP8TccWYqYt9GX9Lj6PGQ 提取码:pfqr

        至此,我们成功的挂载了LM75A设备。

        我将在DAY8里面为大家分享EEPROM的挂载过程。  

使用特权

评论回复
19
韩小野| | 2020-3-6 17:53 | 只看该作者
支持支持!

使用特权

评论回复
20
K4rthur| | 2020-3-13 19:22 | 只看该作者
感谢分享!学习学习!

使用特权

评论回复
发新帖 本帖赏金 6.66元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

92

主题

223

帖子

25

粉丝