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裸奔和有系统的区别是啥?上系统的价值很大?
从软件工程的开发和维护难度、开发速度和软件性能方面考虑。