- 2024-09-18
-
加入了学习《Follow me第二季第2期视频演示》,观看 演示视频
- 2024-09-14
-
回复了主题帖:
小调查:大家在学习Rust嵌入式遇到哪些困难?如果搞实战项目,有何建议?
Rust的问题就是把简单的事情复杂化了,不容易入门。
- 2024-08-29
-
回复了主题帖:
《嵌入式软件的时间分析》书友问答接龙 第十集:AUTOSAR
Autosar中Runnable和task是什么关系?
-
回复了主题帖:
《嵌入式软件的时间分析》书友问答接龙 第九集:开发过程中的方法技巧
一点小总结:
本文分享了在嵌入式软件开发的每个阶段如何考虑软件时间,
主要包括时间需求和时间分析需求,时间测试以及检测最终的产品时间。
从个人感受而言,业内尤其是国内能专门去做时间需求分析的微乎其微,
其实更多是在乎开发者个人的考虑于能力,这里提供一个简单点实践策略,
就是根据经验总结checklist而不是专门去做时间需求分析,因为大部分嵌入式软件都是类似的,
比如检查malloc/free的时间消耗,可以封装专门的带时间测试的接口,比如检查中断的执行时间,使用IO翻转示波器查看,这些常见的时间分析写入checklist,并对于通用实现一些封装可供直接调用。
- 2024-08-15
-
回复了主题帖:
《嵌入式软件的时间分析》书友问答接龙 第八集:软件运行时间优化
一点小总结:书中总结了很多时间优化的方法和示例,比如memcpy的优化剖析。
个人有点感受,书中提到的数据对齐,在嵌入式开发中其实是很容易获得比较好的优化效果的一个小的编程技巧,平常编程时就可以尽量考虑使用数据对齐。
另外减少存储的拷贝,也是一个优化时间的比较简单有效的方法。
还有就是减少循环体内的执行时间等,也是比较有用的方法,
总之一点,优化时间要先找出花费时间比较大头的地方去优化,首先从算法架构,实现方式去优化,其次才是去利用某些特定特性,比如cache去优化,因为后者往往有副作用需要注意,前者才是通用且成本低效果好的方式。
- 2024-08-08
-
回复了主题帖:
《嵌入式软件的时间分析》书友问答接龙 第七集:多核及多ECU环境下的软件时间
做个小的总结,
这章首先提到了同构,异构,锁步这三种多核架构,其中锁步架构比较有意思,感觉是在宇航级芯片上可能用的多,实际是一种冗余设计,这种冗余要考虑两种实现要不一样,避免同类错误导致"全军覆没",比如镜像放置,时钟偏置,独立时钟等等细节都是处于此考虑。
然后介绍了不同类型的并行执行:应用程序并行执行,函数的并行执行,指令的并行执行。
然后提到了数据一致性的问题,一般低端MCU都没有cache所以遇到比较少,而高端cache会有多级cache,多核,这个问题变得很突出,需要时刻关注数据一致性问题。
- 2024-08-02
-
回复了主题帖:
《嵌入式软件的时间分析》书友问答接龙 第六集:软件时间问题案例
6.5 拉着手刹去比赛,举了一个有趣的例子,由于项目复杂且从闪存执行大量代码导致速度变慢导致功能异常,使能了Cache之后速度加快功能正常了。
其实对于嵌入式开发来说,这里隐含着一个非常需要重视的问题,即事物的正反面,使能了Cache虽然大大提高了性能,但是必定导致数据一致性的问题,应用开发就需要处处关注,是否存在一致性问题,一致性问题很可能导致很多隐蔽难以发现的问题。这就是嵌入式开发中需要处处关注并且最终权衡选择的。
包括存储需求-性能的权衡,可移植性-复杂性的权衡,时间换空间,空间换时间等等。
- 2024-07-25
-
回复了主题帖:
《嵌入式软件的时间分析》书友问答接龙 第五集:软件时间分析方法
hehung 发表于 2024-7-23 13:31
调度模式的原理和工作方式是什么
调度模拟是对操作系统组织任务和中断的执行逻辑进行模拟。
选择用于模拟的操作系统->
创建任务和中断->
静态动态参数配置->
激活模式激活任务并触发中断->
生成追踪图表
-
发表了主题帖:
【瑞萨RA8D1开发板,基于M85内核的图形MCU】移植精简的shell
前面我们移植了xprintf可以方便的打印输出和输入,为了方便后面调试开发,我们进一步移植一个精简的shell,实现命令行交互。
参考微信公众号”嵌入式Lee”的文章
https://mp.weixin.qq.com/s/XLmbJn0SKoDT1aLdxHDrbg 一个超级精简高可移植的shell命令行C实现
Shell.c如下,完全可移植无需修改
#include <stdint.h>
#include "shell.h"
shell_read_pf s_input_pf = 0; /* ?????? */
shell_write_pf s_output_pf = 0; /* ?????? */
shell_cmd_cfg* s_cmd_cfg_pst = 0; /* ?????? */
uint8_t s_enableecho_u8 = 0; /* ????echo?? */
static uint8_t s_cmd_buf_au8[SHELL_CMD_LEN]="\r"; /* ????? */
static uint32_t s_cmd_buf_index_u32 = 0; /* ??????????? */
/**
* ??????
*/
static void shell_putchar(uint8_t val)
{
uint8_t tmp;
if(s_output_pf != 0)
{
tmp = val;
s_output_pf(&tmp, 1);
}
}
/**
* ???????
*/
static void shell_putstring(char* str)
{
uint32_t len = 0;
uint8_t*p = (uint8_t*)str;
while(*str++)
{
len++;
}
s_output_pf(p, len);
}
/**
* ?????
*/
static int shell_getchar(uint8_t *data)
{
if(s_input_pf == 0)
{
return -1;
}
if(0 == s_input_pf(data, 1))
{
return -1;
}
else
{
return 0;
}
}
/**
* ??????????
* ??????????
*/
static uint32_t shell_cmd_len(uint8_t *cmd)
{
uint8_t *p = cmd;
uint32_t len = 0;
while((*p != ' ') && (*p != 0))
{
p++;
len++;
}
return len;
}
/**
* ???????????,????0
*/
static int shell_cmd_check(uint8_t *cmd, uint8_t *str)
{
uint32_t len1 = shell_cmd_len(cmd);
uint32_t len2 = shell_cmd_len(str);
if(len1 != len2)
{
return -1;
}
for(uint32_t i=0; i<len1; i++)
{
if(*cmd++ != *str++)
{
return -1;
}
}
return 0;
}
/**
* ??????
*/
static uint32_t shell_read_line(void)
{
uint8_t ch;
uint32_t count;
/* ????sh> */
if(s_cmd_buf_au8[0]=='\r')
{
shell_putstring("sh>\r\n");
s_cmd_buf_au8[0] = 0;
}
/* ????????? */
if(shell_getchar(&ch) !=0 )
{
return 0;
}
/* ???????????????,?????????
* ????????,????????
*/
if((ch == '\r' || ch == '\n' || ch < ' ' || ch > '~') && (ch != '\b'))
{
if(s_cmd_buf_index_u32==0)
{
/* ?????????????????,?????sh> */
shell_putstring("sh>\r\n");
}
else
{
/* ????????,???????????????
* ?????????,?????,??????
* ???????0
*/
count = s_cmd_buf_index_u32;
s_cmd_buf_au8[s_cmd_buf_index_u32]=0;
s_cmd_buf_index_u32 =0;
shell_putstring("\r\n");
return count;
}
}
else
{
if(ch == '\b')
{
/* ????,???????????????,????? */
if(s_cmd_buf_index_u32 != 0)
{
s_cmd_buf_index_u32--;
shell_putchar('\b');
shell_putchar(' ');
shell_putchar('\b');
s_cmd_buf_au8[s_cmd_buf_index_u32]= '\0';
}
}
else
{
/* ?????,??????
* ??????????????-1,?????????
* -1?????????0??
*/
if(s_enableecho_u8 != 0)
{
shell_putchar(ch);
}
s_cmd_buf_au8[s_cmd_buf_index_u32++] = ch;
if(s_cmd_buf_index_u32>=(sizeof(s_cmd_buf_au8)-1))
{
count = s_cmd_buf_index_u32;
s_cmd_buf_au8[s_cmd_buf_index_u32]=0;
s_cmd_buf_index_u32 =0;
shell_putstring("\r\n");
return count;
}
}
}
return 0;
}
/**
* ??????????
*/
static int shell_exec_cmdlist(uint8_t* cmd)
{
int i;
if(s_cmd_cfg_pst == 0)
{
return -1;
}
for (i=0; s_cmd_cfg_pst[i].name != 0; i++)
{
if (shell_cmd_check(cmd, s_cmd_cfg_pst[i].name) == 0)
{
s_cmd_cfg_pst[i].func(cmd);
return 0;
}
}
if(s_cmd_cfg_pst[i].name == 0)
{
shell_putstring("unkown command\r\n");
return -1;
}
return 0;
}
/**
* ????,????
*/
void shell_exec(void)
{
if(shell_read_line() > 0)
{
shell_exec_cmdlist(s_cmd_buf_au8);
}
}
/**
* ????,???????
*/
void shell_set_itf(shell_read_pf input, shell_write_pf output, shell_cmd_cfg* cmd_list, uint8_t enableecho)
{
s_input_pf = input;
s_output_pf = output;
s_cmd_cfg_pst = cmd_list;
s_enableecho_u8 = enableecho;
}
Shell.h如下,完全可移植无需修改
#ifndef SHELL_H
#define SHELL_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#define SHELL_CMD_LEN 512 /**< ??????? */
typedef void (*shell_command_pf)(uint8_t *); /**< ?????? */
typedef uint32_t (*shell_read_pf)(uint8_t *buff, uint32_t len); /**< ????? */
typedef void (*shell_write_pf)(uint8_t *buff, uint32_t len); /**< ????? */
/**
* \struct shell_cmd_cfg
* ????
*/
typedef struct
{
uint8_t * name; /**< ????? */
shell_command_pf func; /**< ?????? */
uint8_t * helpstr; /**< ?????? */
}shell_cmd_cfg;
/**
* \fn shell_exec
* ???????,??????,????????????
* ???
*/
void shell_exec(void);
/**
* \fn shell_set_itf
* ??????????,??????
* ??shell_exec_shellcmd??,???????????
* \param[in] input \ref shell_read_pf ????
* \param[in] output \ref shell_write_pf ????
* \param[in] cmd_list \ref shell_cmd_cfg ????
* \param[in] enableecho 0:?????, ???:????
*/
void shell_set_itf(shell_read_pf input, shell_write_pf output, shell_cmd_cfg* cmd_list, uint8_t enableecho);
#ifdef __cplusplus
}
#endif
#endif
shell_func.c如下,可以添加自己的命令,默认实现了help命令,打印所有命令信息
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "shell.h"
#include "shell_func.h"
#include "xprintf.h"
static void helpfunc(uint8_t* param);
/**
* ???????0,??????
*/
const shell_cmd_cfg g_shell_cmd_list_ast[ ] =
{
{ (uint8_t*)"help", helpfunc, (uint8_t*)"help"},
{ (uint8_t*)0, 0 , 0},
};
void helpfunc(uint8_t* param)
{
(void)param;
unsigned int i;
xprintf("\r\n");
xprintf("**************\r\n");
xprintf("* SHELL *\r\n");
xprintf("* V1.0 *\r\n");
xprintf("**************\r\n");
xprintf("\r\n");
for (i=0; g_shell_cmd_list_ast[i].name != 0; i++)
{
xprintf("%02d.",i);
xprintf("%-16s",g_shell_cmd_list_ast[i].name);
xprintf("%s\r\n",g_shell_cmd_list_ast[i].helpstr);
}
}
Shell_func.h如下
#ifndef SHELL_FUNC_H
#define SHELL_FUNC_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
extern const shell_cmd_cfg g_shell_cmd_list_ast[ ];
#ifdef __cplusplus
}
#endif
#endif
实现接口
static uint32_t shell_read_port(uint8_t *buff, uint32_t len)
{
return uart_read(buff,len);
}
static void shell_write_port(uint8_t *buff, uint32_t len)
{
uart_send(buff,len);
}
设置接口
#include "shell.h"
#include "shell_func.h"
shell_set_itf(shell_read_port, shell_write_port, (shell_cmd_cfg*)g_shell_cmd_list_ast, 1);
测试
void blinky_thread_entry (void * pvParameters)
{
uart_init();
xdev_out(xprintf_out_port);
xdev_in(xprintf_in_port);
shell_set_itf(shell_read_port, shell_write_port, (shell_cmd_cfg*)g_shell_cmd_list_ast, 1);
while(1)
{
shell_exec();
vTaskDelay(1);
}
效果如下,上输入help回车,打印所有支持的命令
后面就可以方便添加更多自己的命令,方便调试开发。
- 2024-07-24
-
发表了主题帖:
【瑞萨RA8D1开发板,基于M85内核的图形MCU】移植轻量标准输入输出函数库xprintf
前面我们实现了好用的串口收发接口,进一步我们来实现基于串口的输入输出,方便后面交互打印信息等。
参考微信公众号”嵌入式Lee”的文章
https://mp.weixin.qq.com/s/y4MHV3cd4T0b51L5M4J5Xg 极海半导体APM32F107VC开发板-移植超轻量级标准输入输出函数库xprintf
Xprintf.c如下
/*------------------------------------------------------------------------/
/ Universal String Handler for Console Input and Output
/-------------------------------------------------------------------------/
/
/ Copyright (C) 2021, ChaN, all right reserved.
/
/ xprintf module is an open source software. Redistribution and use of
/ xprintf module in source and binary forms, with or without modification,
/ are permitted provided that the following condition is met:
/
/ 1. Redistributions of source code must retain the above copyright notice,
/ this condition and the following disclaimer.
/
/ This software is provided by the copyright holder and contributors "AS IS"
/ and any warranties related to this software are DISCLAIMED.
/ The copyright owner or contributors be NOT LIABLE for any damages caused
/ by use of this software.
/
/-------------------------------------------------------------------------*/
#include "xprintf.h"
#define SZB_OUTPUT 32
#if XF_USE_OUTPUT
#include <stdarg.h>
void (*xfunc_output)(int); /* Pointer to the default output device */
static char *strptr; /* Pointer to the output memory (used by xsprintf) */
#if XF_USE_FP
/*----------------------------------------------*/
/* Floating point output */
/*----------------------------------------------*/
#include <math.h>
static int ilog10 (double n) /* Calculate log10(n) in integer output */
{
int rv = 0;
while (n >= 10) { /* Decimate digit in right shift */
if (n >= 100000) {
n /= 100000; rv += 5;
} else {
n /= 10; rv++;
}
}
while (n < 1) { /* Decimate digit in left shift */
if (n < 0.00001) {
n *= 100000; rv -= 5;
} else {
n *= 10; rv--;
}
}
return rv;
}
static double i10x (int n) /* Calculate 10^n */
{
double rv = 1;
while (n > 0) { /* Left shift */
if (n >= 5) {
rv *= 100000; n -= 5;
} else {
rv *= 10; n--;
}
}
while (n < 0) { /* Right shift */
if (n <= -5) {
rv /= 100000; n += 5;
} else {
rv /= 10; n++;
}
}
return rv;
}
static void ftoa (
char* buf, /* Buffer to output the generated string */
double val, /* Real number to output */
int prec, /* Number of fractinal digits */
char fmt /* Notation */
)
{
int d;
int e = 0, m = 0;
char sign = 0;
double w;
const char *er = 0;
if (isnan(val)) { /* Not a number? */
er = "NaN";
} else {
if (prec < 0) prec = 6; /* Default precision (6 fractional digits) */
if (val < 0) { /* Nagative value? */
val = -val; sign = '-';
} else {
sign = '+';
}
if (isinf(val)) { /* Infinite? */
er = "INF";
} else {
if (fmt == 'f') { /* Decimal notation? */
val += i10x(-prec) / 2; /* Round (nearest) */
m = ilog10(val);
if (m < 0) m = 0;
if (m + prec + 3 >= SZB_OUTPUT) er = "OV"; /* Buffer overflow? */
} else { /* E notation */
if (val != 0) { /* Not a true zero? */
val += i10x(ilog10(val) - prec) / 2; /* Round (nearest) */
e = ilog10(val);
if (e > 99 || prec + 6 >= SZB_OUTPUT) { /* Buffer overflow or E > +99? */
er = "OV";
} else {
if (e < -99) e = -99;
val /= i10x(e); /* Normalize */
}
}
}
}
if (!er) { /* Not error condition */
if (sign == '-') *buf++ = sign; /* Add a - if negative value */
do { /* Put decimal number */
w = i10x(m); /* Snip the highest digit d */
d = val / w; val -= d * w;
if (m == -1) *buf++ = XF_DPC; /* Insert a decimal separarot if get into fractional part */
*buf++ = '0' + d; /* Put the digit */
} while (--m >= -prec); /* Output all digits specified by prec */
if (fmt != 'f') { /* Put exponent if needed */
*buf++ = fmt;
if (e < 0) {
e = -e; *buf++ = '-';
} else {
*buf++ = '+';
}
*buf++ = '0' + e / 10;
*buf++ = '0' + e % 10;
}
}
}
if (er) { /* Error condition? */
if (sign) *buf++ = sign; /* Add sign if needed */
do *buf++ = *er++; while (*er); /* Put error symbol */
}
*buf = 0; /* Term */
}
#endif /* XF_USE_FLOAT */
/*----------------------------------------------*/
/* Put a character */
/*----------------------------------------------*/
void xputc (
int chr /* Character to be output */
)
{
xfputc(xfunc_output, chr); /* Output it to the default output device */
}
void xfputc ( /* Put a character to the specified device */
void(*func)(int), /* Pointer to the output function (null:strptr) */
int chr /* Character to be output */
)
{
if (XF_CRLF && chr == '\n') xfputc(func, '\r'); /* CR -> CRLF */
if (func) {
func(chr); /* Write a character to the output device */
} else if (strptr) {
*strptr++ = chr; /* Write a character to the memory */
}
}
/*----------------------------------------------*/
/* Put a null-terminated string */
/*----------------------------------------------*/
void xputs ( /* Put a string to the default device */
const char* str /* Pointer to the string */
)
{
xfputs(xfunc_output, str);
}
void xfputs ( /* Put a string to the specified device */
void(*func)(int), /* Pointer to the output function */
const char* str /* Pointer to the string */
)
{
while (*str) { /* Put the string */
xfputc(func, *str++);
}
}
/*----------------------------------------------*/
/* Formatted string output */
/*----------------------------------------------*/
/* xprintf("%d", 1234); "1234"
xprintf("%6d,%3d%%", -200, 5); " -200, 5%"
xprintf("%-6u", 100); "100 "
xprintf("%ld", 12345678); "12345678"
xprintf("%llu", 0x100000000); "4294967296" <XF_USE_LLI>
xprintf("%lld", -1LL); "-1" <XF_USE_LLI>
xprintf("%04x", 0xA3); "00a3"
xprintf("%08lX", 0x123ABC); "00123ABC"
xprintf("%016b", 0x550F); "0101010100001111"
xprintf("%*d", 6, 100); " 100"
xprintf("%s", "String"); "String"
xprintf("%5s", "abc"); " abc"
xprintf("%-5s", "abc"); "abc "
xprintf("%-5s", "abcdefg"); "abcdefg"
xprintf("%-5.5s", "abcdefg"); "abcde"
xprintf("%-.5s", "abcdefg"); "abcde"
xprintf("%-5.5s", "abc"); "abc "
xprintf("%c", 'a'); "a"
xprintf("%12f", 10.0); " 10.000000" <XF_USE_FP>
xprintf("%.4E", 123.45678); "1.2346E+02" <XF_USE_FP>
*/
static void xvfprintf (
void(*func)(int), /* Pointer to the output function */
const char* fmt, /* Pointer to the format string */
va_list arp /* Pointer to arguments */
)
{
unsigned int r, i, j, w, f;
int n, prec;
char str[SZB_OUTPUT], c, d, *p, pad;
#if XF_USE_LLI
long long v;
unsigned long long uv;
#else
long v;
unsigned long uv;
#endif
for (;;) {
c = *fmt++; /* Get a format character */
if (!c) break; /* End of format? */
if (c != '%') { /* Pass it through if not a % sequense */
xfputc(func, c); continue;
}
f = w = 0; /* Clear parms */
pad = ' '; prec = -1;
c = *fmt++; /* Get first char of the sequense */
if (c == '0') { /* Flag: left '0' padded */
pad = '0'; c = *fmt++;
} else {
if (c == '-') { /* Flag: left justified */
f = 2; c = *fmt++;
}
}
if (c == '*') { /* Minimum width from an argument */
n = va_arg(arp, int);
if (n < 0) { /* Flag: left justified */
n = 0 - n; f = 2;
}
w = n; c = *fmt++;
} else {
while (c >= '0' && c <= '9') { /* Minimum width */
w = w * 10 + c - '0';
c = *fmt++;
}
}
if (c == '.') { /* Precision */
c = *fmt++;
if (c == '*') { /* Precision from an argument */
prec = va_arg(arp, int);
c = *fmt++;
} else {
prec = 0;
while (c >= '0' && c <= '9') {
prec = prec * 10 + c - '0';
c = *fmt++;
}
}
}
if (c == 'l') { /* Prefix: Size is long */
f |= 4; c = *fmt++;
#if XF_USE_LLI
if (c == 'l') { /* Prefix: Size is long long */
f |= 8; c = *fmt++;
}
#endif
}
if (!c) break; /* End of format? */
switch (c) { /* Type is... */
case 'b': /* Unsigned binary */
r = 2; break;
case 'o': /* Unsigned octal */
r = 8; break;
case 'd': /* Signed decimal */
case 'u': /* Unsigned decimal */
r = 10; break;
case 'x': /* Hexdecimal (lower case) */
case 'X': /* Hexdecimal (upper case) */
r = 16; break;
case 'c': /* A character */
xfputc(func, (char)va_arg(arp, int)); continue;
case 's': /* String */
p = va_arg(arp, char*); /* Get a pointer argument */
if (!p) p = ""; /* Null ptr generates a null string */
j = strlen(p);
if (prec >= 0 && j > (unsigned int)prec) j = prec; /* Limited length of string body */
for ( ; !(f & 2) && j < w; j++) xfputc(func, pad); /* Left pads */
while (*p && prec--) xfputc(func, *p++);/* String body */
while (j++ < w) xfputc(func, ' '); /* Right pads */
continue;
#if XF_USE_FP
case 'f': /* Float (decimal) */
case 'e': /* Float (e) */
case 'E': /* Float (E) */
ftoa(p = str, va_arg(arp, double), prec, c); /* Make fp string */
for (j = strlen(p); !(f & 2) && j < w; j++) xfputc(func, pad); /* Left pads */
while (*p) xfputc(func, *p++); /* Value */
while (j++ < w) xfputc(func, ' '); /* Right pads */
continue;
#endif
default: /* Unknown type (passthrough) */
xfputc(func, c); continue;
}
/* Get an integer argument and put it in numeral */
#if XF_USE_LLI
if (f & 8) { /* long long argument? */
v = (long long)va_arg(arp, long long);
} else {
if (f & 4) { /* long argument? */
v = (c == 'd') ? (long long)va_arg(arp, long) : (long long)va_arg(arp, unsigned long);
} else { /* int/short/char argument */
v = (c == 'd') ? (long long)va_arg(arp, int) : (long long)va_arg(arp, unsigned int);
}
}
#else
if (f & 4) { /* long argument? */
v = (long)va_arg(arp, long);
} else { /* int/short/char argument */
v = (c == 'd') ? (long)va_arg(arp, int) : (long)va_arg(arp, unsigned int);
}
#endif
if (c == 'd' && v < 0) { /* Negative value? */
v = 0 - v; f |= 1;
}
i = 0; uv = v;
do { /* Make an integer number string */
d = (char)(uv % r); uv /= r;
if (d > 9) d += (c == 'x') ? 0x27 : 0x07;
str[i++] = d + '0';
} while (uv != 0 && i < sizeof str);
if (f & 1) str[i++] = '-'; /* Sign */
for (j = i; !(f & 2) && j < w; j++) xfputc(func, pad); /* Left pads */
do xfputc(func, str[--i]); while (i != 0); /* Value */
while (j++ < w) xfputc(func, ' '); /* Right pads */
}
}
void xprintf ( /* Put a formatted string to the default device */
const char* fmt, /* Pointer to the format string */
... /* Optional arguments */
)
{
va_list arp;
va_start(arp, fmt);
xvfprintf(xfunc_output, fmt, arp);
va_end(arp);
}
void xfprintf ( /* Put a formatted string to the specified device */
void(*func)(int), /* Pointer to the output function */
const char* fmt, /* Pointer to the format string */
... /* Optional arguments */
)
{
va_list arp;
va_start(arp, fmt);
xvfprintf(func, fmt, arp);
va_end(arp);
}
void xsprintf ( /* Put a formatted string to the memory */
char* buff, /* Pointer to the output buffer */
const char* fmt, /* Pointer to the format string */
... /* Optional arguments */
)
{
va_list arp;
strptr = buff; /* Enable destination for memory */
va_start(arp, fmt);
xvfprintf(0, fmt, arp);
va_end(arp);
*strptr = 0; /* Terminate output string */
strptr = 0; /* Disable destination for memory */
}
#if XF_USE_DUMP
/*----------------------------------------------*/
/* Dump a line of binary dump */
/*----------------------------------------------*/
void put_dump (
const void* buff, /* Pointer to the array to be dumped */
unsigned long addr, /* Heading address value */
int len, /* Number of items to be dumped */
size_t width /* Size of buff[0] (1, 2 or 4) */
)
{
int i;
const unsigned char *bp;
const unsigned short *sp;
const unsigned long *lp;
xprintf("%08lX ", addr); /* address */
switch (width) {
case sizeof (char):
bp = buff;
for (i = 0; i < len; i++) { /* Hexdecimal dump in (char) */
xprintf(" %02X", bp[i]);
}
xputs(" ");
for (i = 0; i < len; i++) { /* ASCII dump */
xputc((unsigned char)((bp[i] >= ' ' && bp[i] <= '~') ? bp[i] : '.'));
}
break;
case sizeof (short):
sp = buff;
do { /* Hexdecimal dump in (short) */
xprintf(" %04X", *sp++);
} while (--len);
break;
case sizeof (long):
lp = buff;
do { /* Hexdecimal dump in (short) */
xprintf(" %08lX", *lp++);
} while (--len);
break;
}
xputc('\n');
}
#endif /* XF_USE_DUMP */
#endif /* XF_USE_OUTPUT */
#if XF_USE_INPUT
int (*xfunc_input)(void); /* Pointer to the default input stream */
/*----------------------------------------------*/
/* Get a line from the input */
/*----------------------------------------------*/
int xgets ( /* 0:End of stream, 1:A line arrived */
char* buff, /* Pointer to the buffer */
int len /* Buffer length */
)
{
int c, i;
if (!xfunc_input) return 0; /* No input function is specified */
i = 0;
for (;;) {
c = xfunc_input(); /* Get a char from the incoming stream */
if (c < 0 || c == '\r') break; /* End of stream or CR? */
if (c == '\b' && i) { /* BS? */
i--;
if (XF_INPUT_ECHO) xputc(c);
continue;
}
if (c >= ' ' && i < len - 1) { /* Visible chars? */
buff[i++] = c;
if (XF_INPUT_ECHO) xputc(c);
}
}
if (XF_INPUT_ECHO) {
xputc('\r');
xputc('\n');
}
buff[i] = 0; /* Terminate with a \0 */
return (int)(c == '\r');
}
/*----------------------------------------------*/
/* Get a value of integer string */
/*----------------------------------------------*/
/* "123 -5 0x3ff 0b1111 0377 w "
^ 1st call returns 123 and next ptr
^ 2nd call returns -5 and next ptr
^ 3rd call returns 1023 and next ptr
^ 4th call returns 15 and next ptr
^ 5th call returns 255 and next ptr
^ 6th call fails and returns 0
*/
int xatoi ( /* 0:Failed, 1:Successful */
char **str, /* Pointer to pointer to the string */
long *res /* Pointer to the valiable to store the value */
)
{
unsigned long val;
unsigned char c, r, s = 0;
*res = 0;
while ((c = **str) == ' ') (*str)++; /* Skip leading spaces */
if (c == '-') { /* negative? */
s = 1;
c = *(++(*str));
}
if (c == '0') {
c = *(++(*str));
switch (c) {
case 'x': /* hexdecimal */
r = 16; c = *(++(*str));
break;
case 'b': /* binary */
r = 2; c = *(++(*str));
break;
default:
if (c <= ' ') return 1; /* single zero */
if (c < '0' || c > '9') return 0; /* invalid char */
r = 8; /* octal */
}
} else {
if (c < '0' || c > '9') return 0; /* EOL or invalid char */
r = 10; /* decimal */
}
val = 0;
while (c > ' ') {
if (c >= 'a') c -= 0x20;
c -= '0';
if (c >= 17) {
c -= 7;
if (c <= 9) return 0; /* invalid char */
}
if (c >= r) return 0; /* invalid char for current radix */
val = val * r + c;
c = *(++(*str));
}
if (s) val = 0 - val; /* apply sign if needed */
*res = val;
return 1;
}
#if XF_USE_FP
/*----------------------------------------------*/
/* Get a value of the real number string */
/*----------------------------------------------*/
/* Float version of xatoi
*/
int xatof ( /* 0:Failed, 1:Successful */
char **str, /* Pointer to pointer to the string */
double *res /* Pointer to the valiable to store the value */
)
{
double val;
int s, f, e;
unsigned char c;
*res = 0;
s = f = 0;
while ((c = **str) == ' ') (*str)++; /* Skip leading spaces */
if (c == '-') { /* Negative? */
c = *(++(*str)); s = 1;
} else if (c == '+') { /* Positive? */
c = *(++(*str));
}
if (c == XF_DPC) { /* Leading dp? */
f = -1; /* Start at fractional part */
c = *(++(*str));
}
if (c <= ' ') return 0; /* Wrong termination? */
val = 0;
while (c > ' ') { /* Get a value of decimal */
if (c == XF_DPC) { /* Embedded dp? */
if (f < 0) return 0; /* Wrong dp? */
f = -1; /* Enter fractional part */
} else {
if (c < '0' || c > '9') break; /* End of decimal? */
c -= '0';
if (f == 0) { /* In integer part */
val = val * 10 + c;
} else { /* In fractional part */
val += i10x(f--) * c;
}
}
c = *(++(*str));
}
if (c > ' ') { /* It may be an exponent */
if (c != 'e' && c != 'E') return 0; /* Wrong character? */
c = *(++(*str));
if (c == '-') {
c = *(++(*str)); s |= 2; /* Negative exponent */
} else if (c == '+') {
c = *(++(*str)); /* Positive exponent */
}
if (c <= ' ') return 0; /* Wrong termination? */
e = 0;
while (c > ' ') { /* Get value of exponent */
c -= '0';
if (c > 9) return 0; /* Not a numeral? */
e = e * 10 + c;
c = *(++(*str));
}
val *= i10x((s & 2) ? -e : e); /* Apply exponent */
}
if (s & 1) val = -val; /* Negate sign if needed */
*res = val;
return 1;
}
#endif /* XF_USE_FP */
#endif /* XF_USE_INPUT */
Xprintf.h如下
/*------------------------------------------------------------------------*/
/* Universal string handler for user console interface (C)ChaN, 2021 */
/*------------------------------------------------------------------------*/
#ifndef XPRINTF_DEF
#define XPRINTF_DEF
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
#define XF_USE_OUTPUT 1 /* 1: Enable output functions */
#define XF_CRLF 1 /* 1: Convert \n ==> \r\n in the output char */
#define XF_USE_DUMP 1 /* 1: Enable put_dump function */
#define XF_USE_LLI 1 /* 1: Enable long long integer in size prefix ll */
#define XF_USE_FP 1 /* 1: Enable support for floating point in type e and f */
#define XF_DPC '.' /* Decimal separator for floating point */
#define XF_USE_INPUT 1 /* 1: Enable input functions */
#define XF_INPUT_ECHO 0 /* 1: Echo back input chars in xgets function */
#if defined(__GNUC__) && __GNUC__ >= 10
#pragma GCC diagnostic ignored "-Wcast-function-type"
#endif
#if XF_USE_OUTPUT
#define xdev_out(func) xfunc_output = (void(*)(int))(func)
extern void (*xfunc_output)(int);
void xputc (int chr);
void xfputc (void (*func)(int), int chr);
void xputs (const char* str);
void xfputs (void (*func)(int), const char* str);
void xprintf (const char* fmt, ...);
void xsprintf (char* buff, const char* fmt, ...);
void xfprintf (void (*func)(int), const char* fmt, ...);
void put_dump (const void* buff, unsigned long addr, int len, size_t width);
#endif
#if XF_USE_INPUT
#define xdev_in(func) xfunc_input = (int(*)(void))(func)
extern int (*xfunc_input)(void);
int xgets (char* buff, int len);
int xatoi (char** str, long* res);
int xatof (char** str, double* res);
#endif
#ifdef __cplusplus
}
#endif
#endif
blinky_thread_entry.c中实现接口
static void xprintf_out_port(int ch)
{
uint8_t val = ch;
uart_send(&val,1);
}
static int xprintf_in_port(void)
{
uint32_t len;
uint8_t val;
do
{
len = uart_read(&val,1);
}while(len == 0);
return val;
}
设置接口,blinky_thread_entry中初始化
xdev_out(xprintf_out_port);
xdev_in(xprintf_in_port);
测试代码如下
#include "xprintf.h"
/* Blinky Thread entry function */
void blinky_thread_entry (void * pvParameters)
{
uart_init();
xdev_out(xprintf_out_port);
xdev_in(xprintf_in_port);
while(1)
{
//static uint8_t rx_buffer[64];
//uint32_t rlen = uart_read(rx_buffer,sizeof(rx_buffer));
//if(rlen > 0)
//{
// uart_send(rx_buffer,rlen);
//}
xprintf("%d\n", 1234); /* "1234" */
xprintf("%6d,%3d%%\n", -200, 5); /* " -200, 5%" */
xprintf("%-6u\n", 100); /* "100 " */
xprintf("%ld\n", 12345678); /* "12345678" */
xprintf("%llu\n", 0x100000000); /* "4294967296" <XF_USE_LLI> */
xprintf("%lld\n", -1LL); /* "-1" <XF_USE_LLI> */
xprintf("%04x\n", 0xA3); /* "00a3" */
xprintf("%08lX\n", 0x123ABC); /* "00123ABC" */
xprintf("%016b\n", 0x550F); /* "0101010100001111" */
xprintf("%*d\n", 6, 100); /* " 100" */
xprintf("%s\n", "abcdefg"); /* "abcdefg" */
xprintf("%5s\n", "abc"); /* " abc" */
xprintf("%-5s\n", "abc"); /* "abc " */
xprintf("%.5s\n", "abcdefg"); /* "abcde" */
xprintf("%-5.2s\n", "abcdefg"); /* "ab " */
xprintf("%c\n", 'a'); /* "a" */
xprintf("%12f\n", 10.0); /* " 10.000000" <XF_USE_FP> */
xprintf("%.4E\n", 123.45678); /* "1.2346E+02" <XF_USE_FP> */
while(1)
{
char input_buffer[32];
char* str = input_buffer;
xprintf("please input two int\r\n");
xgets(input_buffer, sizeof(input_buffer));
long a;
xatoi(&str,&a);
long b;
xatoi(&str,&b);
xprintf("%d+%d=%d\r\n",a,b,a+b);
}
}
测试效果如下
打印正常,输入正常
-
发表了主题帖:
【瑞萨RA8D1开发板,基于M85内核的图形MCU】基于FIFO的串口收发接口
本帖最后由 qinyunti 于 2024-7-24 23:48 编辑
前面我们实现了串口的收发测试,现在来基于FIFO实现好用的串口收发接口。FIFO的实现参考微信公众号”嵌入式Lee”的文章
https://mp.weixin.qq.com/s/MvL9eDesyuxD60fnbl1nag 超级精简系列之十三:超级精简的循环FIFO,C实现
Fifo.c源码如下
#include <string.h>
#include "fifo.h"
#define FIFO_PARAM_CHECK 0
/**
* in????? 0~(buffer_len-1)?
* out????? 0~(buffer_len-1)?
* in == out?????,?????,????len??????????
* ???in??,?????out???
* ????out??,?????in???
* in??out??[out,in)????????
* in??out??[out,buffer_len)?[0,in)????????
***********************************************************
* 0 buffer_len-1 buffer_len
* (1)?? in?out??0
* | |
* in(0)
* out(0)
* len = 0
* (2)??n???? in??n?out??0 ??in??out???
* | |
* out(0)������������>in(n) |
* len = n
* (3)??m????(m<n) in??n?out??m ??in??out???
* | |
* out(m)����>in(n)
* len = n-m
* (4)??????,?????,??in??out???
* | |
* out(m)��������������������������������>
* ��>in(k)
* len = k + buffer_len-m
*/
uint32_t fifo_in(fifo_st* dev, uint8_t* buffer, uint32_t len)
{
uint32_t space = 0; /* ?????????? */
/* ???? */
#if FIFO_PARAM_CHECK
if((dev == 0) || (buffer == 0) || (len == 0))
{
return 0;
}
if(dev->buffer == 0)
{
return 0;
}
#endif
/* ??len??????buffer?? */
if(len > dev->buffer_len)
{
len = dev->buffer_len;
}
/* ????????
* ??dev->len?????dev->buffer_len
*/
if(dev->buffer_len >= dev->len)
{
space = dev->buffer_len - dev->len;
}
else
{
/* ???????, ?????? */
dev->len = 0;
space = dev->buffer_len;
}
/* ???????, ??len???????????????? */
len = (len >= space) ? space : len;
if(len == 0)
{
return 0; /* ??????????,???? */
}
/* ??len??????????,?????? */
space = dev->buffer_len - dev->in; /* ??????in???????????? */
if(space >= len)
{
/* ??????in??????????? */
memcpy(dev->buffer+dev->in,buffer,len);
}
else
{
/* ??????in???????,????????? */
memcpy(dev->buffer+dev->in,buffer,space); /* ???tail?? */
memcpy(dev->buffer,buffer+space,len-space); /* ???????? */
}
/* ????????????? */
dev->in += len;
if(dev->in >= dev->buffer_len)
{
dev->in -= dev->buffer_len; /* ????? ?? dev->in %= dev->buffer->len */
}
dev->len += len; /* dev->len??dev->buffer->len,??%= dev->buffer->len */
return len;
}
uint32_t fifo_out(fifo_st* dev, uint8_t* buffer, uint32_t len)
{
uint32_t space = 0;
/* ???? */
#if FIFO_PARAM_CHECK
if((dev == 0) || (buffer == 0) || (len == 0))
{
return 0;
}
if(dev->buffer == 0)
{
return 0;
}
#endif
/* ??????? */
if(dev->len == 0)
{
return 0;
}
/* ?????????????????? */
len = (dev->len) > len ? len : dev->len;
/* ??len??????????,?????? */
space = dev->buffer_len - dev->out; /* ??????out???????????? */
if(space >= len)
{
/* ??????out??????????? */
memcpy(buffer,dev->buffer+dev->out,len);
}
else
{
/* ??????out???????,????????? */
memcpy(buffer,dev->buffer+dev->out,space); /* ???tail?? */
memcpy(buffer+space,dev->buffer,len-space); /* ???????? */
}
/* ????????????? */
dev->out += len;
if(dev->out >= dev->buffer_len)
{
dev->out -= dev->buffer_len; /* ????? ?? dev->out %= dev->buffer->len */
}
dev->len -= len; /* ??dev->len ?????len,???? */
return len;
}
uint32_t fifo_getlen(fifo_st* dev)
{
#if FIFO_PARAM_CHECK
if(dev == 0)
{
return 0;
}
#endif
return dev->len;
}
void fifo_clean(fifo_st* dev)
{
#if FIFO_PARAM_CHECK
if(dev == 0)
{
return 0;
}
#endif
dev->len = 0;
dev->in = 0;
dev->out = 0;
}
Fifo.h源码如下
#ifndef FIFO_H
#define FIFO_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/**
* \struct fifo_st
* FIFO?????.
*/
typedef struct
{
uint32_t in; /**< ???? */
uint32_t out; /**< ???? */
uint32_t len; /**< ?????? */
uint32_t buffer_len; /**< ???? */
uint8_t* buffer; /**< ??,???? */
} fifo_st;
/**
* \fn fifo_in
* ?fifo????
* \param[in] dev \ref fifo_st
* \param[in] buffer ??????
* \param[in] len ??????
* \retval ??????????
*/
uint32_t fifo_in(fifo_st* dev, uint8_t* buffer, uint32_t len);
/**
* \fn fifo_out
* ?fifo????
* \param[in] dev \ref fifo_st
* \param[in] buffer ??????
* \param[in] len ?????????
* \retval ??????????
*/
uint32_t fifo_out(fifo_st* dev, uint8_t* buffer, uint32_t len);
uint32_t fifo_getlen(fifo_st* dev);
void fifo_clean(fifo_st* dev);
#ifdef __cplusplus
}
#endif
#endif
Uart.c中定义fifo实例
static uint8_t s_uart_rx_buffer[64];
static fifo_st s_uart_fifo_dev=
{
.in = 0,
.len = 0,
.out = 0,
.buffer = s_uart_rx_buffer,
.buffer_len = sizeof(s_uart_rx_buffer),
};
串口接收中断中,将数据写入fifo
void user_uart3_callback(uart_callback_args_t *p_args);
void user_uart3_callback(uart_callback_args_t *p_args)
{
uint8_t tmp;
switch (p_args->event)
{
case UART_EVENT_TX_COMPLETE:
g_data_transmit_flag = true;
break;
case UART_EVENT_TX_DATA_EMPTY:
g_data_transmit_flag = true;
break;
case UART_EVENT_RX_COMPLETE:
// Start Transmission
fifo_in(&s_uart_fifo_dev, rx_buffer, 1);
R_SCI_B_UART_Read(&g_uart3_ctrl, (uint8_t * const)(rx_buffer), 1U);
//uart_send(rx_buffer,1);
break;
case UART_EVENT_RX_CHAR:
tmp = g_uart3_ctrl.p_reg->RDR_BY;
fifo_in(&s_uart_fifo_dev, &tmp, 1);
//uart_send(&tmp,1);
break;
default:
break;
}
}
临界段接口,中断中操作fifo无需临界段保护,uart_read再线程中调用,需要临界段保护。
#define CriticalAlloc()
#define EnterCritical() __disable_irq()
#define ExitCritical() __enable_irq()
串口读接口,从fifo中读数据
uint32_t uart_read(uint8_t* buffer, uint32_t len)
{
uint32_t rlen;
CriticalAlloc();
EnterCritical();
rlen = fifo_out(&s_uart_fifo_dev, buffer, len);
ExitCritical();
return rlen;
}
最终的uart.c如下
#include "hal_data.h"
#include <stdio.h>
#include <stdbool.h>
#include "r_uart_api.h"
#include "r_sci_b_uart.h"
#include "uart.h"
#include "blinky_thread.h"
#include "fifo.h"
#define CriticalAlloc()
#define EnterCritical() __disable_irq()
#define ExitCritical() __enable_irq()
static uint8_t s_uart_rx_buffer[64];
static fifo_st s_uart_fifo_dev=
{
.in = 0,
.len = 0,
.out = 0,
.buffer = s_uart_rx_buffer,
.buffer_len = sizeof(s_uart_rx_buffer),
};
volatile bool g_data_transmit_flag = false;
uint8_t rx_buffer[1];
void user_uart3_callback(uart_callback_args_t *p_args);
void user_uart3_callback(uart_callback_args_t *p_args)
{
uint8_t tmp;
switch (p_args->event)
{
case UART_EVENT_TX_COMPLETE:
g_data_transmit_flag = true;
break;
case UART_EVENT_TX_DATA_EMPTY:
g_data_transmit_flag = true;
break;
case UART_EVENT_RX_COMPLETE:
// Start Transmission
fifo_in(&s_uart_fifo_dev, rx_buffer, 1);
R_SCI_B_UART_Read(&g_uart3_ctrl, (uint8_t * const)(rx_buffer), 1U);
//uart_send(rx_buffer,1);
break;
case UART_EVENT_RX_CHAR:
tmp = g_uart3_ctrl.p_reg->RDR_BY;
fifo_in(&s_uart_fifo_dev, &tmp, 1);
//uart_send(&tmp,1);
break;
default:
break;
}
}
int uart_init(void)
{
fsp_err_t err;
err = R_SCI_B_UART_Open(&g_uart3_ctrl, &g_uart3_cfg);
if (FSP_SUCCESS != err)
{
return -1;
}
else
{
// Start Transmission
err = R_SCI_B_UART_Read(&g_uart3_ctrl, (uint8_t * const)(rx_buffer), 1U);
if (FSP_SUCCESS != err)
{
return -1;
}
return 0;
}
}
uint32_t uart_send(uint8_t* buffer, uint32_t len)
{
g_data_transmit_flag = false;
for(uint32_t i=0;i<len;i++)
{
g_uart3_ctrl.p_reg->TDR_BY = buffer;
while((g_uart3_ctrl.p_reg->CSR_b.TEND == 0) || (g_uart3_ctrl.p_reg->CSR_b.TDRE == 0));
}
//fsp_err_t err = R_SCI_B_UART_Write(&g_uart3_ctrl, (uint8_t * const)(buffer), len);
//if (FSP_SUCCESS != err)
//{
// return 0;
//}
// Wait for event receive complete
//while (!g_data_transmit_flag)
//{
//}
return len;
}
uint32_t uart_read(uint8_t* buffer, uint32_t len)
{
uint32_t rlen;
CriticalAlloc();
EnterCritical();
rlen = fifo_out(&s_uart_fifo_dev, buffer, len);
ExitCritical();
return rlen;
}
Uart.h如下
#ifndef UART_H
#define UART_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
int uart_init(void);
uint32_t uart_send(uint8_t* buffer, uint32_t len);
uint32_t uart_read(uint8_t* buffer, uint32_t len);
#ifdef __cplusplus
}
#endif
#endif
测试
blinky_thread_entry.c中
#include "uart.h"
void blinky_thread_entry (void * pvParameters)
{
uart_init();
while(1)
{
static uint8_t rx_buffer[64];
uint32_t rlen = uart_read(rx_buffer,sizeof(rx_buffer));
if(rlen > 0)
{
uart_send(rx_buffer,rlen);
}
}
发送任意数据原样返回
以上实现了方便好用的串口收发接口,基于fifo接口简单非常方便。
-
发表了主题帖:
【瑞萨RA8D1开发板,基于M85内核的图形MCU】串口收发测试
本帖最后由 qinyunti 于 2024-7-24 23:48 编辑
前言
本篇来实现串口的收发测试,后面再基于此基于FIFO的串口接口,然后实现shell等,为后面的开发调试准备环境。
引脚
板上使用P408和P409接到板载Jlink的DBG_TXD和DBG_RXD, 可以使用板载Jlink的虚拟串口进行通讯。
配置
配置P408和P409对应SCI3
添加串口驱动
设置实例位SCI3以及波特率等参数
设置中断回调函数,用户实现user_uart3_callback
更新
串口测试
添加uart.h/uart.c实现如下
Uart.h
#ifndef UART_H
#define UART_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
int uart_init(void);
uint32_t uart_send(uint8_t* buffer, uint32_t len);
#ifdef __cplusplus
}
#endif
#endif
Uart.c
#include "hal_data.h"
#include <stdio.h>
#include <stdbool.h>
#include "r_uart_api.h"
#include "r_sci_b_uart.h"
#include "uart.h"
#include "blinky_thread.h"
volatile bool g_data_transmit_flag = false;
uint8_t rx_buffer[1];
void user_uart3_callback(uart_callback_args_t *p_args);
void user_uart3_callback(uart_callback_args_t *p_args)
{
uint8_t tmp;
switch (p_args->event)
{
case UART_EVENT_TX_COMPLETE:
g_data_transmit_flag = true;
break;
case UART_EVENT_TX_DATA_EMPTY:
g_data_transmit_flag = true;
break;
case UART_EVENT_RX_COMPLETE:
// Start Transmission
R_SCI_B_UART_Read(&g_uart3_ctrl, (uint8_t * const)(rx_buffer), 1U);
uart_send(rx_buffer,1);
break;
case UART_EVENT_RX_CHAR:
tmp = g_uart3_ctrl.p_reg->RDR_BY;
uart_send(&tmp,1);
break;
default:
break;
}
}
int uart_init(void)
{
fsp_err_t err;
err = R_SCI_B_UART_Open(&g_uart3_ctrl, &g_uart3_cfg);
if (FSP_SUCCESS != err)
{
return -1;
}
else
{
// Start Transmission
err = R_SCI_B_UART_Read(&g_uart3_ctrl, (uint8_t * const)(rx_buffer), 1U);
if (FSP_SUCCESS != err)
{
return -1;
}
return 0;
}
}
uint32_t uart_send(uint8_t* buffer, uint32_t len)
{
g_data_transmit_flag = false;
for(uint32_t i=0;i<len;i++)
{
g_uart3_ctrl.p_reg->TDR_BY = buffer[i];
while((g_uart3_ctrl.p_reg->CSR_b.TEND == 0) || (g_uart3_ctrl.p_reg->CSR_b.TDRE == 0));
}
//fsp_err_t err = R_SCI_B_UART_Write(&g_uart3_ctrl, (uint8_t * const)(buffer), len);
//if (FSP_SUCCESS != err)
//{
// return 0;
//}
// Wait for event receive complete
//while (!g_data_transmit_flag)
//{
//}
return len;
}
实现收到数据原样返回
blinky_thread_entry.c中
#include "uart.h"
void blinky_thread_entry (void * pvParameters)
{
uart_init();
while(1);
测试如下,收到后原样返回。
注:发送进不了中断,接收可以,所以暂时发送改为查询方式,后面再查找原因。
- 2024-07-21
-
发表了主题帖:
【瑞萨RA8D1开发板,基于M85内核的图形MCU】USB开发环境搭建以CDC为例
前言
本片分享USB开发环境搭建,以CDC为例。
创建工程
打开e2studio
菜单栏点击
文件->新建->瑞萨C/C++项目->Renesas RA
选择C/C++ -> Renesas RA C/C++ Project下一步
指定工程名字,下一步
指定board,芯片,工具链,下一步
指定开发模式flat,下一步
指定生成可执行项目,选择freertos,下一步
指定led模板,完成
配置
双击xml配置文件
添加heap
按照如下选择stacks->点击Thread->New Stack->RTOS->FreeRTOS Heap4
此时提示有错误,使用heap需要将线程创建改为动态方式
如下配置,点击Thread->属性->设置相关参数
设置Total Heap Size
设置Support Dynamic Allocation使能
设置USB
配置引脚
配置FS引脚P814和P815
HD的VBUS PB01
Stacks-.Thread->New Stack->Connectivity->USB PCDC
添加USB CDC驱动
设置其属性
按照如下设置PCDC的属性 实例民鼻子g_pcdc,
Bulk in bulk out interrupt的pipe为1 2 6
配置USB时钟使用24MHz,这里很重要,默认的20M不能工作。
使能DMA,使用HS的地址。
设置以下属性实例名字 g_basic
使用IP1高速
设置描述符
设置cdc回调函数
DMA配置
添加2个传输
设置传输0的属性
设置传输1的属性
配置信号量等对象
创建信号量属性如下
再创建三个消息队列
属性分别如下
更新配置
先保存,再更新配置
添加描述符
添加文件r_usb_pcdc_descriptor.c到src目录下
r_usb_pcdc_descriptor.c文件内容如下
/*
* Copyright (c) 2020 - 2024 Renesas Electronics Corporation and/or its affiliates
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/******************************************************************************
Includes <System Includes> , "Project Includes"
******************************************************************************/
#include "r_usb_basic.h"
#include "r_usb_basic_api.h"
#include "r_usb_basic_cfg.h"
/******************************************************************************
Macro definitions
******************************************************************************/
/* bcdUSB */
#define USB_BCDNUM (0x0200U)
/* Release Number */
#define USB_RELEASE (0x0200U)
/* DCP max packet size */
#define USB_DCPMAXP (64U)
/* Configuration number */
#define USB_CONFIGNUM (1U)
/* Vendor ID */
#define USB_VENDORID (0x0000U)
/* Product ID */
#define USB_PRODUCTID (0x0002U)
/* Class-Specific Configuration Descriptors */
#define USB_PCDC_CS_INTERFACE (0x24U)
/* bDescriptor SubType in Communications Class Functional Descriptors */
/* Header Functional Descriptor */
#define USB_PCDC_DT_SUBTYPE_HEADER_FUNC (0x00U)
/* Call Management Functional Descriptor. */
#define USB_PCDC_DT_SUBTYPE_CALL_MANAGE_FUNC (0x01U)
/* Abstract Control Management Functional Descriptor. */
#define USB_PCDC_DT_SUBTYPE_ABSTRACT_CTR_MANAGE_FUNC (0x02U)
/* Union Functional Descriptor */
#define USB_PCDC_DT_SUBTYPE_UNION_FUNC (0x06U)
/* Communications Class Subclass Codes */
#define USB_PCDC_CLASS_SUBCLASS_CODE_ABS_CTR_MDL (0x02U)
/* USB Class Definitions for Communications Devices Specification
release number in binary-coded decimal. */
#define USB_PCDC_BCD_CDC (0x0110U)
/* Descriptor length */
#define USB_PCDC_QD_LEN (10U)
#define USB_PCDC_CD1_LEN (67U)
#define STRING_DESCRIPTOR0_LEN (4U)
#define STRING_DESCRIPTOR1_LEN (16U)
#define STRING_DESCRIPTOR2_LEN (44U)
#define STRING_DESCRIPTOR3_LEN (46U)
#define STRING_DESCRIPTOR4_LEN (22U)
#define STRING_DESCRIPTOR5_LEN (18U)
#define STRING_DESCRIPTOR6_LEN (28U)
#define NUM_STRING_DESCRIPTOR (7U)
/* Descriptor data Mask */
#define USB_UCHAR_MAX (0xffU)
#define USB_W_TOTAL_LENGTH_MASK (256U)
#define USB_W_MAX_PACKET_SIZE_MASK (64U)
#define USB_PCDC_BCD_CDC_MASK (256U)
/******************************************************************************
Private global variables and functions
******************************************************************************/
/******************************************************************************
Exported global variables
******************************************************************************/
/******************************************************************************
Exported global functions (to be accessed by other files)
******************************************************************************/
/* Standard Device Descriptor */
uint8_t g_apl_device[USB_DD_BLENGTH + ( USB_DD_BLENGTH % 2)] =
{
USB_DD_BLENGTH, /* 0:bLength */
USB_DT_DEVICE, /* 1:bDescriptorType */
(USB_BCDNUM & (uint8_t) USB_UCHAR_MAX), /* 2:bcdUSB_lo */
((uint8_t) (USB_BCDNUM >> 8) & (uint8_t) USB_UCHAR_MAX), /* 3:bcdUSB_hi */
USB_IFCLS_CDCC, /* 4:bDeviceClass */
0, /* 5:bDeviceSubClass */
0, /* 6:bDeviceProtocol */
(uint8_t) USB_DCPMAXP, /* 7:bMAXPacketSize(for DCP) */
(USB_VENDORID & (uint8_t) USB_UCHAR_MAX), /* 8:idVendor_lo */
((uint8_t) (USB_VENDORID >> 8) & (uint8_t) USB_UCHAR_MAX), /* 9:idVendor_hi */
((uint16_t) USB_PRODUCTID & (uint8_t) USB_UCHAR_MAX), /* 10:idProduct_lo */
((uint8_t) (USB_PRODUCTID >> 8) & (uint8_t) USB_UCHAR_MAX), /* 11:idProduct_hi */
(USB_RELEASE & (uint8_t) USB_UCHAR_MAX), /* 12:bcdDevice_lo */
((uint8_t) (USB_RELEASE >> 8) & (uint8_t) USB_UCHAR_MAX), /* 13:bcdDevice_hi */
1, /* 14:iManufacturer */
2, /* 15:iProduct */
6, /* 16:iSerialNumber */
USB_CONFIGNUM /* 17:bNumConfigurations */
};
/************************************************************
* Device Qualifier Descriptor *
************************************************************/
uint8_t g_apl_qualifier_descriptor[USB_PCDC_QD_LEN + ( USB_PCDC_QD_LEN % 2)] =
{
USB_PCDC_QD_LEN, /* 0:bLength */
USB_DT_DEVICE_QUALIFIER, /* 1:bDescriptorType */
(USB_BCDNUM & (uint8_t) USB_UCHAR_MAX), /* 2:bcdUSB_lo */
((uint8_t) (USB_BCDNUM >> 8) & (uint8_t) USB_UCHAR_MAX), /* 3:bcdUSB_hi */
0, /* 4:bDeviceClass */
0, /* 5:bDeviceSubClass */
0, /* 6:bDeviceProtocol */
(uint8_t) USB_DCPMAXP, /* 7:bMAXPacketSize(for DCP) */
USB_CONFIGNUM, /* 8:bNumConfigurations */
0 /* 9:bReserved */
};
/************************************************************
* Configuration Or Other_Speed_Configuration Descriptor *
************************************************************/
/* For Full-Speed */
uint8_t g_apl_configuration[USB_PCDC_CD1_LEN + ( USB_PCDC_CD1_LEN % 2)] =
{
USB_CD_BLENGTH, /* 0:bLength */
USB_SOFT_CHANGE, /* 1:bDescriptorType */
USB_PCDC_CD1_LEN % USB_W_TOTAL_LENGTH_MASK, /* 2:wTotalLength(L) */
USB_PCDC_CD1_LEN / USB_W_TOTAL_LENGTH_MASK, /* 3:wTotalLength(H) */
2, /* 4:bNumInterfaces */
1, /* 5:bConfigurationValue */
0, /* 6:iConfiguration */
USB_CF_RESERVED | USB_CF_SELFP, /* 7:bmAttributes */
(10 / 2), /* 8:MAXPower (2mA unit) */
/* Interface Descriptor */
USB_ID_BLENGTH, /* 0:bLength */
USB_DT_INTERFACE, /* 1:bDescriptor */
0, /* 2:bInterfaceNumber */
0, /* 3:bAlternateSetting */
1, /* 4:bNumEndpoints */
USB_IFCLS_CDCC, /* 5:bInterfaceClass */
USB_PCDC_CLASS_SUBCLASS_CODE_ABS_CTR_MDL, /* 6:bInterfaceSubClass */
1, /* 7:bInterfaceProtocol */
0, /* 8:iInterface */
/* Communications Class Functional Descriptorss */
5, /* 0:bLength */
USB_PCDC_CS_INTERFACE, /* 1:bDescriptorType */
USB_PCDC_DT_SUBTYPE_HEADER_FUNC, /* 2:bDescriptorSubtype */
USB_PCDC_BCD_CDC % USB_W_TOTAL_LENGTH_MASK, /* 3:bcdCDC_lo */
USB_PCDC_BCD_CDC / USB_W_TOTAL_LENGTH_MASK, /* 4:bcdCDC_hi */
/* Communications Class Functional Descriptorss */
4, /* 0:bLength */
USB_PCDC_CS_INTERFACE, /* 1:bDescriptorType */
USB_PCDC_DT_SUBTYPE_ABSTRACT_CTR_MANAGE_FUNC, /* 2:bDescriptorSubtype */
2, /* 3:bmCapabilities */
/* Communications Class Functional Descriptorss */
5, /* 0:bLength */
USB_PCDC_CS_INTERFACE, /* 1:bDescriptorType */
USB_PCDC_DT_SUBTYPE_UNION_FUNC, /* 2:bDescriptorSubtype */
0, /* 3:bMasterInterface */
1, /* 4:bSlaveInterface0 */
/* Communications Class Functional Descriptorss */
5, /* 0:bLength */
USB_PCDC_CS_INTERFACE, /* 1:bDescriptorType */
USB_PCDC_DT_SUBTYPE_CALL_MANAGE_FUNC, /* 2:bDescriptorSubtype */
/* D1:1-Device can send/receive call management
information over a Data Class interface. */
/* D0:1-Device handles call management itself. */
3, /* 3:bmCapabilities */
1, /* 4:bDataInterface */
/* Endpoint Descriptor 0 */
7, /* 0:bLength */
USB_DT_ENDPOINT, /* 1:bDescriptorType */
USB_EP_IN | USB_EP3, /* 2:bEndpointAddress */
USB_EP_INT, /* 3:bmAttribute */
16, /* 4:wMAXPacketSize_lo */
0, /* 5:wMAXPacketSize_hi */
0x10, /* 6:bInterval */
/* Interface Descriptor */
USB_ID_BLENGTH, /* 0:bLength */
USB_DT_INTERFACE, /* 1:bDescriptor */
1, /* 2:bInterfaceNumber */
0, /* 3:bAlternateSetting */
2, /* 4:bNumEndpoints */
USB_IFCLS_CDCD, /* 5:bInterfaceClass */
0, /* 6:bInterfaceSubClass */
0, /* 7:bInterfaceProtocol */
0, /* 8:iInterface */
/* Endpoint Descriptor 0 */
USB_ED_BLENGTH, /* 0:bLength */
USB_DT_ENDPOINT, /* 1:bDescriptorType */
USB_EP_IN | USB_EP1, /* 2:bEndpointAddress */
USB_EP_BULK, /* 3:bmAttribute */
USB_W_MAX_PACKET_SIZE_MASK, /* 4:wMAXPacketSize_lo */
0, /* 5:wMAXPacketSize_hi */
0, /* 6:bInterval */
/* Endpoint Descriptor 1 */
USB_ED_BLENGTH, /* 0:bLength */
USB_DT_ENDPOINT, /* 1:bDescriptorType */
USB_EP_OUT | USB_EP2, /* 2:bEndpointAddress */
USB_EP_BULK, /* 3:bmAttribute */
USB_W_MAX_PACKET_SIZE_MASK, /* 4:wMAXPacketSize_lo */
0, /* 5:wMAXPacketSize_hi */
0, /* 6:bInterval */
};
/* For High-Speed */
uint8_t g_apl_hs_configuration[USB_PCDC_CD1_LEN + ( USB_PCDC_CD1_LEN % 2)] =
{
9, /* 0:bLength */
USB_SOFT_CHANGE, /* 1:bDescriptorType */
USB_PCDC_CD1_LEN % USB_W_TOTAL_LENGTH_MASK, /* 2:wTotalLength(L) */
USB_PCDC_CD1_LEN / USB_W_TOTAL_LENGTH_MASK, /* 3:wTotalLength(H) */
2, /* 4:bNumInterfaces */
1, /* 5:bConfigurationValue */
0, /* 6:iConfiguration */
USB_CF_RESERVED | USB_CF_SELFP, /* 7:bmAttributes */
(10 / 2), /* 8:MAXPower (2mA unit) */
/* Interface Descriptor */
9, /* 0:bLength */
USB_DT_INTERFACE, /* 1:bDescriptor */
0, /* 2:bInterfaceNumber */
0, /* 3:bAlternateSetting */
1, /* 4:bNumEndpoints */
USB_IFCLS_CDCC, /* 5:bInterfaceClass */
USB_PCDC_CLASS_SUBCLASS_CODE_ABS_CTR_MDL, /* 6:bInterfaceSubClass */
1, /* 7:bInterfaceProtocol */
0, /* 8:iInterface */
/* Communications Class Functional Descriptorss */
5, /* 0:bLength */
USB_PCDC_CS_INTERFACE, /* 1:bDescriptorType */
USB_PCDC_DT_SUBTYPE_HEADER_FUNC, /* 2:bDescriptorSubtype */
USB_PCDC_BCD_CDC % USB_PCDC_BCD_CDC_MASK, /* 3:bcdCDC_lo */
USB_PCDC_BCD_CDC / USB_PCDC_BCD_CDC_MASK, /* 4:bcdCDC_hi */
/* Communications Class Functional Descriptorss */
4, /* 0:bLength */
USB_PCDC_CS_INTERFACE, /* 1:bDescriptorType */
USB_PCDC_DT_SUBTYPE_ABSTRACT_CTR_MANAGE_FUNC, /* 2:bDescriptorSubtype */
2, /* 3:bmCapabilities */
/* Communications Class Functional Descriptorss */
5, /* 0:bLength */
USB_PCDC_CS_INTERFACE, /* 1:bDescriptorType */
USB_PCDC_DT_SUBTYPE_UNION_FUNC, /* 2:bDescriptorSubtype */
0, /* 3:bMasterInterface */
1, /* 4:bSlaveInterface0 */
/* Communications Class Functional Descriptorss */
5, /* 0:bLength */
USB_PCDC_CS_INTERFACE, /* 1:bDescriptorType */
USB_PCDC_DT_SUBTYPE_CALL_MANAGE_FUNC, /* 2:bDescriptorSubtype */
/* D1:1-Device can send/receive call management
information over a Data Class interface. */
/* D0:1-Device handles call management itself. */
3, /* 3:bmCapabilities */
1, /* 4:bDataInterface */
/* Endpoint Descriptor 0 */
7, /* 0:bLength */
USB_DT_ENDPOINT, /* 1:bDescriptorType */
USB_EP_IN | USB_EP3, /* 2:bEndpointAddress */
USB_EP_INT, /* 3:bmAttribute */
16, /* 4:wMAXPacketSize_lo */
0, /* 5:wMAXPacketSize_hi */
0x10, /* 6:bInterval */
/* Interface Descriptor */
9, /* 0:bLength */
USB_DT_INTERFACE, /* 1:bDescriptor */
1, /* 2:bInterfaceNumber */
0, /* 3:bAlternateSetting */
2, /* 4:bNumEndpoints */
USB_IFCLS_CDCD, /* 5:bInterfaceClass */
0, /* 6:bInterfaceSubClass */
0, /* 7:bInterfaceProtocol */
0, /* 8:iInterface */
/* Endpoint Descriptor 0 */
7, /* 0:bLength */
USB_DT_ENDPOINT, /* 1:bDescriptorType */
USB_EP_IN | USB_EP1, /* 2:bEndpointAddress */
USB_EP_BULK, /* 3:bmAttribute */
0, /* 4:wMAXPacketSize_lo */
2, /* 5:wMAXPacketSize_hi */
0, /* 6:bInterval */
/* Endpoint Descriptor 1 */
7, /* 0:bLength */
USB_DT_ENDPOINT, /* 1:bDescriptorType */
USB_EP_OUT | USB_EP2, /* 2:bEndpointAddress */
USB_EP_BULK, /* 3:bmAttribute */
0, /* 4:wMAXPacketSize_lo */
2, /* 5:wMAXPacketSize_hi */
0, /* 6:bInterval */
};
/*************************************
* String Descriptor *
*************************************/
/* UNICODE 0x0409 English (United States) */
uint8_t g_cdc_string_descriptor0[STRING_DESCRIPTOR0_LEN + ( STRING_DESCRIPTOR0_LEN % 2)] =
{
STRING_DESCRIPTOR0_LEN, /* 0:bLength */
USB_DT_STRING, /* 1:bDescriptorType */
0x09, 0x04 /* 2:wLANGID[0] */
};
/* iManufacturer */
uint8_t g_cdc_string_descriptor1[STRING_DESCRIPTOR1_LEN + ( STRING_DESCRIPTOR1_LEN % 2)] =
{
STRING_DESCRIPTOR1_LEN, /* 0:bLength */
USB_DT_STRING, /* 1:bDescriptorType */
'R', 0x00, /* 2:wLANGID[0] */
'E', 0x00,
'N', 0x00,
'E', 0x00,
'S', 0x00,
'A', 0x00,
'S', 0x00,
};
/* iProduct */
uint8_t g_cdc_string_descriptor2[STRING_DESCRIPTOR2_LEN + ( STRING_DESCRIPTOR2_LEN % 2)] =
{
STRING_DESCRIPTOR2_LEN, /* 0:bLength */
USB_DT_STRING, /* 1:bDescriptorType */
'C', 0x00,
'D', 0x00,
'C', 0x00,
' ', 0x00,
'U', 0x00,
'S', 0x00,
'B', 0x00,
' ', 0x00,
'D', 0x00,
'e', 0x00,
'm', 0x00,
'o', 0x00,
'n', 0x00,
's', 0x00,
't', 0x00,
'r', 0x00,
'a', 0x00,
't', 0x00,
'i', 0x00,
'o', 0x00,
'n', 0x00,
};
/* iInterface */
uint8_t g_cdc_string_descriptor3[STRING_DESCRIPTOR3_LEN + ( STRING_DESCRIPTOR3_LEN % 2)] =
{
STRING_DESCRIPTOR3_LEN, /* 0:bLength */
USB_DT_STRING, /* 1:bDescriptorType */
'C', 0x00,
'o', 0x00,
'm', 0x00,
'm', 0x00,
'u', 0x00,
'n', 0x00,
'i', 0x00,
'c', 0x00,
'a', 0x00,
't', 0x00,
'i', 0x00,
'o', 0x00,
'n', 0x00,
's', 0x00,
' ', 0x00,
'D', 0x00,
'e', 0x00,
'v', 0x00,
'i', 0x00,
'c', 0x00,
'e', 0x00,
's', 0x00
};
/* iConfiguration */
uint8_t g_cdc_string_descriptor4[STRING_DESCRIPTOR4_LEN + ( STRING_DESCRIPTOR4_LEN % 2)] =
{
STRING_DESCRIPTOR4_LEN, /* 0:bLength */
USB_DT_STRING, /* 1:bDescriptorType */
'F', 0x00, /* 2:wLANGID[0] */
'u', 0x00,
'l', 0x00,
'l', 0x00,
'-', 0x00,
'S', 0x00,
'p', 0x00,
'e', 0x00,
'e', 0x00,
'd', 0x00
};
/* iConfiguration */
uint8_t g_cdc_string_descriptor5[STRING_DESCRIPTOR5_LEN + ( STRING_DESCRIPTOR5_LEN % 2)] =
{
STRING_DESCRIPTOR5_LEN, /* 0:bLength */
USB_DT_STRING, /* 1:bDescriptorType */
'H', 0x00, /* 2:wLANGID[0] */
'i', 0x00,
'-', 0x00,
'S', 0x00,
'p', 0x00,
'e', 0x00,
'e', 0x00,
'd', 0x00
};
/* iSerialNumber */
uint8_t g_cdc_string_descriptor6[STRING_DESCRIPTOR6_LEN + ( STRING_DESCRIPTOR6_LEN % 2)] =
{
STRING_DESCRIPTOR6_LEN, /* 0:bLength */
USB_DT_STRING, /* 1:bDescriptorType */
'0', 0x00, /* 2:wLANGID[0] */
'0', 0x00,
'0', 0x00,
'0', 0x00,
'0', 0x00,
'0', 0x00,
'0', 0x00,
'0', 0x00,
'0', 0x00,
'0', 0x00,
'0', 0x00,
'0', 0x00,
'1', 0x00,
};
uint8_t *gp_apl_string_table[] =
{
g_cdc_string_descriptor0,
g_cdc_string_descriptor1,
g_cdc_string_descriptor2,
g_cdc_string_descriptor3,
g_cdc_string_descriptor4,
g_cdc_string_descriptor5,
g_cdc_string_descriptor6
};
const usb_descriptor_t g_usb_descriptor =
{
g_apl_device, /* Pointer to the device descriptor */
g_apl_configuration, /* Pointer to the configuration descriptor for Full-speed */
g_apl_hs_configuration, /* Pointer to the configuration descriptor for Hi-speed */
g_apl_qualifier_descriptor, /* Pointer to the qualifier descriptor */
gp_apl_string_table, /* Pointer to the string descriptor table */
NUM_STRING_DESCRIPTOR
};
/******************************************************************************
Renesas Abstracted Peripheral Communications Devices Class Driver API functions
******************************************************************************/
/******************************************************************************
End Of File
******************************************************************************/
CDC操作
blinky_thread_entry.c中实现
usb_pcdc_callback
任务循环中
打开USB
< class="p" style="">/* Open USB instance */
< class="p" style="">{
< class="p" style="">err = R_USB_Open (&g_basic_ctrl, &g_basic_cfg);
< class="p" style="">if (FSP_SUCCESS != err)
< class="p" style="">{
< class="p" style="">//APP_ERR_PRINT("\r\nR_USB_Open failed.\r\n");
< class="p" style="">//APP_ERR_TRAP(err);
< class="p" style="">}
< class="p" style="">//APP_PRINT("\r\nUSB Opened successfully.\n\r");
< class="p" style="">}
然后不断处理队列消息
< class="p" style="">/* Check if USB event is received */
< class="p" style="">err_queue = xQueueReceive(g_event_queue, (void * const)&q_instance, (portMAX_DELAY));
< class="p" style="">if(pdTRUE != err_queue)
< class="p" style="">{
< class="p" style="">//APP_ERR_PRINT("\r\nNo USB Event received. Please check USB connection \r\n");
< class="p" style="">}
完整的代码如下
blinky_thread_entry.c
/*
* Copyright (c) 2020 - 2024 Renesas Electronics Corporation and/or its affiliates
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "blinky_thread.h"
typedef struct
{
uint32_t peripheral;
union
{
uint32_t data_size;
}u;
}queue_evt_t;
typedef enum
{
PERIPHERAL_NONE = 0,
PERIPHERAL_USB,
PERIPHERAL_UART,
}peripheral_t;
#define RESET_VALUE (0x00)
#define DATA_LEN (512U) // Data Length
#define LINE_CODING_LENGTH (0x07U) // Line coding length
/* Variable to capture USB event. */
volatile bool g_tx_complete = true;
volatile usb_event_info_t g_usb_pcdc_event;
/* Flag to indicate USB resume/suspend status */
static bool b_usb_attach = false;
/* Variable to store UART settings */
volatile usb_pcdc_linecoding_t g_line_coding;
usb_pcdc_ctrllinestate_t g_control_line_state =
{
.bdtr = 0,
.brts = 0,
};
/* Error status flag */
static volatile bool g_err_flag = false;
/* Variable to store baud rate */
uint32_t g_baud_rate = RESET_VALUE ;
/* Buffer to store user data */
uint8_t g_user_data_buf[DATA_LEN] = {RESET_VALUE};
/* Variable to store size of data received from tera term */
volatile uint32_t g_terminal_data_size = RESET_VALUE ;
uint8_t g_usb_tx_buffer[512]="hello";
extern bsp_leds_t g_bsp_leds;
/*******************************************************************************************************************//**
* [url=home.php?mod=space&uid=159083]@brief[/url] Deinitialize initialized USB instance
* @param[in] None
* @retval None
**********************************************************************************************************************/
static void deinit_usb(void)
{
fsp_err_t err = FSP_SUCCESS;
/* Close module */
err = R_USB_Close (&g_basic_ctrl);
if (FSP_SUCCESS != err)
{
//APP_ERR_PRINT ("\r\n** USB close API failed ** \r\n");
}
}
/* Blinky Thread entry function */
void blinky_thread_entry (void * pvParameters)
{
FSP_PARAMETER_NOT_USED(pvParameters);
fsp_err_t err = FSP_SUCCESS;
BaseType_t err_queue = pdFALSE;
queue_evt_t q_instance;
/* LED type structure */
bsp_leds_t leds = g_bsp_leds;
/* If this board has no LEDs then trap here */
if (0 == leds.led_count)
{
while (1)
{
; // There are no LEDs on this board
}
}
/* Holds level to set for pins */
//bsp_io_level_t pin_level = BSP_IO_LEVEL_LOW;
/* Open USB instance */
{
err = R_USB_Open (&g_basic_ctrl, &g_basic_cfg);
if (FSP_SUCCESS != err)
{
//APP_ERR_PRINT("\r\nR_USB_Open failed.\r\n");
//APP_ERR_TRAP(err);
}
//APP_PRINT("\r\nUSB Opened successfully.\n\r");
}
xSemaphoreGive(g_usb_tx_semaphore);
while (1)
{
/* Check if USB event is received */
err_queue = xQueueReceive(g_event_queue, (void * const)&q_instance, (portMAX_DELAY));
if(pdTRUE != err_queue)
{
//APP_ERR_PRINT("\r\nNo USB Event received. Please check USB connection \r\n");
}
/* Check for usb event */
if (PERIPHERAL_USB == q_instance.peripheral)
{
/* Send received data out to the UART */
if ((true == b_usb_attach))
{
if(0U < q_instance.u.data_size)
{
/* Wait for previous USB transfer to complete */
BaseType_t err_semaphore = xSemaphoreTake (g_usb_tx_semaphore, portMAX_DELAY);
if (pdTRUE == err_semaphore)
{
/* Write data to host machine */
err = R_USB_Write (&g_basic_ctrl, &g_usb_tx_buffer[0], sizeof(g_usb_tx_buffer), USB_CLASS_PCDC);
if (FSP_SUCCESS != err)
{
//APP_ERR_PRINT("\r\nR_USB_Write API failed.\r\n");
deinit_usb();
//deinit_uart();
//APP_ERR_TRAP(err);
}
}
#if 0
/* Wait till previously queued data is out completely */
{
BaseType_t err_semaphore = xSemaphoreTake( g_uart_tx_mutex, portMAX_DELAY );
if(pdTRUE != err_semaphore)
{
APP_ERR_PRINT("\r\nxSemaphoreTake on g_uart_tx_mutex Failed \r\n");
APP_ERR_TRAP(err_semaphore);
}
}
/* Write data to UART Tx pin */
#if (BSP_FEATURE_SCI_VERSION == 2U)
err = R_SCI_B_UART_Write(&g_uart_ctrl, g_user_data_buf, q_instance.u.data_size);
#else
err = R_SCI_UART_Write(&g_uart_ctrl, g_user_data_buf, q_instance.u.data_size);
#endif
if(FSP_SUCCESS != err)
{
APP_ERR_PRINT ("\r\n** R_SCI_UART_Write API failed **\r\n");
deinit_usb();
deinit_uart();
APP_ERR_TRAP(err);
}
#endif
}
else
{
/* Buffer is physically transmitted since UART_EVENT_TX_COMPLETE was generated. */
/* Continue to read data from USB. */
/* The amount of data received will be known when USB_STATUS_READ_COMPLETE event occurs*/
err = R_USB_Read(&g_basic_ctrl, g_user_data_buf, DATA_LEN, USB_CLASS_PCDC);
if (FSP_SUCCESS != err)
{
//APP_ERR_PRINT("\r\nR_USB_Read API failed.\r\n");
deinit_usb();
//deinit_uart();
//APP_ERR_TRAP(err);
}
}
}
continue;
}
if(PERIPHERAL_NONE == q_instance.peripheral)
{
;
}
#if 0
/* Enable access to the PFS registers. If using r_ioport module then register protection is automatically
* handled. This code uses BSP IO functions to show how it is used.
*/
R_BSP_PinAccessEnable();
/* Update all board LEDs */
for (uint32_t i = 0; i < leds.led_count; i++)
{
/* Get pin to toggle */
uint32_t pin = leds.p_leds[i];
/* Write to this pin */
R_BSP_PinWrite((bsp_io_port_pin_t) pin, pin_level);
}
/* Protect PFS registers */
R_BSP_PinAccessDisable();
/* Toggle level for next write */
if (BSP_IO_LEVEL_LOW == pin_level)
{
pin_level = BSP_IO_LEVEL_HIGH;
}
else
{
pin_level = BSP_IO_LEVEL_LOW;
}
#endif
//vTaskDelay(configTICK_RATE_HZ);
}
}
/*******************************************************************************************************************//**
* @brief USB PCDC with freertos callback
* @param[IN] usb_event_info_t usb event
* @param[IN] usb_hdl_t task
* @param[IN] usb_onoff_t state
* @retval None
**********************************************************************************************************************/
void usb_pcdc_callback(usb_event_info_t * p_pcdc_event , usb_hdl_t task, usb_onoff_t state)
{
FSP_PARAMETER_NOT_USED (task);
FSP_PARAMETER_NOT_USED (state);
queue_evt_t instance;
fsp_err_t err;
switch (p_pcdc_event->event)
{
/* USB Read complete Class Request */
case USB_STATUS_READ_COMPLETE:
{
//APP_PRINT("\nUSB STATUS : USB_STATUS_READ_COMPLETE \n");
instance.peripheral = PERIPHERAL_USB;
instance.u.data_size = p_pcdc_event->data_size;
/* Send the event from queue */
if (pdTRUE != (xQueueSend(g_event_queue, (const void *)&instance, (TickType_t)(RESET_VALUE))))
{
g_err_flag = true;
//APP_ERR_PRINT("\r\n xQueueSend on g_event_queue Failed \r\n");
//APP_ERR_TRAP(pdTRUE);
}
}
break;
/* Write Complete Class Request */
case USB_STATUS_WRITE_COMPLETE:
{
//APP_PRINT("\nUSB STATUS : USB_STATUS_WRITE_COMPLETE \n");
BaseType_t err_semaphore = xSemaphoreGive(g_usb_tx_semaphore);
if(pdTRUE != err_semaphore)
{
//APP_ERR_PRINT("\r\n xSemaphoreGive on g_usb_tx_semaphore Failed \r\n");
//APP_ERR_TRAP(err_semaphore);
}
err = R_USB_Read (&g_basic_ctrl, g_user_data_buf, DATA_LEN, USB_CLASS_PCDC);
if (FSP_SUCCESS != err)
{
//APP_ERR_PRINT("\r\nR_USB_Read API failed.\r\n");
deinit_usb();
//APP_ERR_TRAP(err);
}
return;
}
break;
/* Configured state class request */
case USB_STATUS_CONFIGURED:
{
b_usb_attach = true;
//APP_PRINT("\r\nUSB Status Configured Successful\r\n");
/* Read data from tera term */
err = R_USB_Read (&g_basic_ctrl, g_user_data_buf, DATA_LEN, USB_CLASS_PCDC);
if (FSP_SUCCESS != err)
{
//APP_ERR_PRINT("\r\nR_USB_Read API failed.\r\n");
deinit_usb();
//APP_ERR_TRAP(err);
}
return;
}
break;
/* Receive Class Request */
case USB_STATUS_REQUEST:
{
/* Check for the specific CDC class request IDs */
if (USB_PCDC_SET_LINE_CODING == (p_pcdc_event->setup.request_type & USB_BREQUEST))
{
//APP_PRINT("\nUSB STATUS : USB_STATUS_REQUEST \nRequest_Type: USB_PCDC_SET_LINE_CODING \n");
/* Get the class request.*/
err = R_USB_PeriControlDataGet (&g_basic_ctrl, (uint8_t*) &g_line_coding, LINE_CODING_LENGTH);
if(FSP_SUCCESS == err)
{
#if 0
/* Line Coding information read from the control pipe */
APP_PRINT ("\n*********SET***********\nbitrate = %d\nChar_Format = %d\nParity_Type = %d\ndata_Bit = %d\n***********************\n",\
g_line_coding.dw_dte_rate,
g_line_coding.b_char_format,
g_line_coding.b_parity_type,
g_line_coding.b_data_bits);
g_sci_extend_cfg.p_baud_setting = &g_baud_setting;
g_uart_test_cfg.p_extend = &g_sci_extend_cfg;
/* Calculate the baud rate*/
g_baud_rate = g_line_coding.dw_dte_rate;
if(INVALID_SIZE < g_baud_rate)
{
/* Calculate baud rate setting registers */
#if (BSP_FEATURE_SCI_VERSION == 2U)
err = R_SCI_B_UART_BaudCalculate(g_baud_rate, g_enable_bitrate_modulation, g_error_rate_x_1000, &g_baud_setting);
#else
err = R_SCI_UART_BaudCalculate(g_baud_rate, g_enable_bitrate_modulation, g_error_rate_x_1000, &g_baud_setting);
#endif
if(FSP_SUCCESS != err)
{
APP_ERR_PRINT ("\r\n** R_SCI_UART_BaudCalculate API failed **\r\n");
deinit_usb();
deinit_uart();
APP_ERR_TRAP(err);
}
}
/* Set number of parity bits */
set_uart_line_coding_cfg (&g_uart_test_cfg, &g_line_coding);
/* Close module */
#if (BSP_FEATURE_SCI_VERSION == 2U)
err = R_SCI_B_UART_Close (&g_uart_ctrl);
#else
err = R_SCI_UART_Close (&g_uart_ctrl);
#endif
if (FSP_SUCCESS != err)
{
APP_ERR_PRINT ("\r\n** R_SCI_UART_Close API failed ** \r\n");
}
/* Open UART with changed UART settings */
#if (BSP_FEATURE_SCI_VERSION == 2U)
err = R_SCI_B_UART_Open(&g_uart_ctrl, &g_uart_test_cfg);
#else
err = R_SCI_UART_Open(&g_uart_ctrl, &g_uart_test_cfg);
#endif
if(FSP_SUCCESS != err)
{
APP_ERR_PRINT ("\r\n** R_SCI_UART_Open API failed **\r\n");
deinit_usb();
APP_ERR_TRAP(err);
}
#endif
}
}
else if (USB_PCDC_GET_LINE_CODING == (p_pcdc_event->setup.request_type & USB_BREQUEST))
{
//APP_PRINT("\nUSB STATUS : USB_STATUS_REQUEST \nRequest_Type: USB_PCDC_GET_LINE_CODING \n");
/* Set the class request.*/
err = R_USB_PeriControlDataSet (&g_basic_ctrl, (uint8_t*) &g_line_coding, LINE_CODING_LENGTH);
if (FSP_SUCCESS == err)
{
//APP_PRINT ("\n*********GET***********\nbitrate = %d\nChar_Format = %d\nParity_Type = %d\ndata_Bit = %d\n***********************\n",
// g_line_coding.dw_dte_rate,
// g_line_coding.b_char_format,
// g_line_coding.b_parity_type,
// g_line_coding.b_data_bits);
}
else
{
//APP_ERR_PRINT("\r\nR_USB_PeriControlDataSet failed.\r\n");
deinit_usb();
//deinit_uart();
//APP_ERR_TRAP(err);
}
}
else if (USB_PCDC_SET_CONTROL_LINE_STATE == (p_pcdc_event->setup.request_type & USB_BREQUEST))
{
//APP_PRINT("\nUSB STATUS : USB_STATUS_REQUEST \nRequest_Type: USB_PCDC_SET_CONTROL_LINE_STATE \n");
/* Get the status of the control signals */
err = R_USB_PeriControlDataGet(&g_basic_ctrl,
(uint8_t*) &g_control_line_state,
sizeof(usb_pcdc_ctrllinestate_t));
if (FSP_SUCCESS == err)
{
if (FSP_SUCCESS == err)
{
#if 0
g_control_line_state.bdtr = (unsigned char)((p_pcdc_event->setup.request_value >> 0) & 0x01);
g_control_line_state.brts = (unsigned char)((p_pcdc_event->setup.request_value >> 1) & 0x01);
/* Toggle the line state if the flow control pin is set to a value (other than SCI_UART_INVALID_16BIT_PARAM) */
if (SCI_UART_INVALID_16BIT_PARAM != g_uart_ctrl.flow_pin)
{
R_BSP_PinAccessEnable();
R_BSP_PinWrite(g_uart_ctrl.flow_pin,
(g_control_line_state.brts == 0) ? BSP_IO_LEVEL_LOW : BSP_IO_LEVEL_HIGH);
R_BSP_PinAccessDisable();
}
APP_PRINT("\n******Line State*******\nbdtr = %d\nbrts = %d\n***********************\n",
g_control_line_state.bdtr,
g_control_line_state.brts);
#endif
}
}
/* Set the usb status as ACK response.*/
err = R_USB_PeriControlStatusSet (&g_basic_ctrl, USB_SETUP_STATUS_ACK);
if (FSP_SUCCESS != err)
{
//APP_ERR_PRINT("\r\nR_USB_PeriControlStatusSet failed.\r\n");
deinit_usb();
//deinit_uart();
//APP_ERR_TRAP(err);
}
}
else
{
;
}
return;
}
break;
/* Complete Class Request */
case USB_STATUS_REQUEST_COMPLETE:
{
if(USB_PCDC_SET_LINE_CODING == (p_pcdc_event->setup.request_type & USB_BREQUEST))
{
//APP_PRINT("\nUSB STATUS : USB_STATUS_REQUEST_COMPLETE \nRequest_Type: USB_PCDC_SET_LINE_CODING \n");
}
else if (USB_PCDC_GET_LINE_CODING == (p_pcdc_event->setup.request_type & USB_BREQUEST))
{
//APP_PRINT("\nUSB STATUS : USB_STATUS_REQUEST_COMPLETE \nRequest_Type: USB_PCDC_GET_LINE_CODING \n");
}
else
{
;
}
return;
}
break;
/* Detach, Suspend State Class requests */
case USB_STATUS_DETACH:
/* Stop all read/write transactions using R_USB_Stop */
case USB_STATUS_SUSPEND:
{
//APP_PRINT("\nUSB STATUS : USB_STATUS_DETACH or USB_STATUS_SUSPEND\r\n");
/* Reset the usb attached flag indicating usb is removed.*/
b_usb_attach = false;
memset (g_user_data_buf, RESET_VALUE, sizeof(g_user_data_buf));
return;
}
/* Resume state */
case USB_STATUS_RESUME:
{
//APP_PRINT("\nUSB STATUS : USB_STATUS_RESUME\r\n");
/* set the usb attached flag*/
b_usb_attach = true;
}
break;
default:
return;
break;
}
}
编译运行
右键点击工程名->构建项目
点击甲壳虫图标
点击运行
可以看到枚举出来的串口
上位机发送一个字节,开发板返回hello
总结
使用配置工具可以比较方便的配置相关的驱动,能够比较快速的搭建USB开发环境。
注意USB PLL频率要配置为24MHz。
- 2024-07-20
-
发表了主题帖:
【超小型 Linux 开发套件Quantum Tiny Linux】tinygl+mpu6050角度3D展示与UDP上报数据
完整代码见附件
视频
[localvideo]1260e26ee8040763e9cc1cfdb342c2a2[/localvideo]
b站视频
视频号
tinygl+mpu6050角度3D展示与UDP上报数据 (qq.com)
前面我们实现了角度数据的获取,显示,我们还可以将数据传输到云端,如果超过范围实现告警,实现地震,塌方,位移等地质灾害得预警。
板在wifi可以连接外网,我们使用udp协议上报数据,
增加udp.c udp.h 实现相关发送接口
Udp.c如下
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* socket文件描述符 */
int sock_fd = -1;
struct sockaddr_in addr_serv;
int udp_init(char* ip, int port)
{
if(sock_fd >= 0)
{
return 0;
}
/* 建立udp socket */
sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
if(sock_fd < 0)
{
perror("socket");
return -1;
}
/* 设置address */
memset(&addr_serv, 0, sizeof(addr_serv));
addr_serv.sin_family = AF_INET;
addr_serv.sin_addr.s_addr = inet_addr(ip);
addr_serv.sin_port = htons(port);
return 0;
}
int udp_send(char* buffer, int len)
{
int send_num;
send_num = sendto(sock_fd, buffer, len, 0, (struct sockaddr *)&addr_serv, sizeof(addr_serv));
if(send_num < 0)
{
perror("sendto error:");
return -1;
}
}
int udp_deinit(void)
{
if(sock_fd >= 0)
{
close(sock_fd);
sock_fd = -1;
}
}
Udp.h如下
#ifndef UDP_H
#define UDP_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
int udp_init(char* ip, int port);
int udp_send(char* buffer, int len);
int udp_deinit(void);
#ifdef __cplusplus
}
#endif
#endif
上报数据
snprintf(text,sizeof(text),"x:%f",th[0]);
glDrawText((GLubyte *)text, 0, 0, 0xFF0000);
udp_send(text, strlen(text));
snprintf(text,sizeof(text),"y:%f",th[1]);
glDrawText((GLubyte *)text, 0, 12, 0x00FF00);
udp_send(text, strlen(text));
snprintf(text,sizeof(text),"z:%f",th[2]);
glDrawText((GLubyte *)text, 0, 24, 0x0000FF);
udp_send(text, strlen(text));
完整代码见附件
编译
gcc tinygl/src/*.c cube.c lcd.c mpu6050.c mpu6050_itf.c udp.c -I tinygl/include/ -o cube -lm
运行
先连接wifi,
确认服务端ip地址 我这里是192.168.31.236
sudo python ~/WorkSpace/System/net/connect_wifi.py CMCC-bdgQ cqmygysdss
./cube 192.168.31.236 8243
测试效果见测试
-
发表了主题帖:
【超小型 Linux 开发套件Quantum Tiny Linux】基于tinygl+mpu6050的3D角度计Demo
源码见附件
视频
[localvideo]8a7af6ceb374849fac8ec8c30f65f96c[/localvideo]
b站视频
视频号
基于tinygl+mpu6050的3D角度计Demo (qq.com)
前面我们移植了tinygl可以进行3D显示了,结合之前获取的mpu6050的角度信息,我们就可以3D动态显示角度的变化过程。实现水准(角度计)的Demo。
角度显示
char text[64];
/* 获取角度 */
int16_t accel[3];
mpu6050_itf_get_accel(accel);
accel[0] /= 4096;
accel[1] /= 4096;
accel[2] /= 4096;
/* 加速度计算角度
θx=α1180/π=[arctan(Ax/squr(AyAy+AzAz))]180/π
θy=β1180/π=[arctan(Ay/squr(AxAx+AzAz))]180/π
θz=γ1180/π=[arctan(Az/squr(AxAx+AyAy))]*180/π
*/
float th[3];
th[0] = atan2(sqrt(accel[1]*accel[1]+accel[2]*accel[2]),accel[0]) * 180/PI;
th[1] = atan2(sqrt(accel[0]*accel[0]+accel[2]*accel[2]),accel[1]) * 180/PI;
th[2] = atan2(sqrt(accel[0]*accel[0]+accel[1]*accel[1]),accel[2]) * 180/PI;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* 显示角度 */
snprintf(text,sizeof(text),"x:%f",th[0]);
glDrawText((GLubyte *)text, 0, 0, 0xFF0000);
snprintf(text,sizeof(text),"y:%f",th[1]);
glDrawText((GLubyte *)text, 0, 12, 0x00FF00);
snprintf(text,sizeof(text),"z:%f",th[2]);
glDrawText((GLubyte *)text, 0, 24, 0x0000FF);
显示立方体,立方体绕三轴旋转来动态展示,三轴的角度
/* 画立方体,并旋转角度 */
draw_cube(th[0], th[1], th[2], 2, winSizeX, winSizeY);
void draw_cube(float x, float y, float z, float size, float cx, float cy)
{
glRotatef(x, 1.0f, 0.0f, 0.0f);
glRotatef(y, 0.0f, 1.0f, 0.0f);
glRotatef(z, 0.0f, 0.0f, 1.0f);
glBegin(GL_QUADS);
// Front Face
glColor3f(1.0f, 0.0f, 0.0f); //红
glVertex3f(-size, -size, size);
glVertex3f(size, -size, size);
glVertex3f(size, size, size);
glVertex3f(-size, size, size);
// Back Face
glColor3f(1.0f, 1.0f, 0.0f); //黄
glVertex3f(-size, -size, -size);
glVertex3f(size, -size, -size);
glVertex3f(size, size, -size);
glVertex3f(-size, size, -size);
// Top Face
glColor3f(0.0f, 0.0f, 1.0f); //蓝
glVertex3f(-size, size, size);
glVertex3f(size, size, size);
glVertex3f(size, size, -size);
glVertex3f(-size, size, -size);
// Bottom Face
glColor3f(1.0f, 0.0f, 1.0f); //紫
glVertex3f(-size, -size, size);
glVertex3f(size, -size, size);
glVertex3f(size, -size, -size);
glVertex3f(-size, -size, -size);
// Left Face
glColor3f(0.0f, 1.0f, 0.0f); //绿
glVertex3f(-size, -size, -size);
glVertex3f(-size, -size, size);
glVertex3f(-size, size, size);
glVertex3f(-size, size, -size);
// Right face
glColor3f(0.0f, 1.0f, 1.0f); //青
glVertex3f(size, -size, size);
glVertex3f(size, -size, -size);
glVertex3f(size, size, -size);
glVertex3f(size, size, size);
glEnd();
}
完整的代码见附件。
编译
gcc tinygl/src/*.c cube.c lcd.c mpu6050.c mpu6050_itf.c -I tinygl/include/ -o cube -lm
运行
./cube
测试效果见视频
-
发表了主题帖:
【超小型 Linux 开发套件Quantum Tiny Linux】移植tinygl实现3D显示
本帖最后由 qinyunti 于 2024-7-20 13:39 编辑
源码如下
视频
[localvideo]e59e016f76e0ea72b0458e724f19f86f[/localvideo]
b站视频
微信公众号视频
移植tinygl实现3D显示-基于Quantum开发板 (qq.com)
视频号
前言
前面我们基于fb实现了ftf操作接口,现在开始就可以移植各种GUI了,
我们前面实现了mpu6050的角度获取,后面就可以实现角度的3D显示。
这一篇我们先来移植tinygl为3D显示做准备。
Tinygl项目网站见https://bellard.org/TinyGL/
Tinygl是OpenGL的一个嵌入式实现子集
下载代码
git clone https://github.com/jserv/tinygl
或者直接下载打包源码
https://bellard.org/TinyGL/TinyGL-0.4.1.tar.gz
将TinyGL-0.4.1.tar.gz导入到开发板
解压
tar -xvf TinyGL-0.4.1.tar.gz
cd TinyGL
make
可以看到能够编译,
但是默认需要x X display,所以我们需要移植到我们的tft显示,使用之前的基于fb的lcd接口封装。
删除不必要的文件最终目录如下
复制examples下raw下的gears.c样例程序进行修改。
接口移植
Tinygl显示基于buffer,即最终显示内容是写入buffer的
初始化 ZB_open返回帧buffer,frameBuffer
// initialize TinyGL
ZBuffer *frameBuffer = ZB_open(winSizeX, winSizeY,
#if TGL_FEATURE_RENDER_BITS == 32
ZB_MODE_RGBA,
#else
ZB_MODE_5R6G5B,
#endif
0);
if (!frameBuffer) {
printf("\nZB_open failed!");
exit(1);
}
glInit(frameBuffer);
需要刷新显示时将帧frameBuffer拷贝出来到imbuf,然后显示imbuf即可
ZB_copyFrameBuffer(frameBuffer, imbuf, winSizeX * sizeof(PIXEL));
或者直接修改 ZB_copyFrameBuffer
将frameBuffer直接写入用户的显存,无需再经过imbuf中转,减少一次内存拷贝。
这里在原来lcd.c上增加一个接口
int lcd_fill(uint8_t* buffer)
{
memcpy(s_fbp, buffer, s_vinfo.xres*s_vinfo.yres*s_vinfo.bits_per_pixel / 8);
}
如下进行显示
ZB_copyFrameBuffer(frameBuffer, imbuf, winSizeX * sizeof(PIXEL));
lcd_fill((uint8_t*)imbuf);
配置
修改显示的位宽,我们这里是16位
\include\zfeatures.h下修改
#define TGL_FEATURE_16_BITS 0
#define TGL_FEATURE_32_BITS 1
为
#define TGL_FEATURE_16_BITS 0
#define TGL_FEATURE_32_BITS 0
测试
编译
gcc tinygl/src/*.c gears.c lcd.c -I tinygl/include/ -o gears -lm
运行
./gears
测试效果见视频
-
回复了主题帖:
【超小型 Linux 开发套件Quantum Tiny Linux】更换ftf屏幕
lugl4313820 发表于 2024-7-20 06:10
这是大佬手工替换的吗?好象是焊接的吧。
是fpc排线焊接的,
-
发表了主题帖:
【超小型 Linux 开发套件Quantum Tiny Linux】基于fb封装TFT操作接口
为了方便后续移植GUI, 基于fb实现TTF的点的操作接口。
初始化打开设备,映射mmap
int lcd_init(char* dev)
{
s_fp = open(dev, O_RDWR);
if(s_fp < 0)
{
printf("Error : Can not open framebuffer device/n");
return -1;
}
if(ioctl(s_fp, FBIOGET_FSCREENINFO, &s_finfo))
{
if(s_fp > 0) /* 关闭设备 */
{
close (s_fp);
s_fp = -1;
}
printf("Error reading fixed information/n");
return -2;
}
if(ioctl(s_fp, FBIOGET_VSCREENINFO, &s_vinfo))
{
if(s_fp > 0) /* 关闭设备 */
{
close (s_fp);
s_fp = -1;
}
printf("Error reading variable information/n");
return -3;
}
s_screensize = s_vinfo.xres * s_vinfo.yres * s_vinfo.bits_per_pixel / 8;
printf("The phy mem = 0x%lx, total size = %d(byte)\n", s_finfo.smem_start, s_finfo.smem_len);
printf("xres = %d, yres = %d, bits_per_pixel = %d\n", s_vinfo.xres, s_vinfo.yres, s_vinfo.bits_per_pixel);
printf("So the s_screensize = %d(byte), using %d frame\n", s_screensize, s_finfo.smem_len/s_screensize);
printf("s_vinfo.xoffset = %d, s_vinfo.yoffset = %d\n", s_vinfo.xoffset, s_vinfo.yoffset);
printf("s_vinfo.vmode is :%d\n", s_vinfo.vmode);
printf("s_finfo.ypanstep is :%d\n", s_finfo.ypanstep);
printf("s_vinfo.red.offset=0x%x\n", s_vinfo.red.offset);
printf("s_vinfo.red.length=0x%x\n", s_vinfo.red.length);
printf("s_vinfo.green.offset=0x%x\n", s_vinfo.green.offset);
printf("s_vinfo.green.length=0x%x\n", s_vinfo.green.length);
printf("s_vinfo.blue.offset=0x%x\n", s_vinfo.blue.offset);
printf("s_vinfo.blue.length=0x%x\n", s_vinfo.blue.length);
printf("s_vinfo.transp.offset=0x%x\n", s_vinfo.transp.offset);
printf("s_vinfo.transp.length=0x%x\n", s_vinfo.transp.length);
s_fbp =(char *)mmap(0, s_screensize, PROT_READ | PROT_WRITE, MAP_SHARED, s_fp, 0);
if ((void *)s_fbp == MAP_FAILED)
{
printf ("Error: failed to map framebuffer device to memory./n");
if(s_fp > 0) /* 关闭设备 */
{
close (s_fp);
s_fp = -1;
}
return -4;
}
printf("Get virt mem = %p\n", s_fbp);
/* using first frame, for FBIOPAN_DISPLAY
* 当刷新需要调用FBIOPAN_DISPLAY, 要告知驱动刷哪块帧, 用到下面两个参数
* 如果使用第二帧buffer -> s_vinfo.xoffset = 0; s_vinfo.yoffset = s_vinfo.yres;
*/
s_vinfo.xoffset = 0;
s_vinfo.yoffset = 0;
return 0;
}
解除初始化
int lcd_deinit(void)
{
if(s_fbp != NULL)
{
munmap(s_fbp, s_screensize); /* 解除映射 */
s_fbp = NULL;
}
if(s_fp > 0) /* 关闭设备 */
{
close (s_fp);
s_fp = -1;
}
}
写点
int lcd_set_pixel(uint32_t x, uint32_t y, uint32_t color)
{
uint32_t location = x * (s_vinfo.bits_per_pixel / 8) + y * s_finfo.line_length;
if(s_vinfo.bits_per_pixel == 8)
{
*(uint8_t*)(s_fbp+location) = (uint8_t)(color&0xFF);
}
else if(s_vinfo.bits_per_pixel == 16)
{
*(uint16_t*)(s_fbp+location) = (uint16_t)(color&0xFFFF);
}
else if(s_vinfo.bits_per_pixel == 32)
{
*(uint32_t*)(s_fbp+location) = color;
}
else{}
//ioctl(s_fp, FBIOPAN_DISPLAY, &s_vinfo);
}
读点
int lcd_get_pixel(uint32_t x, uint32_t y, uint32_t* color)
{
uint32_t location = x * (s_vinfo.bits_per_pixel / 8) + y * s_finfo.line_length;
if(s_vinfo.bits_per_pixel == 8)
{
*color = *(uint8_t*)(s_fbp+location);
}
else if(s_vinfo.bits_per_pixel == 16)
{
*color = *(uint16_t*)(s_fbp+location);
}
else if(s_vinfo.bits_per_pixel == 32)
{
*color = *(uint32_t*)(s_fbp+location);
}
else{}
}
测试,RGB刷屏
#if FB_TEST
int main(int argc, char* argv[])
{
if(argc == 2)
{
int res = lcd_init(argv[1]);
if(res != 0)
{
printf("lcd init err:%d\r\n",res);
return -1;
}
uint32_t xres;
uint32_t yres;
lcd_get_res(&xres, &yres);
for(int t=0; t<10; t++)
{
for(uint32_t i=0; i<xres; i++)
{
for(uint32_t j=0; j<yres; j++)
{
lcd_set_pixel(i, j, 0xF800);
}
}
sleep(1);
for(uint32_t i=0; i<xres; i++)
{
for(uint32_t j=0; j<yres; j++)
{
lcd_set_pixel(i, j, 0x07E0);
}
}
sleep(1);
for(uint32_t i=0; i<xres; i++)
{
for(uint32_t j=0; j<yres; j++)
{
lcd_set_pixel(i, j, 0x1F);
}
}
sleep(1);
}
lcd_deinit();
}
else
{
printf("usage:./fb dev\r\n");
return -2;
}
}
#endif
完整的lcd.c
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <string.h>
#define FB_TEST 1
static int s_fp=0;
static uint8_t *s_fbp = NULL;
static uint32_t s_screensize=0;
static struct fb_var_screeninfo s_vinfo;
static struct fb_fix_screeninfo s_finfo;
int lcd_sync(void)
{
return 0;
}
int lcd_set_pixel(uint32_t x, uint32_t y, uint32_t color)
{
uint32_t location = x * (s_vinfo.bits_per_pixel / 8) + y * s_finfo.line_length;
if(s_vinfo.bits_per_pixel == 8)
{
*(uint8_t*)(s_fbp+location) = (uint8_t)(color&0xFF);
}
else if(s_vinfo.bits_per_pixel == 16)
{
*(uint16_t*)(s_fbp+location) = (uint16_t)(color&0xFFFF);
}
else if(s_vinfo.bits_per_pixel == 32)
{
*(uint32_t*)(s_fbp+location) = color;
}
else{}
//ioctl(s_fp, FBIOPAN_DISPLAY, &s_vinfo);
}
int lcd_get_pixel(uint32_t x, uint32_t y, uint32_t* color)
{
uint32_t location = x * (s_vinfo.bits_per_pixel / 8) + y * s_finfo.line_length;
if(s_vinfo.bits_per_pixel == 8)
{
*color = *(uint8_t*)(s_fbp+location);
}
else if(s_vinfo.bits_per_pixel == 16)
{
*color = *(uint16_t*)(s_fbp+location);
}
else if(s_vinfo.bits_per_pixel == 32)
{
*color = *(uint32_t*)(s_fbp+location);
}
else{}
}
int lcd_get_res(uint32_t* x, uint32_t* y)
{
*x = s_vinfo.xres;
*y = s_vinfo.yres;
return 0;
}
int lcd_init(char* dev)
{
s_fp = open(dev, O_RDWR);
if(s_fp < 0)
{
printf("Error : Can not open framebuffer device/n");
return -1;
}
if(ioctl(s_fp, FBIOGET_FSCREENINFO, &s_finfo))
{
if(s_fp > 0) /* 关闭设备 */
{
close (s_fp);
s_fp = -1;
}
printf("Error reading fixed information/n");
return -2;
}
if(ioctl(s_fp, FBIOGET_VSCREENINFO, &s_vinfo))
{
if(s_fp > 0) /* 关闭设备 */
{
close (s_fp);
s_fp = -1;
}
printf("Error reading variable information/n");
return -3;
}
s_screensize = s_vinfo.xres * s_vinfo.yres * s_vinfo.bits_per_pixel / 8;
printf("The phy mem = 0x%lx, total size = %d(byte)\n", s_finfo.smem_start, s_finfo.smem_len);
printf("xres = %d, yres = %d, bits_per_pixel = %d\n", s_vinfo.xres, s_vinfo.yres, s_vinfo.bits_per_pixel);
printf("So the s_screensize = %d(byte), using %d frame\n", s_screensize, s_finfo.smem_len/s_screensize);
printf("s_vinfo.xoffset = %d, s_vinfo.yoffset = %d\n", s_vinfo.xoffset, s_vinfo.yoffset);
printf("s_vinfo.vmode is :%d\n", s_vinfo.vmode);
printf("s_finfo.ypanstep is :%d\n", s_finfo.ypanstep);
printf("s_vinfo.red.offset=0x%x\n", s_vinfo.red.offset);
printf("s_vinfo.red.length=0x%x\n", s_vinfo.red.length);
printf("s_vinfo.green.offset=0x%x\n", s_vinfo.green.offset);
printf("s_vinfo.green.length=0x%x\n", s_vinfo.green.length);
printf("s_vinfo.blue.offset=0x%x\n", s_vinfo.blue.offset);
printf("s_vinfo.blue.length=0x%x\n", s_vinfo.blue.length);
printf("s_vinfo.transp.offset=0x%x\n", s_vinfo.transp.offset);
printf("s_vinfo.transp.length=0x%x\n", s_vinfo.transp.length);
s_fbp =(char *)mmap(0, s_screensize, PROT_READ | PROT_WRITE, MAP_SHARED, s_fp, 0);
if ((void *)s_fbp == MAP_FAILED)
{
printf ("Error: failed to map framebuffer device to memory./n");
if(s_fp > 0) /* 关闭设备 */
{
close (s_fp);
s_fp = -1;
}
return -4;
}
printf("Get virt mem = %p\n", s_fbp);
/* using first frame, for FBIOPAN_DISPLAY
* 当刷新需要调用FBIOPAN_DISPLAY, 要告知驱动刷哪块帧, 用到下面两个参数
* 如果使用第二帧buffer -> s_vinfo.xoffset = 0; s_vinfo.yoffset = s_vinfo.yres;
*/
s_vinfo.xoffset = 0;
s_vinfo.yoffset = 0;
return 0;
}
int lcd_deinit(void)
{
if(s_fbp != NULL)
{
munmap(s_fbp, s_screensize); /* 解除映射 */
s_fbp = NULL;
}
if(s_fp > 0) /* 关闭设备 */
{
close (s_fp);
s_fp = -1;
}
}
#if FB_TEST
int main(int argc, char* argv[])
{
if(argc == 2)
{
int res = lcd_init(argv[1]);
if(res != 0)
{
printf("lcd init err:%d\r\n",res);
return -1;
}
uint32_t xres;
uint32_t yres;
lcd_get_res(&xres, &yres);
for(int t=0; t<10; t++)
{
for(uint32_t i=0; i<xres; i++)
{
for(uint32_t j=0; j<yres; j++)
{
lcd_set_pixel(i, j, 0xF800);
}
}
sleep(1);
for(uint32_t i=0; i<xres; i++)
{
for(uint32_t j=0; j<yres; j++)
{
lcd_set_pixel(i, j, 0x07E0);
}
}
sleep(1);
for(uint32_t i=0; i<xres; i++)
{
for(uint32_t j=0; j<yres; j++)
{
lcd_set_pixel(i, j, 0x1F);
}
}
sleep(1);
}
lcd_deinit();
}
else
{
printf("usage:./fb dev\r\n");
return -2;
}
}
#endif
完整的lcd.h
#ifndef LCD_H
#define LCD_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
int lcd_deinit(void);
int lcd_init(char* dev);
int lcd_get_res(uint32_t* x, uint32_t* y);
int lcd_get_pixel(uint32_t x, uint32_t y, uint32_t* color);
int lcd_set_pixel(uint32_t x, uint32_t y, uint32_t color);
int lcd_sync(void);
#ifdef __cplusplus
}
#endif
#endif
测试
将代码导入到开发板
编译
gcc lcd.c -o lcd
运行
./lcd /dev/fb1
可以看到屏幕RGB刷屏
- 2024-07-19
-
发表了主题帖:
【超小型 Linux 开发套件Quantum Tiny Linux】更换ftf屏幕
板子邮寄过来时就发现tft屏花屏了,怀疑是快递过程中受损了
于是卖了一块同型号的替换
去掉原来的屏幕,焊接新的屏幕
清洗下
上电看到ok了
跑一下之前的测试程序,显示正常了
- 2024-07-18
-
回复了主题帖:
《嵌入式软件的时间分析》书友问答接龙 第四集:软件时间理论
做个小结:
本章介绍了多种时间参数, 可以使用最小最大值,平均值以及直方图进行呈现,一般系统可以直接记录最小值最大值平均值不需要过多的存储资源,而记录直方图需要较多的存储资源所以一般可以通过一定通讯接口发送到PC等进行存储分析。
CPU负载是一个比较关键的概念,一般RTOS中都有对应的接口可以获取,简单可以理解为CPU执行有效业务所占总时间的比例,可以换个思路用1-执行空闲任务所占比例来求。而计算需要选择一个合适的窗口时间来统计。