BabyOS V8.3.0更新介绍

BabyOS V8.3.0版本首先是修复了队列等模块的bug,然后HAL层增加中断接口,Modules增加select功能模块。

以下对新增的两个模块进行介绍。

HAL层中断接口

BabyOS V8.3.0 之前,MCU发生中断没有接口通知BabyOS,导致编写驱动程序时无法使用中断。

例如:ST的三轴传感器lis3dh,其有32级FIFO并支持FIFO溢出中断。

假设某场景要求ODR为50Hz,读取数据的方式有以下几种:

  1. 每20ms获取一次三轴数据,这样MCU不用干其他事了,对性能影响非常大。

  2. 使用传感器的FIFO,每100ms查询一次FIFO溢出的标志。这样不能及时处理数据。

  3. 使用传感器的FIFO+溢出中断。有中断触发后读取值。这样最为合理。

增加中断接口后,BabyOS编写LIS3DH驱动时可用第3种方式。

那使用什么样的中断接口呢?深入研究MCU内核的中断部分,像ametal那样将原厂SDK里的启动文件都重写?

结合BabyOS开源项目的实际情况,ametal的那种方式是不合适的:

  1. 没有充足的人力、时间投入去研究各类内核。

  2. 第1项不满足的情况,不能考虑对原厂SDK提供的文件进行修改。

最终采用如下方式:

#define bHAL_IT_REGISTER(name, _it, _index, _handler, _user_data) \
    static bHalIt_t name;                                         \
    do                                                            \
    {                                                             \
        name.it        = _it;                                     \
        name.index     = _index;                                  \
        name.handler   = _handler;                                \
        name.user_data = _user_data;                              \
        bHalItRegister(&name);                                    \
    } while (0)

/**
 * 注册中断处理函数。
 * index : 例如,当int 为 B_HAL_IT_EXTI, index可以表示外部中断号
 *         例如  当int 为 B_HAL_IT_UART_RX,index可以表示串口号
 * 推荐使用:bHAL_IT_REGISTER(name, _interrupt, _index, _handler)
 */
int bHalItRegister(bHalIt_t *pit);

/**
 * MCU触发中断后,通过此函数告诉BOS有中断发生,并将数据传给BOS
 */
int bHalItInvoke(bHalItNumber_t it, uint8_t index, bHalItParam_t *param);

中断

select功能模块

紧接着上文,描述为什么增加这个模块。当中断触发后,读取FIFO数据到驱动的缓存等待被读取。

应用程序如何去知道lis3dh缓存已经有数据可读。

  1. 通过bCtl注册回调,驱动程序读取FIFO数据后调用回调

  2. 使用select,同时监控1个或多个句柄的可读、可写和异常情况。

相比回调,使用select可以让代码可读性更加友好。以下是可使用的接口:

#define bFD_ZERO(pfds) 
#define bFD_SET(fd, pfds)
#define bFD_ISSET(fd, pfds)
#define B_PT_SELECT(pt, maxfdp, readfds, writefds, errorfds, timeout, result) 
// bSelect是非阻塞的,如果要做到阻塞的效果,建议开启pt,并使用B_PT_SELECT
int bSelect(int maxfdp, bFdSet_t *readfds, bFdSet_t *writefds, bFdSet_t *errorfds);

lis3dh例程的代码便可以改写成这样:

static PT_THREAD(gsensor_task(struct pt *pt))
{
    int             count = 0;
    bGsensor3Axis_t Gsensor[32];
    static int      fd = -1;
    static bFdSet_t fdset;
    PT_BEGIN(pt);
    fd = bOpen(bLIS3DH, BCORE_FLAG_RW);
    if (fd < 0)
    {
        return 0;
    }
    while (1)
    {
        bFD_ZERO(&fdset);
        bFD_SET(fd, &fdset);
        B_PT_SELECT(pt, fd + 1, &fdset, NULL, NULL, 2000, count);
        b_log("select:%d\r\n", count);
        if (count > 0)
        {
            if (bFD_ISSET(fd, &fdset))
            {
                bRead(fd, (uint8_t *)&Gsensor, sizeof(Gsensor));
                for (int i = 0; i < 32; i++)
                {
                    b_log("x:%d y:%d z:%d\r\n", Gsensor[i].x_mg, Gsensor[i].y_mg, Gsensor[i].z_mg);
                }
            }
        }
    }
    PT_END(pt);
}

以上为抛砖引玉,希望有兴趣的盆友拉取最新的代码体验。对设计方面有建议可以在Issues提单或者基于dev分支修改代码后提交至仓库。