基于优先级调度的嵌入式实时操作系统内核详解(下)

描述

 

三、板载led和串口的驱动

3.1 板载led(GPIO)

RA6M5的引脚结构体定义

左右滑动查看

 

typedef struct _ra6m5_fire_pin_t
{
    cat_uint32_t             pin_num;
    ioport_instance_ctrl_t  *p_ctrl_ptr;
    const bsp_io_port_pin_t  gpio_pin;
}ra6m5_fire_pin_t;

 

暂时只用得上输出引脚,实现pin_write接口,利用fsp库实现引脚输出。

左右滑动查看

 

cat_uint8_t cat_pin_write(cat_uint32_t pin_num, cat_uint8_t val)
{
    cat_uint8_t ret = CAT_ERROR;
    ra6m5_fire_pin_t *p = &(pin_map[0]);


    /* 遍历pin_map数组 */
    for(; p->pin_num!=0xffff; p++)
    {
        if(p->pin_num == pin_num)
        {
            if(0 == val)
            {
                R_IOPORT_PinWrite(p->p_ctrl_ptr, p->gpio_pin, BSP_IO_LEVEL_LOW);
                ret = CAT_EOK;
            }
            else if(1 == val)
            {
                R_IOPORT_PinWrite(p->p_ctrl_ptr, p->gpio_pin, BSP_IO_LEVEL_HIGH);
                ret = CAT_EOK;
            }
            else
            {
                /* 非法值,之后打印错误信息 */
                ret = CAT_ERROR;
                while(1);
            }


            /* 写入结束结束循环 */
            break;
        } /* if */
    } /* for */


    return ret;
}

 

3.2 串口

野火教程以及我找到的官方例程中RA6M5的串口收发均使用中断实现,但在本内核中的标准输入输出函数大部分是以字符为单位,故发送接口用寄存器方式实现,串口接收仍然使用fsp库+中断实现

3.2.1 串口发送

左右滑动查看

 

static cat_int8_t ra6m5_uart_send_char(cat_device_t*dev, cat_uint32_t timeout, cat_uint8_t data)
{
    cat_int8_t ret = CAT_ERROR;
    struct _cat_ra6m5_fire_uart_private_data_t *private_data = NULL;


    /* 获取设备实例数据 */
    private_data = (struct _cat_ra6m5_fire_uart_private_data_t *)(dev->pri_data);


    sci_uart_instance_ctrl_t *p_ctrl = private_data->inst_ctrl_ptr;


    /* 将要发送的数据放进数据寄存器 */
    p_ctrl->p_reg->TDR = data;


    /* 等待发送完成或超时 */
    while(
        ((p_ctrl->p_reg->SSR_b.TEND) == 0) &&
        (0 != timeout)
    )
    {
        timeout--;
    }


    /* 未超时才成功 */
    if(0 != timeout)
    {
        ret = CAT_EOK;
    }


    return ret;
}


static cat_uint32_t ra6m5_uart_send(cat_device_t*dev, uint32_t timeout, uint8_t const * const buffer, uint32_t const size)
{
    (void)timeout;
    cat_uint32_t cnt = 0;
    cat_int8_t err = CAT_EOK;


    while(
        (CAT_EOK == err) &&
        (cnt < size)
    )
    {
        err = ra6m5_uart_send_char(dev, 0xffff, buffer[cnt]);
        cnt++;
    }


    /* 因为前面在一次 while 循环中无论发送是否成功 cnt 都会无条件加一,所以如果失败了就有一个多加上的计数 */
    if(CAT_ERROR == err)
    {
        cnt--;
    }


    return cnt;
}

 

3.2.2 串口接收

左右滑动查看

 

static cat_uint32_t ra6m5_uart_recv(cat_device_t*dev, uint32_t timeout, uint8_t *buffer, uint32_t const size)
{
cat_uint32_t recv_buffer_idx = 0; /**< 串口接收缓冲区访问索引 */
cat_uint32_t err = CAT_ERROR;
struct _cat_ra6m5_fire_uart_private_data_t *private_data = NULL;


/* 获取设备实例数据 */
private_data = (struct _cat_ra6m5_fire_uart_private_data_t *)(dev->pri_data);
assert(NULL != private_data);


/* 读取 */
while(recv_buffer_idx != size)
{
while(
(false == uart4_receive_char) &&
(0 != timeout)
)
{
timeout--;
};


if(0 == timeout)
{
break;
}


while(
(cat_ringbuffer_is_empty(private_data->p_ringbuffer) == 0)
)
{
/* 获取接收到的字符 */
err = cat_ringbuffer_get(private_data->p_ringbuffer, &(buffer[recv_buffer_idx++]));


if(CAT_ERROR == err)
{
/* 获取失败,因为while条件判断过非空,所以出大问题 */
while(1);
}


if(recv_buffer_idx == size)
{
break;
}
}


if(cat_ringbuffer_is_empty(private_data->p_ringbuffer))
{
/* 取完才改遍flag */
uart4_receive_char = false;
}
}


return recv_buffer_idx;
}

 

3.2.3 串口中断服务函数

左右滑动查看

 

/* uart4中断回调函数 */
void debug_uart4_callback(uart_callback_args_t *pargs)
{
    switch(pargs->event)
    {
        case UART_EVENT_RX_CHAR:
        {
            cat_ringbuffer_put(&uart4_rb, pargs->data);
            uart4_receive_char = true;
        }
        default:
        {
            break;
        }
    }
}

 

四、调试验证

4.1 创建demo项目

在Projects目录利用RASC工具生成Keil裸机工程,只需配置led引脚以及UART串口

RTOS

RTOS

4.2 编写程序创建任务

在hal_entry中创建用户任务

左右滑动查看

 

#include "hal_data.h"
#include "catos.h"


FSP_CPP_HEADER
void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER


/*******************************************************************************************************************//**
* main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used.  This function
* is called by main() when no RTOS is used.
**********************************************************************************************************************/
#define TASK1_STACK_SIZE    (1024)
#define TASK2_STACK_SIZE    (1024)


struct _cat_task_t task1;
struct _cat_task_t task2;


cat_stack_type_t task1_env[TASK1_STACK_SIZE];
cat_stack_type_t task2_env[TASK2_STACK_SIZE];


uint32_t sched_task1_times = 0;
uint32_t sched_task2_times = 0;


#define BOARD_LED_PIN 0


void board_led_init(void)
{
    cat_pin_init(BOARD_LED_PIN, CAT_PIN_MODE_OUTPUT);
}


void board_led_on(void)
{
    cat_pin_write(BOARD_LED_PIN, CAT_PIN_LOW);
}


void board_led_off(void)
{
    cat_pin_write(BOARD_LED_PIN, CAT_PIN_HIGH);
}


void task1_entry(void *arg)
{


    for(;;)
    {
        sched_task1_times++;
        board_led_on();
        cat_sp_task_delay(100);
        board_led_off();
        cat_sp_task_delay(100);
    }
}


void task2_entry(void *arg)
{
    for(;;)
    {
        cat_sp_task_delay(100);
        //CAT_DEBUG_PRINTF("[task2] %d
", catos_systicks);
    }
}


void hal_entry(void)
{
    /* TODO: add your own code here */


    /* 初始化os */
    catos_init();


    /* 利用pin驱动初始化板载led */
    board_led_init();


    /* 测试创建任务运行 */
    cat_sp_task_create(
      (const uint8_t *)"task1_task",
      &task1,
      task1_entry,
      NULL,
      0,
      task1_env,
      TASK1_STACK_SIZE
    );


    cat_sp_task_create(
      (const uint8_t *)"task2_task",
      &task2,
      task2_entry,
      NULL,
      0,
      task2_env,
      sizeof(task2_env)
    );




    /* 开始调度 */
    catos_start_sched();


    /* 不会到达这里 */


    while(1);


#if BSP_TZ_SECURE_BUILD
    /* Enter non-secure code */
    R_BSP_NonSecureEnter();
#endif
}



 

4.3 烧写与验证

使用xshell连接串口并烧录程序,可以观察到l led闪烁,并且串口有shell的信息,命令可以正常使用。

RTOS

五、总结

在整个项目过程中,因为涉及底层操作,并且教程还比较少,走了不少弯路,但总体来说还是很不错的,特别是fsp配置方面。

建议瑞萨可以在e2 studio适配更多调试器方便开发者使用;并且在使用野火dap时发现其在ubuntu下要被识别比较麻烦,如果能改进,使用场景会更多。

  审核编辑:汤梓红

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分