rtthread开发笔记心得

一env使用

1.1:使用env构建rtthread项目:安装env_released_1.1.1,打开env命令终端可以对rtthread的项目进行配置,在env中使用menuconfig命令进行图形界面的选择配置,menuconfig除了系统自带的根目录,外设的设备添加选项由项目的kconfig配置得到,将kconfig添加想添加的外设,使用menuconfig配置后,保存,会把相应的配置更新到.config文件中,然后使用命令scons --target=mdk5(scons --target=xxx)更新到项目工程中。

1.2:打开项目工程,在rtconfig.h中可以得到配置好的头文件包含了,相应的rtthread中的外设支持头文件,源文件可以在rtdevice.h中查看,相应的源文件,头文件加入工程需要在rtconfi.h配置相应的头文件。Menuconfig结合kconfig可以完成这一步。

1.3:当系统是不能支持env的,也就是项目工程不需要SConscript脚本配置的情况下使用手动添加即可。(另项目工程的各目录下的配置脚本是各目录下的SConscript脚本,开发时候可以在相应的脚本中添加用户需要的配置)其中env工具要求项目工程必须有bsp目录(即板级支持包,里面是不同芯片板卡系列的实现工程)。其执行添加在项目工程所在目录下,查找bsp。

2:工程更改基本配置:

2.1:kconfig,即rtconfig 的头文件配置就可以直接加载3步骤的东西

2.2:其中基本要配置的script有 :E:\rtt\rt-thread-master - 1\bsp\gd32303e-eval\drivers这个目录下的script是向工程自动添加上相应为外设源文件(用户添加的)

E:\rtt\rt-thread-master - 1\bsp\gd32303e-eval\Libraries 下的SConscript是配置工程的开发环境的脚本,比如更改hd.s等

2.3:然后rtthread提供的外设结构体在E:\rtt\rt-thread-master - 1\components\drivers下

 

 

二相应的添加外设操作(env):

 

三用户完成外设驱动层(最主要)

1:Rtthread是一个分层架构的系统,用户需要对接rtthread外设并将其提供的ops结构体进行实现,之后就可以开始使用和驱动外设了,

实现这个ops的源代码可以参考各芯片系列的。其中主要的原因就是各外设需要挂载到总线上,调用注册函数就进行挂载,外部即可使用。

2:其中ops基本的结构会包含init,control,write,read这几部分,需要相应的去实现,二各外设基本分成两部分:1是类似spi这种有总线的外设,其最大的区别就是可以在一个spi总线上链接很多的设备,各设备的驱动芯片不同,导致需要添加不同的芯片驱动,2是类似串口,定时器这种的,基本都是开始初始化一个设备就可以进行使用。所以两者之间的ops结构体实现的方式是有些不同的。

Spi例子讲解:

 

#include "drv_spi.h"

#include "gd32f30x.h"

#include <rtthread.h>

 

/* private rt-thread spi ops function */

static rt_err_t configure(struct rt_spi_device* device, struct rt_spi_configuration* configuration);

static rt_uint32_t xfer(struct rt_spi_device* device, struct rt_spi_message* message);

 

static struct rt_spi_ops gd32_spi_ops =   //实现rt_spi_ops接口,主要实现里面的成员属性

{

    configure,

    xfer

};

//主要用于配置spi

static rt_err_t configure(struct rt_spi_device* device, struct rt_spi_configuration* configuration)

{

    spi_parameter_struct spi_init_struct;

 

    rt_uint32_t spi_periph = (rt_uint32_t)device->bus->parent.user_data;

 

    RT_ASSERT(device != RT_NULL);

    RT_ASSERT(configuration != RT_NULL);

 

    if(configuration->data_width <= 8)

    {

        spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;

    }

    else if(configuration->data_width <= 16)

    {

        spi_init_struct.frame_size = SPI_FRAMESIZE_16BIT;

    }

    else

    {

        return RT_EIO;

    }

 

    {

        rcu_clock_freq_enum spi_src;

        rt_uint32_t spi_apb_clock;

        rt_uint32_t max_hz;

 

        max_hz = configuration->max_hz;

 

        if (spi_periph == SPI1 || spi_periph == SPI2)

        {

            spi_src = CK_APB1;   //×î´ó60M

        }

        else

        {

            spi_src = CK_APB2;

        }

        spi_apb_clock = rcu_clock_freq_get(spi_src);

 

        if(max_hz >= spi_apb_clock/2)   //2·ÖƵ

        {

            spi_init_struct.prescale = SPI_PSC_2;

        }

        else if (max_hz >= spi_apb_clock/4)

        {

            spi_init_struct.prescale = SPI_PSC_4;

        }

        else if (max_hz >= spi_apb_clock/8)

        {

            spi_init_struct.prescale = SPI_PSC_8;

        }

        else if (max_hz >= spi_apb_clock/16)

        {

            spi_init_struct.prescale = SPI_PSC_16;

        }

        else if (max_hz >= spi_apb_clock/32)

        {

            spi_init_struct.prescale = SPI_PSC_32;

        }

        else if (max_hz >= spi_apb_clock/64)

        {

            spi_init_struct.prescale = SPI_PSC_64;

        }

        else if (max_hz >= spi_apb_clock/128)

        {

            spi_init_struct.prescale = SPI_PSC_128;

        }

        else

        {

            /*  min prescaler 256 */

            spi_init_struct.prescale = SPI_PSC_256;

        }

    } /* baudrate */

    

    switch(configuration->mode & RT_SPI_MODE_3)

    {

    case RT_SPI_MODE_0:

        spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;  

        break;

    case RT_SPI_MODE_1:

        spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_2EDGE;

        break;

    case RT_SPI_MODE_2:

        spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_1EDGE;

        break;

    case RT_SPI_MODE_3:

        spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;

        break;

    }

    

    /* MSB or LSB */

    if(configuration->mode & RT_SPI_MSB)

    {

        spi_init_struct.endian = SPI_ENDIAN_MSB;   //zege

    }

    else

    {

        spi_init_struct.endian = SPI_ENDIAN_LSB;

    }

 

    spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;

    spi_init_struct.device_mode = SPI_MASTER;

    spi_init_struct.nss = SPI_NSS_SOFT;

 

    spi_init(spi_periph, &spi_init_struct);

 

    spi_crc_off(spi_periph);    //spi_crc_polynomial_set(spi_periph,7); spi_crc_on(spi_periph);

   

 

    spi_enable(spi_periph);

 

    return RT_EOK;

};

//实现发送接受接口

static rt_uint32_t xfer(struct rt_spi_device* device, struct rt_spi_message* message)  

{

    rt_base_t gd32_cs_pin = (rt_base_t)device->parent.user_data;

    rt_uint32_t spi_periph = (rt_uint32_t)device->bus->parent.user_data;

    struct rt_spi_configuration * config = &device->config;

 

    RT_ASSERT(device != NULL);

    RT_ASSERT(message != NULL);

 

    /* take CS */

if(message->cs_take)

{  

 gpio_bit_reset(GPIOA,GPIO_PIN_4);

    }

 

    {

        if(config->data_width <= 8)

        {

            const rt_uint8_t * send_ptr = message->send_buf;

            rt_uint8_t * recv_ptr = message->recv_buf;

            rt_uint32_t size = message->length;

            

            DEBUG_PRINTF("spi poll transfer start: %d\n", size);

 

            while(size--)

            {

                rt_uint8_t data = 0xFF;

 

                if(send_ptr != RT_NULL)

                {

                    data = *send_ptr++;

                }

                

                while(RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TBE));

                spi_i2s_data_transmit(spi_periph, data);

 

                while(RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE));

                data = spi_i2s_data_receive(spi_periph);

 

                if(recv_ptr != RT_NULL)

                {

                    *recv_ptr++ = data;

                }

            }

        }

        else if(config->data_width <= 16)

        {

            const rt_uint16_t * send_ptr = message->send_buf;

            rt_uint16_t * recv_ptr = message->recv_buf;

            rt_uint32_t size = message->length;

            while(size--)

            {

                rt_uint16_t data = 0xFF;

 

                if(send_ptr != RT_NULL)

                {

                    data = *send_ptr++;

                }

 

                while(RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TBE));

                spi_i2s_data_transmit(spi_periph, data);

 

                while(RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE));

                data = spi_i2s_data_receive(spi_periph);

 

                if(recv_ptr != RT_NULL)

                {

                    *recv_ptr++ = data;

                }

            }

        }

    }

 

    /* release CS */

    if(message->cs_release)

    {

gpio_bit_set(GPIOA,GPIO_PIN_4);

    }

    return message->length;

};

 

 

int gd32_hw_spi_init(void)   

{

    int result = 0;

#ifdef RT_USING_SPI0

    static struct rt_spi_bus spi_bus0;

    spi_bus0.parent.user_data = (void *)SPI0;

 

    result = rt_spi_bus_register(&spi_bus0, "spi0", &gd32_spi_ops);       

rcu_periph_clock_enable(RCU_GPIOA|RCU_AF);                          

    rcu_periph_clock_enable(RCU_SPI0);

    /* SPI0_SCK(PA5), SPI0_MISO(PA6) and SPI0_MOSI(PA7) GPIO pin configuration */

 

    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_7);   

#endif

    return result;

}

INIT_BOARD_EXPORT(gd32_hw_spi_init);  

#endif

以上代码用于向系统注册spi总线,方便外部挂载设备

 

外部挂载设备可以如下调用:

 

#define SPI_BUS_NAME                  "spi0"   //设备挂载的总线名称

#define SPI_dac104s085_DEVICE_NAME     "spi01"   //随便命名

 

#define CS_PIN   29           //根据不同芯片的引脚号去选择

 

struct stm32_hw_spi_cs

{

    rt_uint32_t pin;

};

 

static struct rt_spi_device spi_dev_dac104s085;

static struct stm32_hw_spi_cs  spi_cs;

 

rt_err_t dac104s085_write_data(const rt_uint16_t *data,const int lendth)

{

    rt_size_t len;

    len = rt_spi_send(&spi_dev_dac104s085, data, lendth);

    if (len != lendth)

    {

        OLED_TRACE("dac104s085_write_data error. %d\r\n",len);

        return -RT_ERROR;

    }

    else       

    {

        return RT_EOK;

    }

}

 

static int rt_hw_dac104s085_config(void)

{

rt_err_t res;

 

    spi_cs.pin = CS_PIN;

    rt_pin_mode(spi_cs.pin, GPIO_MODE_OUT_PP);   

rt_pin_write(CS_PIN, PIN_HIGH);

    res = rt_spi_bus_attach_device(&spi_dev_dac104s085, SPI_dac104s085_DEVICE_NAME, SPI_BUS_NAME, (void*)&spi_cs);

    if (res != RT_EOK)

    {

        OLED_TRACE("rt_spi_bus_attach_device!\r\n");

        return res;

    }

 

    /* config spi */

    {

        struct rt_spi_configuration cfg;

        cfg.data_width = 16;

        cfg.mode =  RT_SPI_MODE_1 | RT_SPI_MSB;

        cfg.max_hz = 40 * 1000 *1000; /* 40M,SPI*/

 

        rt_spi_configure(&spi_dev_dac104s085, &cfg);

    }

    return RT_EOK;

}

 

static int rt_hw_dac104s0835_init(void)

{

rt_hw_dac104s085_config();

    return 0;

}

INIT_PREV_EXPORT(rt_hw_dac104s0835_init);

 

定时器的例子可以下载我上传的资源。

https://download.csdn.net/download/lilijianqun/11570745

 

四驱动流程

1外设的初始化在完整的rtthread的工程中直接使用INIT_BOARD_EXPORT()命令导出去进行自动初始化操作,这个命令调用的是rtthread中的自动初始化功能,

2启动流程

 

$Sub$$main()这个是系统启动最先调用的函数,之后调用rtthread_startup()函数去调用各种必要初始化条件,这些基本重要的函数都在components.c文件中可以查到

 

五开发:

线程,信号量,信号队列,等看文档开发rtrthread编程指南

 

 

六移植:

最主要的在于板卡的支持,其中主要是时钟树的驱动(系统时钟,滴答定时器)和中断的处理

{contextdrv.s中

中断主要是实现上下文切换:

{

“这几个的实现可以参考rtrthread编程指南”

rt_hw_context_switch_to() 

rt_hw_context_switch() 

rt_hw_context_switch_interrupt()

}

PendSV_Handler

rt_hw_interrupt_disable   关中断

rt_hw_interrupt_enable   开中断

rt_hw_interrupt_thread_switch

}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值