【2024-RSOC】Day4 : RT-Thread设备驱动(上)
【2024-RSOC】 基于RT-Thread官方开发板星火一号,本篇参考RT-Thread入门pdf资料《RT-Thread 内核-线程间同步》,和夏令营老师讲解,编写而成。本内容面向小白,因为写这个的作者也是小白,跟着夏令营刚开始学,欸嘿(笑)。
如果初次使用spark的bsp软件包,未构建vscode文件,则参考我前日发布【2024-RSOC】夏令营Day2:初识rt-thread及多线程简单试用中的初次搞机(干通官方bsp源码)
小节,确保工程文件能正常打开烧录例程,再往下进行。
实验1 注册字符设备
代码如下:
#include <rtdevice.h>
#include <rtthread.h>
static int rt_device_test_init(void)
{
//动态创建设备实例
rt_device_t test_dev = rt_device_create(RT_Device_Class_Char,0);
if(!test_dev)
{
rt_kprintf("test_dev create failed!\n");
return -RT_ERROR;
}
if(rt_device_register(test_dev,"test_dev",RT_DEVICE_FLAG_RDWR)!= RT_EOK)
{
rt_kprintf("test_dev register failed\n");
return -RT_ERROR;
}
return RT_EOK;
}
MSH_CMD_EXPORT(rt_device_test_init, rt_device_test_init);
实验2 按键ulog显示
ulog 是一个非常简洁、易用的 C/C++ 日志组件,第一个字母 u 代表 μ,即微型的意思。它能做到最低ROM<1K, RAM<0.2K的资源占用。ulog 不仅有小巧体积,同样也有非常全面的功能,其设计理念参考的是另外一款 C/C++ 开源日志库:EasyLogger(简称 elog),并在功能和性能等方面做了非常多的改进。
首先在env中,我们打开menuconfig.exe
,按照下图设置打开ulog。
首先找到ulog。
选中,再按回车进入内部,勾选Enable ISR log
,保存退出,然后scons -j32
编译。
新建.c文件,将以下代码添加进去。按f5运行。
代码如下:
#include <board.h>
#include <rtthread.h>
#include <drv_gpio.h>
#include <ulog.h>
#ifndef RT_USING_NANO
#include <rtdevice.h>
#endif /* RT_USING_NANO */
#define GPIO_LED_B GET_PIN(F, 11)
#define GPIO_LED_R GET_PIN(F, 12)
#define KET_UP GET_PIN(C, 5)
#define KET_DOWN GET_PIN(C, 1)
#define KET_LIFT GET_PIN(C, 0)
#define KET_RIGHT GET_PIN(C, 4)
#define LOG_TAG "pin.irq"
#define LOG_LVL LOG_LVL_DBG
void key_up_callback(void *args)
{
int value = rt_pin_read(KET_UP);
LOG_I("key up! %d",value);
}
void key_down_callback(void *args)
{
int value = rt_pin_read(KET_DOWN);
LOG_I("key down! %d",value);
}
void key_lift_callback(void *args)
{
int value = rt_pin_read(KET_LIFT);
LOG_I("key lift! %d",value);
}
void key_right_callback(void *args)
{
int value = rt_pin_read(KET_RIGHT);
LOG_I("key right! %d",value);
}
static int rt_pin_irq_example(void)
{
rt_pin_mode(KET_UP, PIN_MODE_INPUT_PULLUP);
rt_pin_mode(KET_DOWN, PIN_MODE_INPUT_PULLUP);
rt_pin_mode(KET_LIFT, PIN_MODE_INPUT_PULLUP);
rt_pin_mode(KET_RIGHT, PIN_MODE_INPUT_PULLUP);
rt_pin_attach_irq(KET_UP,PIN_IRQ_MODE_FALLING,key_up_callback,RT_NULL);
rt_pin_attach_irq(KET_DOWN,PIN_IRQ_MODE_FALLING,key_down_callback,RT_NULL);
rt_pin_attach_irq(KET_LIFT,PIN_IRQ_MODE_FALLING,key_lift_callback,RT_NULL);
rt_pin_attach_irq(KET_RIGHT,PIN_IRQ_MODE_FALLING,key_right_callback,RT_NULL);
rt_pin_irq_enable(KET_UP,PIN_IRQ_ENABLE);
rt_pin_irq_enable(KET_DOWN,PIN_IRQ_ENABLE);
rt_pin_irq_enable(KET_LIFT,PIN_IRQ_ENABLE);
rt_pin_irq_enable(KET_RIGHT,PIN_IRQ_ENABLE);
return RT_EOK;
}
MSH_CMD_EXPORT(rt_pin_irq_example, rt pin irq examlpe);
运行结果如图:按压案件,会打印输出日志。
##实验3 IIC读写。
首先在env中,我们打开menuconfig.exe
,按照下图设置打开IIC。
然后scons -j32
编译。
已经能看到iic1已经注册。
实验4 修改Kconfig文件以添加自己设备
刚才我们选取IIC1已经看到了有5个IIC。如果我们要添加IIC6,那该如何讷?
在board目录下找到Kconfig文件打开,找到IIC的配置行。
将IIC5整段复制,粘贴,修改为IIC6,再打开drv_soft_i2c.c,同样添加一段IIC6的代码如图。
以及修改上方#if defined(BSP_USING_I2C1) || defined(BSP_USING_I2C2) || defined(BSP_USING_I2C3) || defined(BSP_USING_I2C4) || defined(BSP_USING_I2C5) || defined(BSP_USING_I2C6)
(在末尾添加IIC6的判断)
在头文件里也要加上IIC6信息,复制粘贴再修改即可
保存所有修改好的文件,再次打开menuconfig.exe,发现IIC选项内已有IIC6。如图示。
按住shift+?,查看依赖信息,显示的信息对接的即Kconfig的内容。
小插曲ಠ_ಠ
消失的libraries库
刚刚在修改HAL驱动包时发现,我的bsp包内不存在libraries文件夹,导致我无法修改HAL库来添加IIC6的配置信息。那么如何将libraries目录改至工程目录呢?
我们进入.vscode目录查看c_cpp_properties.json
文件,如图:
libraries相关的目录全改为工程目录下,改为如下图示,即删去…\之类的东西。记得保存更改。
此时去stm32目录下,找到libraries文件夹,进入找到星火一号的F407VGT6的HAL库,和HAL_Drivers单独拷贝到工程目录下的libraries文件夹内。scons -j32
编译即可。
i2c-tools探测设备地址。
在menuconfig.exe中启用,如图。可以很便捷的查找设备地址。
实验5 IIC读与写操作
代码如下
#include <rtthread.h>
#include <rtdevice.h>
#include <ulog.h>
#define LOG_TAG "i2c.app"
#define LOG_LVL LOG_LVL_DOG
void i2c_sample_single_byte_write(void)
{
struct rt_i2c_bus_device *i2c_bus;
struct rt_i2c_msg msgs;
rt_uint8_t buf[2];
i2c_bus = (struct rt_i2c_bus_device *)rt_device_find("i2c2");
if (i2c_bus == RT_NULL)
{
LOG_E("can't find %s device!\n","i2c2");
}
buf[0] = 0x6B;
msgs.addr = 0x68;
msgs.flags = RT_I2C_WR;
msgs.buf = buf;
msgs.len = 1;
if (rt_i2c_transfer(i2c_bus,&msgs,1) == 1)
LOG_I("single byte write success!");
else
LOG_E("single byte write failed!");
}
MSH_CMD_EXPORT(i2c_sample_single_byte_write, i2c_sample_single_byte_write);
void i2c_sample_multi_byte_write(void)
{
struct rt_i2c_bus_device *i2c_bus;
struct rt_i2c_msg msgs;
rt_uint8_t buf[3];
i2c_bus = (struct rt_i2c_bus_device *)rt_device_find("i2c2");
if (i2c_bus == RT_NULL)
{
LOG_E("can't find %s device!\n","i2c2");
}
buf[0] = 0x01;
buf[1] = 0x02;
buf[2] = 0x03;
msgs.addr = 0x68;
msgs.flags = RT_I2C_WR;
msgs.buf = buf;
msgs.len = 3;
if (rt_i2c_transfer(i2c_bus,&msgs,1) == 1)
LOG_I("multi byte write success!");
else
LOG_E("multi byte write failed!");
}
MSH_CMD_EXPORT(i2c_sample_multi_byte_write, i2c_sample_multi_byte_write);
void i2c_sample_single_byte_read(void)
{
struct rt_i2c_bus_device *i2c_bus;
struct rt_i2c_msg msgs[2];
rt_uint8_t send_buf[1],recv_buf[1];
rt_err_t ret = RT_EOK;
i2c_bus = (struct rt_i2c_bus_device *)rt_device_find("i2c2");
if (i2c_bus == RT_NULL)
{
LOG_E("can't find %s device!\n","i2c2");
}
send_buf[0] = 0x6B;
recv_buf[1] = 0x6A;
msgs[0].addr = 0x68;
msgs[0].flags = RT_I2C_WR;
msgs[0].buf = send_buf;
msgs[0].len = 1;
msgs[1].addr = 0x68;
msgs[1].flags = RT_I2C_RD;
msgs[1].buf = recv_buf;
msgs[1].len = 1;
ret = rt_i2c_transfer(i2c_bus,&msgs,2);
if (ret == 2)
LOG_I("single byte read success!");
else
LOG_E("single byte read failed! %d", ret);
}
MSH_CMD_EXPORT(i2c_sample_single_byte_read, i2c_sample_single_byte_read);