当前位置: 首页 > 工具软件 > RIOT-OS > 使用案例 >

RIOT OS 学习记录

祁俊喆
2023-12-01

0 学习RIOT的源码结构。

去官网看模块和函数的介绍和例子。下载源码看下。

 

启动过程:

1)startup:cortexM call

void reset_handler_default(void)
{
    uint32_t *dst;
    const uint32_t *src = &_etext;

#ifdef MODULE_PUF_SRAM
    puf_sram_init((uint8_t *)&_srelocate, SEED_RAM_LEN);
#endif

    pre_startup();

#ifdef DEVELHELP
    uint32_t *top;
    /* Fill stack space with canary values up until the current stack pointer */
    /* Read current stack pointer from CPU register */
    __asm__ volatile ("mov %[top], sp" : [top] "=r" (top) : : );
    dst = &_sstack;
    while (dst < top) {
        *(dst++) = STACK_CANARY_WORD;
    }
#endif

    /* load data section from flash to ram */
    for (dst = &_srelocate; dst < &_erelocate; ) {
        *(dst++) = *(src++);
    }

    /* default bss section to zero */
    for (dst = &_szero; dst < &_ezero; ) {
        *(dst++) = 0;
    }

#ifdef CPU_HAS_BACKUP_RAM
    if (!cpu_woke_from_backup() ||
        CPU_BACKUP_RAM_NOT_RETAINED) {

        /* load low-power data section. */
        for (dst = _sbackup_data, src = _sbackup_data_load;
             dst < _ebackup_data;
             dst++, src++) {
            *dst = *src;
        }

        /* zero-out low-power bss. */
        for (dst = _sbackup_bss; dst < _ebackup_bss; dst++) {
            *dst = 0;
        }
    }
#endif /* CPU_HAS_BACKUP_RAM */

#if defined(MODULE_MPU_STACK_GUARD) || defined(MODULE_MPU_NOEXEC_RAM)
    mpu_enable();
#endif

#ifdef MODULE_MPU_NOEXEC_RAM
    /* Mark the RAM non executable. This is a protection mechanism which
     * makes exploitation of buffer overflows significantly harder.
     *
     * This marks the memory region from 0x20000000 to 0x3FFFFFFF as non
     * executable. This is the Cortex-M SRAM region used for on-chip RAM.
     */
    mpu_configure(
        0,                                               /* Region 0 (lowest priority) */
        (uintptr_t)&_sram,                               /* RAM base address */
        MPU_ATTR(1, AP_RW_RW, 0, 1, 0, 1, MPU_SIZE_512M) /* Allow read/write but no exec */
    );
#endif

#ifdef MODULE_MPU_STACK_GUARD
    if (((uintptr_t)&_sstack) != SRAM_BASE) {
        mpu_configure(
            1,                                              /* MPU region 1 */
            (uintptr_t)&_sstack + 31,                       /* Base Address (rounded up) */
            MPU_ATTR(1, AP_RO_RO, 0, 1, 0, 1, MPU_SIZE_32B) /* Attributes and Size */
        );

    }
#endif

    post_startup();

    /* initialize the board (which also initiates CPU initialization) */
    board_init();

#if MODULE_NEWLIB
    /* initialize std-c library (this must be done after board_init) */
    extern void __libc_init_array(void);
    __libc_init_array();
#endif

    /* startup the kernel */
    kernel_init();
}

2)Board initialization:Board initialization functions are defined in board.c. This file must at least define a board_init() function that is called at startup.

void board_init(void)
{
    /* initialize the CPU core */
    cpu_init();

    /* initialize GPIO or others... */
    ...
}
void cpu_init(void)
{
    /* initialize the Cortex-M core */
    cortexm_init();
    /* enable PWR module */
#ifndef CPU_FAM_STM32WB
    periph_clk_en(APB1, BIT_APB_PWREN);
#endif
    /* initialize the system clock as configured in the periph_conf.h */
    stmclk_init_sysclk();
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \
    defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F3) || \
    defined(CPU_FAM_STM32F4) || defined(CPU_FAM_STM32F7) || \
    defined(CPU_FAM_STM32L1)
    _gpio_init_ain();
#endif
#ifdef MODULE_PERIPH_DMA
    /*  initialize DMA streams */
    dma_init();
#endif
    /* initialize stdio prior to periph_init() to allow use of DEBUG() there */
    stdio_init();

#ifdef STM32F1_DISABLE_JTAG
    RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
    AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_JTAGDISABLE;
#endif

    /* trigger static peripheral initialization */
    periph_init();
}

 

void stdio_init(void)
{
    uart_rx_cb_t cb;
    void *arg;

#ifdef MODULE_STDIO_UART_RX
    cb = (uart_rx_cb_t) isrpipe_write_one;
    arg = &stdio_uart_isrpipe;
#else
    cb = NULL;
    arg = NULL;
#endif

#ifdef MODULE_STDIO_ETHOS
    uart_init(ETHOS_UART, ETHOS_BAUDRATE, cb, arg);
#else
    uart_init(STDIO_UART_DEV, STDIO_UART_BAUDRATE, cb, arg);
#endif

#if MODULE_VFS
    vfs_bind_stdio();
#endif
}


/**
 * @brief   Default UART device access macro
 */
#ifndef UART_DEV
#define UART_DEV(x)         (x)
#endif

3)After the board is initialized, RIOT starts two threads: the idle thread and the main thread.The main thread calls the main() function.

void kernel_init(void)
{
    irq_disable();

    thread_create(idle_stack, sizeof(idle_stack),
                  THREAD_PRIORITY_IDLE,
                  THREAD_CREATE_WOUT_YIELD | THREAD_CREATE_STACKTEST,
                  idle_thread, NULL, "idle");

    thread_create(main_stack, sizeof(main_stack),
                  THREAD_PRIORITY_MAIN,
                  THREAD_CREATE_WOUT_YIELD | THREAD_CREATE_STACKTEST,
                  main_trampoline, NULL, "main");

    cpu_switch_context_exit();
}

源代码编译过程:

git clone git://github.com/RIOT-OS/RIOT.git # assumption: git is pre-installed
cd RIOT
git checkout <LATEST_RELEASE>
sudo ./dist/tools/tapsetup/tapsetup         # create virtual Ethernet
                                            # interfaces to connect multiple
                                            # RIOT instances
cd examples/default/
make all
make term

 

1 MCU的板上资源的使用和新板子的移植。

GPIO:

UART:

TIMER:

IIC:

SPI:

 

 

2 多线程编程。

创建:线程优先级设置最好不同 0为最高优先级 -1为最低,栈大小设置。任务执行。

#include "thread.h"

char rcv_thread_stack[THREAD_STACKSIZE_MAIN];

void *rcv_thread(void *arg)
{
    (void) arg;
    msg_t m;

    while (1) {
        msg_receive(&m);
        printf("Got msg from %" PRIkernel_pid "\n", m.sender_pid);
    }

    return NULL;
}

int main(void)
{
    thread_create(rcv_thread_stack, sizeof(rcv_thread_stack),
                  THREAD_PRIORITY_MAIN - 1, THREAD_CREATE_STACKTEST,
                  rcv_thread, NULL, "rcv_thread");
}

 

线程间通信,msg

(1)阻塞式:msg_send() or msg_receive()

#include <stdio.h>

#include "msg.h"
#include "thread.h"

static kernel_pid_t rcv_pid;
static char rcv_stack[THREAD_STACKSIZE_DEFAULT];

static void *rcv(void *arg)
{
    msg_t msg_req, msg_resp;

    (void)arg;
    while (1) {
        msg_receive(&msg_req);
        msg_resp.content.value = msg_req.content.value + 1;
        msg_reply(&msg_req, &msg_resp);
    }
    return NULL;
}

int main(void)
{
    msg_t msg_req, msg_resp;

    msg_resp.content.value = 0;
    rcv_pid = thread_create(rcv_stack, sizeof(rcv_stack),
                            THREAD_PRIORITY_MAIN - 1, 0, rcv, NULL, "rcv");
    while (1) {
        msg_req.content.value = msg_resp.content.value;
        msg_send_receive(&msg_req, &msg_resp, rcv_pid);
        printf("Result: %" PRIu32 "\n", msg_resp.content.value);
    }
    return 0;
}

(2)非阻塞式:msg_try_send() or msg_try_receive()

#include <inttypes.h>
#include <stdio.h>

#include "msg.h"
#include "thread.h"

#define RCV_QUEUE_SIZE  (8)

static kernel_pid_t rcv_pid;
static char rcv_stack[THREAD_STACKSIZE_DEFAULT + THREAD_EXTRA_STACKSIZE_PRINTF];
static msg_t rcv_queue[RCV_QUEUE_SIZE];

static void *rcv(void *arg)
{
    msg_t msg;

    (void)arg;
    msg_init_queue(rcv_queue, RCV_QUEUE_SIZE);
    while (1) {
        msg_receive(&msg);
        printf("Received %" PRIu32 "\n", msg.content.value);
    }
    return NULL;
}

int main(void)
{
    msg_t msg;

    msg.content.value = 0;
    rcv_pid = thread_create(rcv_stack, sizeof(rcv_stack),
                            THREAD_PRIORITY_MAIN - 1, 0, rcv, NULL, "rcv");
    while (1) {
        if (msg_try_send(&msg, rcv_pid) == 0) {
            printf("Receiver queue full.\n");
        }
        msg.content.value++;
    }
    return 0;
}

同步:条件变量 互斥锁。

mutex_lock(&lock);
while (condition_is_not_true) {
    cond_wait(&cond, &lock);
}
// do work while condition is true.
mutex_unlock(&lock);

 

3 编写新的设备驱动。

4 MCU裸奔和有系统的区别是啥?上系统的价值很大?

从软件工程的开发和维护难度、开发速度和软件性能方面考虑。

 

 类似资料: