- 2025-04-03
-
发表了主题帖:
【米尔-STM32MP257开发板试用体验】音频实时处理_回声消除与降噪应用评估
前言
本文评估开发板上进行音频实时处理,移植speex算法,进行回声消除和降噪处理,主要关注算法执行时间。
移植speex
Speex的移植可以参考公众号文章
https://mp.weixin.qq.com/s/zJPNgyOaKNpIbHfshe6CjQ
https://mp.weixin.qq.com/s/-nRwGWvYfl6wtvFSSul1DQ
https://mp.weixin.qq.com/s/p6cOppuoFYCTw6a-bu299Q
我这里分享了测试demo,
https://github.com/qinyunti/speex_test.git
测试
git clone https://github.com/qinyunti/speex_test.git
编译
source /opt/st/myd-ld25x/4.2.4-snapshot/environment-setup-cortexa35-ostl-linux
修改build.sh
gcc为$CC
chmod +x ./build.sh
./build.sh
导入测试文件到开发板
导入程序到开发板
chmod +x speexecho
./speexecho mic3.wav spk3.wav out3.wav
可以看到执行时间大概是1.8mS
导出out3.wav查看波形
可以看到回声消除和降噪效果。
这里对比其他
某个M4F平台N=256点,TAIL=1024需要14~15mS
这里只需要1.8mS,和之前测试的fft的效率比例相当,所以算法主要执行时间就是取决于fft运算时间,当然还有很多内存搬运的时间和平台相关。
总结
以上可以看到进行16k音频的实时处理,对应时间为16mS,需要算法时间为1.8ms,
所以算法完全足够,如果按照48k采样率,数据量变为3倍,按倍数估计也只需要5.4ms,
占比16ms也很少,所以进行实时音频处理是毫无压力的。
-
发表了主题帖:
【米尔-STM32MP257开发板试用体验】软件fft测试
本帖最后由 qinyunti 于 2025-4-3 12:33 编辑
代码
前言
后面移植音频处理算法需要大量调用fft算法。其执行时间影响音频算法是否能实时处理,所以我们先来进行实测,评估fft执行时间。刚好前面也评测了一款H系类的M4F核的MCU,可以对比下。
移植KISSFFT
Kissfft是常用的fft实现库,后面的音频算法中也会使用,所以基于该库进行测试。
需要的文件如下
qinyunti@qinyunti:/mnt/d/BaiduSyncdisk/BOARD/ld25x/kissfftt$ tree .
.
├── kiss_fft_port.c
├── kiss_fft_port.h
├── kissfft
│ ├── _kiss_fft_guts.h
│ ├── kfc.c
│ ├── kfc.h
│ ├── kiss_fft.c
│ ├── kiss_fft.h
│ ├── kiss_fft_log.h
│ ├── kiss_fftnd.c
│ ├── kiss_fftnd.h
│ ├── kiss_fftndr.c
│ ├── kiss_fftndr.h
│ ├── kiss_fftr.c
│ ├── kiss_fftr.h
│ └── kissfft.hh
├── kissfft_test.c
└── kissfft_test.h
1 directory, 17 files
其中
kiss_fft_port.c中的kiss_fft_port_malloc和
kiss_fft_port_free使用标准库的malloc和free
kiss_fft_port.c中
#include <stddef.h>
#include <stdlib.h>
void* kiss_fft_port_malloc(size_t size)
{
return malloc(size);
}
void kiss_fft_port_free(void* p)
{
free(p);
}
kissfft_test.c是测试代码
其中事件测量需要获取时间戳
#include <time.h>
static uint64_t get_tm(void){
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC,&ts);
return ts.tv_sec*1000000000ull + ts.tv_nsec;
}
编译
$CC kissfft/*.c kiss_fft_port.c kissfft_test.c -I. -Ikissfft -o kissfft_test -lm
测试
导入kissfft_test到开发板
chmod +x kissfft_test
执行
./kissfft_test 256 1000
打印如下
root@myd-ld25x:~# ./kissfft_test 256 1000
[in]
(1.000000,0.000000),(1.049083,0.000000),(1.098135,0.000000),(1.147129,0.000000),(1.196034,0.000000),(1.244821,0.000000),(1.293461,0.000000),(1.341924,0.000000),(1.390181,0.000000),(1.438203,0.000000),(1.485960,0.000000),(1.533426,0.000000),(1.580569,0.000000),(1.627363,0.000000),(1.673780,0.000000),(1.719790,0.000000),(1.765367,0.000000),(1.810483,0.000000),(1.855110,0.000000),(1.899223,0.000000),(1.942793,0.000000),(1.985796,0.000000),(2.028205,0.000000),(2.069995,0.000000),(2.111140,0.000000),(2.151617,0.000000),(2.191399,0.000000),(2.230463,0.000000),(2.268787,0.000000),(2.306346,0.000000),(2.343118,0.000000),(2.379081,0.000000),(2.414214,0.000000),(2.448494,0.000000),(2.481902,0.000000),(2.514418,0.000000),(2.546021,0.000000),(2.576693,0.000000),(2.606415,0.000000),(2.635170,0.000000),(2.662939,0.000000),(2.689707,0.000000),(2.715457,0.000000),(2.740174,0.000000),(2.763843,0.000000),(2.786448,0.000000),(2.807979,0.000000),(2.828420,0.000000),(2.847759,0.000000),(2.865986,0.000000),(2.883088,0.000000),(2.899056,0.000000),(2.913881,0.000000),(2.927552,0.000000),(2.940063,0.000000),(2.951404,0.000000),(2.961571,0.000000),(2.970555,0.000000),(2.978353,0.000000),(2.984959,0.000000),(2.990369,0.000000),(2.994581,0.000000),(2.997591,0.000000),(2.999398,0.000000),(3.000000,0.000000),(2.999398,0.000000),(2.997591,0.000000),(2.994581,0.000000),(2.990369,0.000000),(2.984959,0.000000),(2.978353,0.000000),(2.970555,0.000000),(2.961571,0.000000),(2.951404,0.000000),(2.940063,0.000000),(2.927552,0.000000),(2.913881,0.000000),(2.899056,0.000000),(2.883088,0.000000),(2.865986,0.000000),(2.847759,0.000000),(2.828419,0.000000),(2.807979,0.000000),(2.786448,0.000000),(2.763843,0.000000),(2.740174,0.000000),(2.715457,0.000000),(2.689707,0.000000),(2.662939,0.000000),(2.635170,0.000000),(2.606415,0.000000),(2.576693,0.000000),(2.546021,0.000000),(2.514418,0.000000),(2.481902,0.000000),(2.448494,0.000000),(2.414214,0.000000),(2.379081,0.000000),(2.343118,0.000000),(2.306346,0.000000),(2.268786,0.000000),(2.230463,0.000000),(2.191398,0.000000),(2.151616,0.000000),(2.111140,0.000000),(2.069995,0.000000),(2.028205,0.000000),(1.985796,0.000000),(1.942793,0.000000),(1.899223,0.000000),(1.855110,0.000000),(1.810483,0.000000),(1.765367,0.000000),(1.719790,0.000000),(1.673780,0.000000),(1.627363,0.000000),(1.580570,0.000000),(1.533425,0.000000),(1.485960,0.000000),(1.438202,0.000000),(1.390181,0.000000),(1.341924,0.000000),(1.293461,0.000000),(1.244821,0.000000),(1.196034,0.000000),(1.147129,0.000000),(1.098135,0.000000),(1.049082,0.000000),(1.000000,0.000000),(0.950917,0.000000),(0.901865,0.000000),(0.852871,0.000000),(0.803965,0.000000),(0.755178,0.000000),(0.706539,0.000000),(0.658076,0.000000),(0.609819,0.000000),(0.561797,0.000000),(0.514040,0.000000),(0.466574,0.000000),(0.419430,0.000000),(0.372636,0.000000),(0.326220,0.000000),(0.280210,0.000000),(0.234633,0.000000),(0.189517,0.000000),(0.144890,0.000000),(0.100777,0.000000),(0.057206,0.000000),(0.014203,0.000000),(-0.028206,0.000000),(-0.069995,0.000000),(-0.111141,0.000000),(-0.151617,0.000000),(-0.191399,0.000000),(-0.230463,0.000000),(-0.268787,0.000000),(-0.306346,0.000000),(-0.343118,0.000000),(-0.379081,0.000000),(-0.414214,0.000000),(-0.448494,0.000000),(-0.481902,0.000000),(-0.514418,0.000000),(-0.546021,0.000000),(-0.576693,0.000000),(-0.606415,0.000000),(-0.635170,0.000000),(-0.662940,0.000000),(-0.689708,0.000000),(-0.715457,0.000000),(-0.740174,0.000000),(-0.763843,0.000000),(-0.786449,0.000000),(-0.807979,0.000000),(-0.828420,0.000000),(-0.847759,0.000000),(-0.865986,0.000000),(-0.883088,0.000000),(-0.899056,0.000000),(-0.913881,0.000000),(-0.927552,0.000000),(-0.940063,0.000000),(-0.951404,0.000000),(-0.961571,0.000000),(-0.970555,0.000000),(-0.978353,0.000000),(-0.984959,0.000000),(-0.990369,0.000000),(-0.994581,0.000000),(-0.997591,0.000000),(-0.999398,0.000000),(-1.000000,0.000000),(-0.999398,0.000000),(-0.997591,0.000000),(-0.994581,0.000000),(-0.990369,0.000000),(-0.984959,0.000000),(-0.978353,0.000000),(-0.970555,0.000000),(-0.961571,0.000000),(-0.951404,0.000000),(-0.940062,0.000000),(-0.927552,0.000000),(-0.913880,0.000000),(-0.899056,0.000000),(-0.883088,0.000000),(-0.865986,0.000000),(-0.847759,0.000000),(-0.828419,0.000000),(-0.807978,0.000000),(-0.786448,0.000000),(-0.763843,0.000000),(-0.740174,0.000000),(-0.715457,0.000000),(-0.689707,0.000000),(-0.662939,0.000000),(-0.635169,0.000000),(-0.606415,0.000000),(-0.576693,0.000000),(-0.546021,0.000000),(-0.514418,0.000000),(-0.481902,0.000000),(-0.448494,0.000000),(-0.414213,0.000000),(-0.379081,0.000000),(-0.343118,0.000000),(-0.306346,0.000000),(-0.268786,0.000000),(-0.230463,0.000000),(-0.191398,0.000000),(-0.151616,0.000000),(-0.111141,0.000000),(-0.069995,0.000000),(-0.028205,0.000000),(0.014204,0.000000),(0.057207,0.000000),(0.100778,0.000000),(0.144890,0.000000),(0.189517,0.000000),(0.234633,0.000000),(0.280210,0.000000),(0.326221,0.000000),(0.372637,0.000000),(0.419431,0.000000),(0.466575,0.000000),(0.514040,0.000000),(0.561798,0.000000),(0.609820,0.000000),(0.658077,0.000000),(0.706540,0.000000),(0.755179,0.000000),(0.803966,0.000000),(0.852871,0.000000),(0.901865,0.000000),(0.950918,0.000000),
used:105119450
[FFT]
(256.000000,0.000000),(0.000019,-256.000000),(-0.000000,0.000006),(0.000002,0.000007),(-0.000000,0.000003),(0.000000,0.000003),(0.000001,0.000005),(0.000000,0.000002),(-0.000001,0.000003),(-0.000002,-0.000000),(-0.000000,-0.000000),(-0.000000,0.000000),(-0.000002,0.000001),(-0.000001,0.000003),(-0.000000,0.000001),(-0.000002,0.000005),(0.000001,-0.000000),(0.000001,-0.000003),(0.000001,0.000002),(0.000001,0.000002),(-0.000001,0.000000),(-0.000001,-0.000001),(-0.000000,0.000001),(-0.000001,0.000004),(0.000000,0.000001),(-0.000002,-0.000000),(-0.000002,0.000001),(-0.000000,-0.000001),(-0.000001,0.000002),(-0.000001,-0.000000),(-0.000000,0.000002),(-0.000005,0.000003),(0.000000,0.000000),(0.000001,-0.000002),(-0.000004,-0.000001),(-0.000007,-0.000001),(-0.000002,-0.000006),(0.000001,-0.000005),(0.000001,-0.000006),(0.000006,-0.000001),(0.000004,-0.000002),(-0.000001,-0.000000),(-0.000000,0.000000),(-0.000001,0.000003),(0.000002,-0.000002),(0.000003,-0.000003),(-0.000001,0.000001),(-0.000001,0.000002),(0.000001,0.000001),(0.000001,-0.000001),(0.000002,-0.000002),(0.000004,0.000001),(-0.000001,0.000000),(-0.000002,-0.000001),(0.000000,0.000001),(-0.000001,-0.000001),(-0.000001,-0.000000),(0.000001,0.000002),(-0.000001,0.000002),(0.000000,-0.000001),(-0.000000,0.000001),(0.000000,0.000001),(0.000001,-0.000001),(0.000001,-0.000001),(0.000000,0.000000),(0.000001,-0.000001),(0.000001,0.000001),(-0.000000,-0.000002),(0.000000,0.000001),(0.000004,0.000002),(-0.000000,0.000002),(0.000002,-0.000002),(0.000000,0.000006),(-0.000001,0.000001),(-0.000000,0.000007),(0.000000,-0.000003),(-0.000003,0.000003),(-0.000003,-0.000002),(-0.000000,-0.000001),(-0.000000,0.000001),(-0.000001,-0.000000),(-0.000000,0.000005),(-0.000000,-0.000000),(0.000001,-0.000002),(-0.000001,-0.000001),(-0.000001,-0.000000),(0.000001,0.000000),(-0.000001,-0.000001),(0.000000,-0.000002),(-0.000001,0.000002),(-0.000000,0.000000),(0.000000,0.000001),(-0.000000,-0.000001),(0.000001,0.000000),(-0.000001,-0.000000),(-0.000004,-0.000004),(0.000000,0.000000),(0.000001,0.000002),(-0.000002,0.000001),(-0.000000,0.000000),(-0.000000,-0.000001),(-0.000002,0.000000),(-0.000001,-0.000000),(-0.000001,0.000003),(0.000000,-0.000001),(-0.000002,0.000001),(-0.000001,0.000000),(-0.000002,-0.000004),(-0.000001,0.000002),(-0.000001,-0.000004),(0.000001,-0.000002),(0.000004,-0.000001),(0.000002,-0.000002),(-0.000002,-0.000002),(0.000001,0.000003),(-0.000001,-0.000001),(0.000001,0.000001),(0.000001,-0.000002),(-0.000001,0.000000),(0.000002,0.000002),(0.000001,0.000000),(-0.000002,0.000002),(0.000000,0.000000),(0.000000,-0.000001),(-0.000002,-0.000001),(0.000000,-0.000001),(-0.000001,0.000001),(0.000001,0.000008),(0.000000,0.000000),(0.000001,-0.000008),(-0.000001,-0.000001),(0.000000,0.000001),(-0.000002,0.000001),(0.000000,0.000001),(0.000000,-0.000000),(-0.000002,-0.000002),(0.000001,-0.000000),(0.000002,-0.000002),(-0.000001,-0.000000),(0.000001,0.000002),(0.000001,-0.000001),(-0.000001,0.000001),(0.000001,-0.000003),(-0.000002,0.000002),(0.000002,0.000002),(0.000004,0.000001),(0.000001,0.000002),(-0.000001,0.000004),(-0.000001,-0.000002),(-0.000002,0.000004),(-0.000001,-0.000000),(-0.000002,-0.000001),(0.000000,0.000001),(-0.000001,-0.000003),(-0.000001,0.000000),(-0.000002,-0.000000),(-0.000000,0.000001),(-0.000000,-0.000000),(-0.000002,-0.000001),(0.000001,-0.000002),(0.000000,0.000000),(-0.000004,0.000004),(-0.000001,0.000000),(0.000001,-0.000000),(-0.000000,0.000001),(0.000000,-0.000001),(-0.000000,-0.000000),(-0.000001,-0.000002),(0.000000,0.000002),(-0.000001,0.000001),(0.000001,-0.000000),(-0.000001,0.000000),(-0.000001,0.000001),(0.000001,0.000002),(-0.000000,0.000000),(-0.000000,-0.000005),(-0.000001,0.000000),(-0.000000,-0.000001),(-0.000000,0.000001),(-0.000003,0.000002),(-0.000003,-0.000003),(0.000000,0.000003),(-0.000000,-0.000007),(-0.000001,-0.000001),(0.000000,-0.000006),(0.000002,0.000002),(-0.000000,-0.000002),(0.000004,-0.000002),(0.000000,-0.000001),(-0.000000,0.000002),(0.000001,-0.000001),(0.000001,0.000001),(0.000000,0.000000),(0.000001,0.000001),(0.000001,0.000001),(0.000000,-0.000001),(-0.000000,-0.000001),(0.000000,0.000001),(-0.000001,-0.000002),(0.000001,-0.000002),(-0.000001,0.000000),(-0.000001,0.000001),(0.000000,-0.000001),(-0.000002,0.000001),(-0.000001,-0.000000),(0.000004,-0.000001),(0.000002,0.000002),(0.000001,0.000001),(0.000001,-0.000001),(-0.000001,-0.000002),(-0.000001,-0.000001),(0.000003,0.000003),(0.000002,0.000002),(-0.000001,-0.000003),(-0.000000,-0.000000),(-0.000001,0.000000),(0.000004,0.000002),(0.000006,0.000001),(0.000001,0.000006),(0.000001,0.000005),(-0.000002,0.000006),(-0.000007,0.000001),(-0.000004,0.000001),(0.000001,0.000002),(0.000000,0.000000),(-0.000005,-0.000003),(-0.000000,-0.000002),(-0.000001,0.000000),(-0.000001,-0.000002),(-0.000000,0.000001),(-0.000002,-0.000001),(-0.000002,0.000000),(0.000000,-0.000001),(-0.000001,-0.000004),(-0.000000,-0.000001),(-0.000001,0.000001),(-0.000001,-0.000000),(0.000001,-0.000002),(0.000001,-0.000002),(0.000001,0.000003),(0.000001,0.000000),(-0.000002,-0.000005),(-0.000000,-0.000001),(-0.000001,-0.000003),(-0.000002,-0.000001),(-0.000000,-0.000000),(-0.000000,0.000000),(-0.000002,0.000000),(-0.000001,-0.000003),(0.000000,-0.000002),(0.000001,-0.000005),(0.000000,-0.000003),(-0.000000,-0.000003),(0.000002,-0.000007),(-0.000000,-0.000006),(0.000019,256.000000),
used:97374875
[IFFT]
(1.000000,0.000000),(1.049083,0.000000),(1.098135,0.000000),(1.147129,-0.000000),(1.196034,-0.000000),(1.244821,-0.000000),(1.293461,0.000000),(1.341924,0.000000),(1.390181,-0.000000),(1.438203,-0.000000),(1.485960,0.000000),(1.533426,0.000000),(1.580569,-0.000000),(1.627363,-0.000000),(1.673780,0.000000),(1.719790,0.000000),(1.765367,0.000000),(1.810483,-0.000000),(1.855110,-0.000000),(1.899223,0.000000),(1.942793,0.000000),(1.985796,-0.000000),(2.028205,0.000000),(2.069995,0.000000),(2.111140,0.000000),(2.151617,-0.000000),(2.191399,-0.000000),(2.230463,-0.000000),(2.268787,-0.000000),(2.306345,-0.000000),(2.343118,-0.000000),(2.379081,0.000000),(2.414214,0.000000),(2.448494,0.000000),(2.481902,-0.000000),(2.514418,-0.000000),(2.546021,0.000000),(2.576693,0.000000),(2.606415,-0.000000),(2.635170,0.000000),(2.662940,-0.000000),(2.689708,-0.000000),(2.715457,-0.000000),(2.740173,-0.000000),(2.763843,-0.000000),(2.786448,-0.000000),(2.807979,-0.000000),(2.828420,0.000000),(2.847759,0.000000),(2.865985,0.000000),(2.883088,-0.000000),(2.899056,-0.000000),(2.913881,0.000000),(2.927552,0.000000),(2.940063,-0.000000),(2.951404,0.000000),(2.961571,-0.000000),(2.970555,-0.000000),(2.978353,-0.000000),(2.984959,-0.000000),(2.990369,-0.000000),(2.994581,-0.000000),(2.997591,-0.000000),(2.999398,0.000000),(3.000000,0.000000),(2.999398,-0.000000),(2.997591,-0.000000),(2.994581,0.000000),(2.990369,-0.000000),(2.984959,0.000000),(2.978353,-0.000000),(2.970555,0.000000),(2.961570,-0.000000),(2.951404,-0.000000),(2.940063,-0.000000),(2.927552,-0.000000),(2.913881,0.000000),(2.899056,0.000000),(2.883088,-0.000000),(2.865986,0.000000),(2.847759,0.000000),(2.828419,-0.000000),(2.807979,-0.000000),(2.786448,0.000000),(2.763843,0.000000),(2.740174,-0.000000),(2.715457,0.000000),(2.689707,0.000000),(2.662939,0.000000),(2.635170,-0.000000),(2.606415,0.000000),(2.576692,0.000000),(2.546021,0.000000),(2.514418,0.000000),(2.481902,0.000000),(2.448494,-0.000000),(2.414214,-0.000000),(2.379081,-0.000000),(2.343118,-0.000000),(2.306346,0.000000),(2.268786,-0.000000),(2.230463,0.000000),(2.191398,-0.000000),(2.151616,0.000000),(2.111140,0.000000),(2.069995,-0.000000),(2.028205,-0.000000),(1.985796,-0.000000),(1.942793,0.000000),(1.899222,-0.000000),(1.855110,0.000000),(1.810483,-0.000000),(1.765367,0.000000),(1.719790,-0.000000),(1.673779,0.000000),(1.627363,0.000000),(1.580570,-0.000000),(1.533425,-0.000000),(1.485960,-0.000000),(1.438202,-0.000000),(1.390180,0.000000),(1.341923,0.000000),(1.293460,-0.000000),(1.244821,0.000000),(1.196034,0.000000),(1.147129,0.000000),(1.098135,-0.000000),(1.049082,-0.000000),(1.000000,0.000000),(0.950917,-0.000000),(0.901865,-0.000000),(0.852871,0.000000),(0.803965,0.000000),(0.755178,0.000000),(0.706539,0.000000),(0.658076,-0.000000),(0.609819,0.000000),(0.561798,0.000000),(0.514039,0.000000),(0.466574,-0.000000),(0.419430,-0.000000),(0.372637,0.000000),(0.326220,0.000000),(0.280210,-0.000000),(0.234633,0.000000),(0.189517,0.000000),(0.144890,-0.000000),(0.100777,0.000000),(0.057207,0.000000),(0.014204,-0.000000),(-0.028206,0.000000),(-0.069995,-0.000000),(-0.111140,-0.000000),(-0.151617,0.000000),(-0.191399,-0.000000),(-0.230463,-0.000000),(-0.268787,-0.000000),(-0.306346,-0.000000),(-0.343118,-0.000000),(-0.379081,-0.000000),(-0.414214,0.000000),(-0.448494,-0.000000),(-0.481902,-0.000000),(-0.514418,-0.000000),(-0.546021,0.000000),(-0.576693,0.000000),(-0.606415,-0.000000),(-0.635170,-0.000000),(-0.662940,0.000000),(-0.689708,0.000000),(-0.715457,0.000000),(-0.740174,-0.000000),(-0.763843,0.000000),(-0.786449,-0.000000),(-0.807979,0.000000),(-0.828420,-0.000000),(-0.847759,0.000000),(-0.865986,-0.000000),(-0.883088,0.000000),(-0.899056,0.000000),(-0.913881,-0.000000),(-0.927552,-0.000000),(-0.940063,0.000000),(-0.951404,-0.000000),(-0.961571,0.000000),(-0.970555,0.000000),(-0.978353,0.000000),(-0.984959,0.000000),(-0.990370,-0.000000),(-0.994581,0.000000),(-0.997591,0.000000),(-0.999398,-0.000000),(-1.000000,0.000000),(-0.999398,0.000000),(-0.997591,0.000000),(-0.994581,-0.000000),(-0.990369,0.000000),(-0.984959,-0.000000),(-0.978353,0.000000),(-0.970555,0.000000),(-0.961570,0.000000),(-0.951404,0.000000),(-0.940063,0.000000),(-0.927552,0.000000),(-0.913881,0.000000),(-0.899056,-0.000000),(-0.883088,0.000000),(-0.865986,0.000000),(-0.847759,0.000000),(-0.828419,0.000000),(-0.807978,0.000000),(-0.786448,-0.000000),(-0.763843,-0.000000),(-0.740174,-0.000000),(-0.715457,-0.000000),(-0.689707,0.000000),(-0.662939,0.000000),(-0.635169,-0.000000),(-0.606415,-0.000000),(-0.576693,0.000000),(-0.546021,-0.000000),(-0.514418,-0.000000),(-0.481902,-0.000000),(-0.448494,-0.000000),(-0.414213,-0.000000),(-0.379081,0.000000),(-0.343118,0.000000),(-0.306346,0.000000),(-0.268786,-0.000000),(-0.230463,0.000000),(-0.191398,-0.000000),(-0.151616,0.000000),(-0.111141,0.000000),(-0.069995,-0.000000),(-0.028205,0.000000),(0.014204,0.000000),(0.057207,0.000000),(0.100778,-0.000000),(0.144890,-0.000000),(0.189517,0.000000),(0.234633,0.000000),(0.280210,-0.000000),(0.326221,-0.000000),(0.372637,-0.000000),(0.419431,-0.000000),(0.466575,0.000000),(0.514040,-0.000000),(0.561798,-0.000000),(0.609819,0.000000),(0.658077,-0.000000),(0.706540,-0.000000),(0.755179,0.000000),(0.803966,0.000000),(0.852871,-0.000000),(0.901865,-0.000000),(0.950918,0.000000),
[KISS IN]
1.000000,1.049083,1.098135,1.147129,1.196034,1.244821,1.293461,1.341924,1.390181,1.438203,1.485960,1.533426,1.580569,1.627363,1.673780,1.719790,1.765367,1.810483,1.855110,1.899223,1.942793,1.985796,2.028205,2.069995,2.111140,2.151617,2.191399,2.230463,2.268787,2.306346,2.343118,2.379081,2.414214,2.448494,2.481902,2.514418,2.546021,2.576693,2.606415,2.635170,2.662939,2.689707,2.715457,2.740174,2.763843,2.786448,2.807979,2.828420,2.847759,2.865986,2.883088,2.899056,2.913881,2.927552,2.940063,2.951404,2.961571,2.970555,2.978353,2.984959,2.990369,2.994581,2.997591,2.999398,3.000000,2.999398,2.997591,2.994581,2.990369,2.984959,2.978353,2.970555,2.961571,2.951404,2.940063,2.927552,2.913881,2.899056,2.883088,2.865986,2.847759,2.828419,2.807979,2.786448,2.763843,2.740174,2.715457,2.689707,2.662939,2.635170,2.606415,2.576693,2.546021,2.514418,2.481902,2.448494,2.414214,2.379081,2.343118,2.306346,2.268786,2.230463,2.191398,2.151616,2.111140,2.069995,2.028205,1.985796,1.942793,1.899223,1.855110,1.810483,1.765367,1.719790,1.673780,1.627363,1.580570,1.533425,1.485960,1.438202,1.390181,1.341924,1.293461,1.244821,1.196034,1.147129,1.098135,1.049082,1.000000,0.950917,0.901865,0.852871,0.803965,0.755178,0.706539,0.658076,0.609819,0.561797,0.514040,0.466574,0.419430,0.372636,0.326220,0.280210,0.234633,0.189517,0.144890,0.100777,0.057206,0.014203,-0.028206,-0.069995,-0.111141,-0.151617,-0.191399,-0.230463,-0.268787,-0.306346,-0.343118,-0.379081,-0.414214,-0.448494,-0.481902,-0.514418,-0.546021,-0.576693,-0.606415,-0.635170,-0.662940,-0.689708,-0.715457,-0.740174,-0.763843,-0.786449,-0.807979,-0.828420,-0.847759,-0.865986,-0.883088,-0.899056,-0.913881,-0.927552,-0.940063,-0.951404,-0.961571,-0.970555,-0.978353,-0.984959,-0.990369,-0.994581,-0.997591,-0.999398,-1.000000,-0.999398,-0.997591,-0.994581,-0.990369,-0.984959,-0.978353,-0.970555,-0.961571,-0.951404,-0.940062,-0.927552,-0.913880,-0.899056,-0.883088,-0.865986,-0.847759,-0.828419,-0.807978,-0.786448,-0.763843,-0.740174,-0.715457,-0.689707,-0.662939,-0.635169,-0.606415,-0.576693,-0.546021,-0.514418,-0.481902,-0.448494,-0.414213,-0.379081,-0.343118,-0.306346,-0.268786,-0.230463,-0.191398,-0.151616,-0.111141,-0.069995,-0.028205,0.014204,0.057207,0.100778,0.144890,0.189517,0.234633,0.280210,0.326221,0.372637,0.419431,0.466575,0.514040,0.561798,0.609820,0.658077,0.706540,0.755179,0.803966,0.852871,0.901865,0.950918,
used:57727425
[KISS FFTR]
(256.000000,0.000000),(0.000015,-255.999985),(-0.000000,0.000006),(0.000001,0.000007),(-0.000000,0.000003),(0.000002,0.000004),(0.000001,0.000005),(-0.000000,0.000001),(-0.000001,0.000003),(-0.000003,-0.000003),(-0.000000,-0.000000),(0.000001,0.000001),(-0.000002,0.000001),(-0.000000,0.000001),(-0.000000,0.000001),(-0.000001,0.000002),(0.000001,-0.000000),(-0.000001,-0.000003),(0.000001,0.000002),(0.000001,0.000001),(-0.000001,0.000000),(0.000000,-0.000001),(-0.000000,0.000001),(-0.000003,0.000005),(0.000000,0.000001),(0.000001,0.000003),(-0.000002,0.000001),(0.000004,-0.000001),(-0.000001,0.000002),(-0.000003,-0.000002),(-0.000000,0.000002),(-0.000003,-0.000001),(0.000000,0.000000),(-0.000001,-0.000008),(-0.000004,-0.000001),(-0.000005,-0.000001),(-0.000002,-0.000006),(-0.000000,-0.000005),(0.000001,-0.000006),(0.000005,-0.000002),(0.000004,-0.000002),(0.000001,0.000002),(-0.000000,0.000000),(-0.000001,0.000002),(0.000002,-0.000002),(0.000002,-0.000003),(-0.000001,0.000001),(-0.000001,0.000002),(0.000001,0.000001),(0.000002,-0.000002),(0.000002,-0.000002),(0.000003,0.000000),(-0.000001,0.000000),(-0.000001,-0.000000),(0.000000,0.000001),(-0.000000,0.000000),(-0.000001,-0.000000),(0.000001,0.000003),(-0.000001,0.000002),(-0.000000,-0.000001),(-0.000000,0.000001),(-0.000001,0.000002),(0.000001,-0.000001),(0.000008,0.000000),(0.000000,-0.000000),(-0.000004,-0.000015),(0.000001,0.000001),(-0.000000,-0.000001),(0.000000,0.000001),(0.000005,0.000002),(-0.000000,0.000002),(-0.000000,-0.000003),(0.000000,0.000006),(-0.000003,-0.000000),(-0.000000,0.000007),(-0.000001,-0.000004),(-0.000003,0.000003),(-0.000003,-0.000003),(-0.000000,-0.000001),(-0.000001,0.000000),(-0.000001,-0.000000),(-0.000001,0.000003),(-0.000000,-0.000000),(0.000000,-0.000000),(-0.000001,-0.000001),(-0.000002,0.000001),(0.000001,0.000000),(0.000001,0.000000),(0.000000,-0.000002),(-0.000001,0.000002),(-0.000000,0.000000),(0.000000,0.000003),(-0.000000,-0.000001),(0.000001,-0.000001),(-0.000001,-0.000000),(-0.000002,0.000001),(0.000000,-0.000000),(0.000003,-0.000003),(-0.000002,0.000001),(0.000001,0.000002),(-0.000000,-0.000001),(-0.000002,0.000000),(-0.000001,-0.000000),(-0.000001,0.000003),(0.000000,-0.000001),(0.000000,0.000000),(-0.000001,0.000000),(-0.000003,-0.000004),(-0.000001,0.000002),(-0.000001,-0.000005),(0.000001,-0.000002),(0.000003,-0.000002),(0.000002,-0.000002),(0.000003,-0.000002),(0.000001,0.000003),(0.000000,-0.000002),(0.000001,0.000001),(0.000003,-0.000001),(-0.000001,0.000000),(0.000002,0.000002),(0.000001,0.000000),(0.000001,0.000002),(0.000000,0.000000),(-0.000002,-0.000001),(-0.000002,-0.000001),(0.000000,-0.000001),(-0.000001,0.000001),(-0.000008,0.000000),(0.000000,0.000000),
used:58225225
[KISS FFTRI]
255.999969,268.565186,281.122650,293.665039,306.184753,318.674286,331.125916,343.532471,355.886292,368.179901,380.405823,392.556885,404.625732,416.605042,428.487549,440.266174,451.933868,463.483582,474.908142,486.200928,497.355133,508.363831,519.220520,529.918701,540.451904,550.813782,560.997925,570.998535,580.809387,590.424561,599.838135,609.044678,618.038696,626.814575,635.366943,643.690857,651.781311,659.633423,667.242188,674.603333,681.712524,688.565063,695.156982,701.484375,707.543701,713.330811,718.842407,724.075378,729.026245,733.692322,738.070496,742.158325,745.953430,749.453369,752.655884,755.559448,758.161987,760.462097,762.458313,764.149475,765.534485,766.612671,767.383240,767.845764,768.000061,767.845825,767.383240,766.612610,765.534546,764.149536,762.458313,760.462097,758.161987,755.559448,752.655945,749.453308,745.953430,742.158447,738.070435,733.692261,729.026306,724.075317,718.842407,713.330811,707.543701,701.484619,695.156982,688.565002,681.712402,674.603333,667.242188,659.633240,651.781433,643.690857,635.366943,626.814453,618.038696,609.044739,599.838135,590.424438,580.809326,570.998535,560.997925,550.813843,540.451904,529.918701,519.220459,508.363800,497.355133,486.200928,474.908203,463.483582,451.933838,440.266205,428.487549,416.604980,404.625854,392.556915,380.405853,368.179779,355.886230,343.532410,331.125885,318.674316,306.184784,293.664948,281.122589,268.565155,255.999939,243.434799,230.877350,218.334961,205.815186,193.325592,180.874100,168.467499,156.113663,143.820160,131.594131,119.443008,107.374207,95.394958,83.512375,71.733780,60.066132,48.516418,37.091751,25.798996,14.644867,3.636124,-7.220596,-17.918610,-28.451874,-38.813828,-48.997955,-58.998550,-68.809402,-78.424576,-87.838135,-97.044708,-106.038696,-114.814484,-123.366913,-131.690857,-139.781311,-147.633423,-155.242157,-162.603455,-169.712494,-176.565079,-183.156921,-189.484406,-195.543671,-201.330917,-206.842438,-212.075378,-217.026337,-221.692337,-226.070511,-230.158325,-233.953430,-237.453339,-240.655884,-243.559464,-246.161987,-248.462097,-250.458313,-252.149521,-253.534592,-254.612732,-255.383240,-255.845779,-256.000061,-255.845795,-255.383240,-254.612656,-253.534607,-252.149506,-250.458313,-248.462097,-246.161987,-243.559418,-240.655945,-237.453308,-233.953430,-230.158417,-226.070480,-221.692230,-217.026306,-212.075287,-206.842346,-201.330719,-195.543671,-189.484589,-183.156982,-176.564941,-169.712372,-162.603271,-155.242188,-147.633316,-139.781448,-131.690857,-123.366913,-114.814453,-106.038574,-97.044754,-87.838150,-78.424438,-68.809326,-58.998535,-48.997925,-38.813690,-28.451935,-17.918747,-7.220551,3.636200,14.644928,25.799118,37.091919,48.516373,60.066147,71.733856,83.512451,95.395035,107.374390,119.443268,131.594086,143.820190,156.113754,168.467606,180.874115,193.325806,205.815338,218.334991,230.877350,243.434906,
256点 1000次,用时如下
复数fft 复数ifft
105119450ns 97374875ns
实数fft 实数ifft
57727425ns 58225225ns
所以一次实数fft计算大概在58uS左右。
对比上面提到的MCU平台,快了5倍以上
如果按照-O3编译
$CC kissfft/*.c kiss_fft_port.c kissfft_test.c -I. -Ikissfft -o kissfft_test -lm -O3
则
复数fft 复数ifft
19674850ns 19976350ns
实数fft 实数ifft
15674675ns 15648700ns
则一次实数fft计算大概在16uS左右,大概是不优化的1/4。
速度是上述MCU平台的17倍。
-
发表了主题帖:
【米尔-STM32MP257开发板试用体验】基于alsa的音频应用开发
基于alsa的音频应用开发
获取音频设备驱动信息与录放音测试
设备信息
查看音频设备信息,如下有两个
cat /proc/asound/cards
0 [ES8388SOUNDCARD]: simple-card - ES8388-SOUND-CARD
ES8388-SOUND-CARD
1 [HDMISOUNDCARD ]: HDMI-SOUND-CARD - HDMI-SOUND-CARD
HDMI-SOUND-CARD
root@myd-ld25x:/etc/myir_test#
查看音频设备文件
ls /dev/snd/ -al
total 0
drwxr-xr-x 3 root root 200 3月 3 18:10 .
drwxr-xr-x 17 root root 4680 3月 3 18:10 ..
drwxr-xr-x 2 root root 80 3月 3 18:10 by-path
crw-rw---- 1 root audio 116, 4 3月 3 18:10 controlC0
crw-rw---- 1 root audio 116, 7 3月 3 18:10 controlC1
crw-rw---- 1 root audio 116, 3 3月 3 18:10 pcmC0D0c
crw-rw---- 1 root audio 116, 2 3月 3 18:10 pcmC0D0p
crw-rw---- 1 root audio 116, 6 3月 3 18:10 pcmC1D0c
crw-rw---- 1 root audio 116, 5 3月 3 18:10 pcmC1D0p
crw-rw---- 1 root audio 116, 33 3月 3 18:10 timer
所以声卡0对应ES8388,
controlC0为ES8388声卡控制
pcmC0D0c读该文件对应ES8388声卡采集 后缀c表示capture
pcmC0D0p写该文件对应ES8388声卡播放 后缀p表示playback
测试
先进行录音播放测试,确认硬件OK。
连接带MIC的耳机。
播放,确认耳机能听到音乐。
cd /etc/myir_test/
./myir_audio_play
ctrl+c退出
录音
amixer -c 0 set "Capture ZC" on
amixer -c 0 set "Capture Digital" 120
arecord -D hw:0,0 -f cd test.wav
Ctrl+c停止录音
aplay -D hw:0,0 test.wav
声卡读写
使用alsa库,参考
https://www.alsa-project.org/alsa-doc/alsa-lib/index.html
查看sdk中asoundlib.h头文件位置
qinyunti@qinyunti:~$ find /opt/st/myd-ld25x/4.2.4-snapshot/ -name asoundlib.h
find: ‘/opt/st/myd-ld25x/4.2.4-snapshot/sysroots/cortexa35-ostl-linux/etc/polkit-1/rules.d’: Permission denied
find: ‘/opt/st/myd-ld25x/4.2.4-snapshot/sysroots/cortexa35-ostl-linux/etc/cups/ssl’: Permission denied
find: ‘/opt/st/myd-ld25x/4.2.4-snapshot/sysroots/cortexa35-ostl-linux/var/spool/cups’: Permission denied
find: ‘/opt/st/myd-ld25x/4.2.4-snapshot/sysroots/cortexa35-ostl-linux/var/cache/cups’: Permission denied
find: ‘/opt/st/myd-ld25x/4.2.4-snapshot/sysroots/cortexa35-ostl-linux/var/lib/tee’: Permission denied
find: ‘/opt/st/myd-ld25x/4.2.4-snapshot/sysroots/cortexa35-ostl-linux/var/lib/sudo’: Permission denied
find: ‘/opt/st/myd-ld25x/4.2.4-snapshot/sysroots/cortexa35-ostl-linux/home/root’: Permission denied
find: ‘/opt/st/myd-ld25x/4.2.4-snapshot/sysroots/cortexa35-ostl-linux/usr/share/polkit-1/rules.d’: Permission denied
/opt/st/myd-ld25x/4.2.4-snapshot/sysroots/cortexa35-ostl-linux/usr/include/alsa/asoundlib.h
/opt/st/myd-ld25x/4.2.4-snapshot/sysroots/cortexa35-ostl-linux/usr/include/asoundlib.h
/opt/st/myd-ld25x/4.2.4-snapshot/sysroots/cortexa35-ostl-linux/usr/include/sys/asoundlib.h
qinyunti@qinyunti:~$
查看板子上lib文件的位置
root@myd-ld25x:/etc/myir_test# find / -name libasound.so.*
/usr/lib/libasound.so.2
/usr/lib/libasound.so.2.0.0
root@myd-ld25x:/etc/myir_test#
Alsa应用程序开发
新建alsa_test.c文件,内容如下
/*
* This extra small demo sends a random samples to your speakers.
*/
#include <alsa/asoundlib.h>
static char *device = "default"; /* playback device */
unsigned char buffer[16*1024]; /* some random data */
int main(void)
{
int err;
unsigned int i;
snd_pcm_t *handle;
snd_pcm_sframes_t frames;
for (i = 0; i < sizeof(buffer); i++)
buffer[i] = random() & 0xff;
if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
printf("Playback open error: %s\n", snd_strerror(err));
exit(EXIT_FAILURE);
}
if ((err = snd_pcm_set_params(handle,
SND_PCM_FORMAT_U8,
SND_PCM_ACCESS_RW_INTERLEAVED,
1,
48000,
1,
500000)) < 0) { /* 0.5sec */
printf("Playback open error: %s\n", snd_strerror(err));
exit(EXIT_FAILURE);
}
for (i = 0; i < 16; i++) {
frames = snd_pcm_writei(handle, buffer, sizeof(buffer));
if (frames < 0)
frames = snd_pcm_recover(handle, frames, 0);
if (frames < 0) {
printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
break;
}
if (frames > 0 && frames < (long)sizeof(buffer))
printf("Short write (expected %li, wrote %li)\n", (long)sizeof(buffer), frames);
}
/* pass the remaining samples, otherwise they're dropped in close */
err = snd_pcm_drain(handle);
if (err < 0)
printf("snd_pcm_drain failed: %s\n", snd_strerror(err));
snd_pcm_close(handle);
return 0;
}
编译
$CC alsa_test.c -o alsa_test -lasound
Cp到win下
cp alsa_test /mnt/d/
Win下使用crt,rz导入到开发板
chmod +x alsa_test
./alsa_test 运行
此时耳机播放的是噪声,随机数。
总结
得益于官方提供了完整的SDK开发环境,以及板子极影部署了alsa,所以基于alsa进行音频开发变得很简单,这一篇先进行了简单的开发过程体验,后面来实现音频的采集与播放,为后面的音频试试处理算法应用demo做准备。
-
发表了主题帖:
【米尔-STM32MP257开发板试用体验】C应用开发环境搭建
本帖最后由 qinyunti 于 2025-4-3 11:03 编辑
准备
供电,Type-C USB供电
Boot模式选择EMMC B3 B2 B1 B0 0010
连接串口
使用串口终端连接
115200--8-n-1
输入root登录
一.应用编译环境
我这里使用WSL+Ubuntu
下载的03-Tools.zip下解压Compile Toolchain/myir-image-full-openstlinux-weston-myd-ld25x-x86_64-toolchain-4.2.4-snapshot.sh
./myir-image-full-openstlinux-weston-myd-ld25x-x86_64-toolchain-4.2.4-snapshot.sh
指定路径回车默认
输入y
每次使用初始化环境
source /opt/st/myd-ld25x/4.2.4-snapshot/environment-setup-cortexa35-ostl-linux
查看 $CC和$XCC
qinyunti@qinyunti:~$ echo $CC
aarch64-ostl-linux-gcc -mcpu=cortex-a35 -march=armv8-a+crc -mbranch-protection=standard --sysroot=/opt/st/myd-ld25x/4.2.4-snapshot/sysroots/cortexa35-ostl-linux
qinyunti@qinyunti:~$ echo $CXX
aarch64-ostl-linux-g++ -mcpu=cortex-a35 -march=armv8-a+crc -mbranch-protection=standard --sysroot=/opt/st/myd-ld25x/4.2.4-snapshot/sysroots/cortexa35-ostl-linux
qinyunti@qinyunti:~$
二.HelloWorld
mkdir ld25x
cd ld25x/
nano helloworld.c
输入
#include <stdio.h>
int main(void){
printf("Hello World\r\n");
return 0;
}
ctrl+o回车保存
ctrl+x退出
编译
$CC helloworld.c -o helloworld
导出到win下
cp helloworld /mnt/d
Win下使用crt登录终端
rz导入helloworld文件
chmod +x helloworld
运行
三.总结
以上简单分享下交叉编译环境搭建,与c程序编译执行测试。为后面开发做准备。
- 2025-04-01
-
回复了主题帖:
【国民技术高性能MCU N32H487开发板】软件fft性能测试
秦天qintian0303 发表于 2025-4-1 11:55
H4的主频是多大?
240MHz
-
发表了主题帖:
【国民技术高性能MCU N32H487开发板】音频实时处理应用_回声消除与降噪
前言
前面我们准备好了环境,移植好了文件系统,方便进行文件的导入导出以及操作。现在就来评估基于N32H487的音频实时处理应用。目前还未搭建好音频的采集与播放通道,所以暂时通过文件系统的wav音频文件作为输入输出,重点验证音频处理算法的执行时间,是否能满足实时处理要求。
代码见:https://github.com/qinyunti/N32H487.git
Speex移植
Speex的移植可以参考公众号文章
https://mp.weixin.qq.com/s/zJPNgyOaKNpIbHfshe6CjQ
https://mp.weixin.qq.com/s/-nRwGWvYfl6wtvFSSul1DQ
https://mp.weixin.qq.com/s/p6cOppuoFYCTw6a-bu299Q
代码如下
添加头文件包含路径
定义宏
HAVE_CONFIG_H
os_support_custom.h中实现malloc,free和打印接口
math_approx.h中实现math函数
测试
这里准备了两个wav文件spk.wav表示回采的远程音频数据,mic.wav是本地采集的mic音频数据(包含了本地声音和远程说话声)。
测试代码见
speexecho.c
shell_func.c中添加命令行
static void speexfunc(uint8_t* param);
{ (uint8_t*)"speex", speexfunc, (uint8_t*)"speex mic spk out"},
extern int speex_main(int argc, char **argv);
void speexfunc(uint8_t* param)
{
char* cmd = "speex";
char mic[32];
char spk[32];
char out[32];
char* argv[4]={cmd,mic,spk,out};
if(3 == sscanf((const char*)param, "%*s %s %s %s", mic, spk, out))
{
xprintf("speex %s %s %S\r\n",mic, spk, out);
speex_main(4, argv);
}
}
导入mic.wav spk.wav
堆先设置大一点,后面再去确认消耗量
执行
speex 0:/mic.wav 0:/spk.wav 0:/out.wav
NN=256 TAIL=1024
最大执行时间为15mS左右。
生成out.wav如下
导出out.wav
查看输出的文件,可以看到降噪效果明显,回声消除效果有不是很好,因为输入文件的质量不是很好,spk没有处于线性范围,需要调整spk和mic的音量范围最好相当,并且要保证同步性。
再测量其他配置
config.h中
//#define FIXED_POINT
#define FLOATING_POINT
修改使用浮点还是固定点
浮点/定点
NN
TAIL
时间
浮点
256
1024
14~15mS
256
512
12~13mS
128
1024
8~9ms
128
512
7~8mS
定点
256
1024
14~15mS
256
512
12~13mS
128
1024
8~9mS
128
512
7~8mS
对于16k,256个点,时间为16ms,算法时间需要15ms,所以基本满足不了
确认堆消耗量
参考
os_support_custom.c记录malloc和free的数量,确定最大消耗量
执行完后打印消耗堆信息
uint32_t curused;
uint32_t maxused;
speex_heap_info(&curused, &maxused);
xprintf("heap used max:%d cur:%d\r\n",maxused,curused);
NN
TAIL
最大堆使用
256
1024
73090
256
512
64894
128
1024
45962
128
512
37762
总结
N32H487有RAM192KB,在典型应用256点,滤波时间1024点时消耗73090B.对于SPK,MIC采集同步的,TAIL无需1024点,512点就足够此时RAM只需要,要减小RAM使用还可以一次处理点数NN减少,根据实际减小TAIL。
对于8k采样,256点时间为32mS,算法需要的执行时间14~15ms,占50%不到,还有一半以上时间可以处理其他业务,所以可以实现实时处理。
以上测试结果看出,得益于较高的性能和资源,在N32H487上也可以实现音频的实时处理。
- 2025-03-31
-
发表了主题帖:
【国民技术高性能MCU N32H487开发板】软件fft性能测试
前言
后面移植音频处理算法需要大量调用fft算法,由于没有硬件fft模块,只能使用软件进行计算。其执行时间影响音频算法是否能实时处理,所以我们先来进行实测,评估fft执行时间。
代码见
https://github.com/qinyunti/N32H487.git
移植kissfft
Kissfft是常用的fft实现库,后面的音频算法中也会使用,所以基于该库进行测试。
添加代码,并设置对应的头文件包含路径
需要实现
kiss_fft_port.c中的kiss_fft_port_malloc和
kiss_fft_port_free
这里使用库自带的malloc和free,配置startup_n32h487.s中
Heap_Size EQU 0x00000200大一点为
Heap_Size EQU 0x00004000
kiss_fft_port.c中
#include <stddef.h>
#include <stdlib.h>
void* kiss_fft_port_malloc(size_t size)
{
return malloc(size);
}
void kiss_fft_port_free(void* p)
{
free(p);
}
测试
shell_func.c中添加命令
#include "kissfft_test.h"
static void ffttestfunc(uint8_t* param);
{ (uint8_t*)"ffttest", ffttestfunc, (uint8_t*)"ffttest nfft cnt"},
void ffttestfunc(uint8_t* param)
{
int cnt;
int nfft;
if(2 == sscanf((const char*)param, "%*s %d %d", &nfft, &cnt))
{
kiss_fft_test_cpx(nfft, cnt);
kiss_fft_test_real(nfft, cnt);
}
}
输入ffttest 256 1000回车
打印如下
[in]
(1.000000,0.000000),(1.049083,0.000000),(1.098135,0.000000),(1.147129,0.000000),(1.196034,0.000000),(1.244821,0.000000),(1.293461,0.000000),(1.341924,0.000000),(1.390181,0.000000),(1.438203,0.000000),(1.485960,0.000000),(1.533426,0.000000),(1.580569,0.000000),(1.627363,0.000000),(1.673780,0.000000),(1.719790,0.000000),(1.765367,0.000000),(1.810483,0.000000),(1.855110,0.000000),(1.899223,0.000000),(1.942793,0.000000),(1.985796,0.000000),(2.028205,0.000000),(2.069995,0.000000),(2.111140,0.000000),(2.151616,0.000000),(2.191399,0.000000),(2.230463,0.000000),(2.268787,0.000000),(2.306346,0.000000),(2.343118,0.000000),(2.379081,0.000000),(2.414214,0.000000),(2.448494,0.000000),(2.481902,0.000000),(2.514418,0.000000),(2.546021,0.000000),(2.576693,0.000000),(2.606415,0.000000),(2.635170,0.000000),(2.662939,0.000000),(2.689707,0.000000),(2.715457,0.000000),(2.740174,0.000000),(2.763843,0.000000),(2.786448,0.000000),(2.807979,0.000000),(2.828420,0.000000),(2.847759,0.000000),(2.865986,0.000000),(2.883088,0.000000),(2.899056,0.000000),(2.913881,0.000000),(2.927552,0.000000),(2.940063,0.000000),(2.951404,0.000000),(2.961571,0.000000),(2.970555,0.000000),(2.978353,0.000000),(2.984959,0.000000),(2.990369,0.000000),(2.994581,0.000000),(2.997591,0.000000),(2.999398,0.000000),(3.000000,0.000000),(2.999398,0.000000),(2.997591,0.000000),(2.994581,0.000000),(2.990369,0.000000),(2.984959,0.000000),(2.978353,0.000000),(2.970555,0.000000),(2.961571,0.000000),(2.951404,0.000000),(2.940063,0.000000),(2.927552,0.000000),(2.913881,0.000000),(2.899056,0.000000),(2.883088,0.000000),(2.865986,0.000000),(2.847759,0.000000),(2.828419,0.000000),(2.807979,0.000000),(2.786448,0.000000),(2.763842,0.000000),(2.740174,0.000000),(2.715457,0.000000),(2.689707,0.000000),(2.662939,0.000000),(2.635170,0.000000),(2.606415,0.000000),(2.576693,0.000000),(2.546021,0.000000),(2.514418,0.000000),(2.481902,0.000000),(2.448494,0.000000),(2.414214,0.000000),(2.379081,0.000000),(2.343118,0.000000),(2.306346,0.000000),(2.268786,0.000000),(2.230463,0.000000),(2.191398,0.000000),(2.151616,0.000000),(2.111140,0.000000),(2.069995,0.000000),(2.028205,0.000000),(1.985796,0.000000),(1.942793,0.000000),(1.899223,0.000000),(1.855110,0.000000),(1.810483,0.000000),(1.765367,0.000000),(1.719790,0.000000),(1.673780,0.000000),(1.627363,0.000000),(1.580569,0.000000),(1.533425,0.000000),(1.485960,0.000000),(1.438202,0.000000),(1.390181,0.000000),(1.341924,0.000000),(1.293461,0.000000),(1.244821,0.000000),(1.196034,0.000000),(1.147129,0.000000),(1.098135,0.000000),(1.049082,0.000000),(1.000000,0.000000),(0.950917,0.000000),(0.901865,0.000000),(0.852871,0.000000),(0.803965,0.000000),(0.755178,0.000000),(0.706539,0.000000),(0.658076,0.000000),(0.609819,0.000000),(0.561797,0.000000),(0.514040,0.000000),(0.466574,0.000000),(0.419430,0.000000),(0.372636,0.000000),(0.326220,0.000000),(0.280210,0.000000),(0.234633,0.000000),(0.189517,0.000000),(0.144890,0.000000),(0.100777,0.000000),(0.057206,0.000000),(0.014203,0.000000),(-0.028206,0.000000),(-0.069995,0.000000),(-0.111141,0.000000),(-0.151617,0.000000),(-0.191399,0.000000),(-0.230463,0.000000),(-0.268787,0.000000),(-0.306346,0.000000),(-0.343118,0.000000),(-0.379081,0.000000),(-0.414214,0.000000),(-0.448494,0.000000),(-0.481902,0.000000),(-0.514418,0.000000),(-0.546021,0.000000),(-0.576693,0.000000),(-0.606415,0.000000),(-0.635170,0.000000),(-0.662939,0.000000),(-0.689707,0.000000),(-0.715457,0.000000),(-0.740174,0.000000),(-0.763842,0.000000),(-0.786449,0.000000),(-0.807979,0.000000),(-0.828420,0.000000),(-0.847759,0.000000),(-0.865986,0.000000),(-0.883088,0.000000),(-0.899056,0.000000),(-0.913881,0.000000),(-0.927552,0.000000),(-0.940063,0.000000),(-0.951404,0.000000),(-0.961571,0.000000),(-0.970555,0.000000),(-0.978353,0.000000),(-0.984959,0.000000),(-0.990370,0.000000),(-0.994581,0.000000),(-0.997591,0.000000),(-0.999398,0.000000),(-1.000000,0.000000),(-0.999398,0.000000),(-0.997591,0.000000),(-0.994581,0.000000),(-0.990369,0.000000),(-0.984959,0.000000),(-0.978353,0.000000),(-0.970555,0.000000),(-0.961571,0.000000),(-0.951404,0.000000),(-0.940062,0.000000),(-0.927552,0.000000),(-0.913881,0.000000),(-0.899056,0.000000),(-0.883088,0.000000),(-0.865986,0.000000),(-0.847759,0.000000),(-0.828419,0.000000),(-0.807978,0.000000),(-0.786448,0.000000),(-0.763842,0.000000),(-0.740174,0.000000),(-0.715457,0.000000),(-0.689707,0.000000),(-0.662939,0.000000),(-0.635169,0.000000),(-0.606415,0.000000),(-0.576693,0.000000),(-0.546021,0.000000),(-0.514418,0.000000),(-0.481902,0.000000),(-0.448494,0.000000),(-0.414213,0.000000),(-0.379081,0.000000),(-0.343118,0.000000),(-0.306346,0.000000),(-0.268786,0.000000),(-0.230463,0.000000),(-0.191398,0.000000),(-0.151616,0.000000),(-0.111141,0.000000),(-0.069995,0.000000),(-0.028205,0.000000),(0.014204,0.000000),(0.057207,0.000000),(0.100778,0.000000),(0.144890,0.000000),(0.189517,0.000000),(0.234633,0.000000),(0.280210,0.000000),(0.326221,0.000000),(0.372637,0.000000),(0.419431,0.000000),(0.466575,0.000000),(0.514040,0.000000),(0.561798,0.000000),(0.609820,0.000000),(0.658077,0.000000),(0.706540,0.000000),(0.755179,0.000000),(0.803966,0.000000),(0.852871,0.000000),(0.901865,0.000000),(0.950918,0.000000),
used:424
[FFT]
(256.000000,0.000000),(0.000019,-255.999985),(0.000000,0.000007),(0.000001,0.000009),(0.000001,0.000002),(0.000001,-0.000001),(-0.000001,0.000005),(0.000001,0.000005),(0.000000,0.000001),(-0.000004,0.000001),(0.000001,-0.000001),(0.000000,-0.000004),(-0.000002,0.000002),(0.000000,0.000006),(-0.000000,0.000001),(-0.000003,0.000005),(0.000002,0.000001),(0.000004,-0.000005),(-0.000001,0.000000),(0.000000,0.000002),(-0.000001,0.000002),(-0.000001,-0.000001),(0.000000,0.000001),(-0.000001,0.000002),(-0.000001,0.000000),(-0.000000,0.000000),(-0.000002,0.000001),(-0.000002,0.000001),(-0.000001,0.000001),(-0.000000,-0.000002),(-0.000001,0.000001),(-0.000005,0.000001),(0.000000,0.000000),(-0.000001,0.000001),(-0.000004,-0.000001),(-0.000005,-0.000002),(-0.000002,-0.000005),(0.000002,-0.000004),(0.000002,-0.000007),(0.000006,-0.000001),(0.000003,0.000000),(-0.000001,0.000001),(-0.000001,-0.000000),(0.000001,0.000001),(0.000002,-0.000002),(0.000002,-0.000001),(0.000000,0.000001),(-0.000001,0.000000),(0.000000,0.000001),(0.000002,0.000000),(0.000002,-0.000001),(0.000002,0.000000),(-0.000001,0.000000),(-0.000002,-0.000001),(-0.000001,0.000000),(-0.000000,-0.000000),(-0.000000,-0.000000),(0.000001,0.000001),(0.000001,0.000002),(-0.000001,0.000000),(-0.000001,0.000001),(-0.000000,-0.000001),(0.000000,-0.000001),(0.000006,0.000000),(0.000000,0.000000),(-0.000002,0.000000),(0.000001,0.000001),(0.000001,-0.000001),(-0.000001,-0.000000),(0.000003,0.000001),(0.000000,0.000002),(0.000002,-0.000002),(0.000000,0.000005),(-0.000002,0.000002),(-0.000000,0.000008),(0.000002,-0.000004),(-0.000002,0.000003),(-0.000002,-0.000001),(0.000001,-0.000001),(-0.000003,0.000000),(0.000000,-0.000001),(0.000001,0.000003),(-0.000001,-0.000000),(0.000000,-0.000002),(-0.000000,-0.000001),(-0.000000,-0.000000),(-0.000001,0.000001),(-0.000001,-0.000000),(-0.000000,-0.000002),(-0.000001,0.000001),(-0.000001,-0.000001),(-0.000000,0.000000),(-0.000000,-0.000001),(0.000001,-0.000000),(-0.000001,-0.000001),(0.000001,0.000000),(0.000000,0.000000),(-0.000003,0.000000),(-0.000000,0.000001),(-0.000000,-0.000000),(0.000000,-0.000000),(-0.000001,0.000000),(-0.000001,-0.000000),(-0.000001,0.000003),(0.000001,0.000000),(-0.000001,0.000001),(-0.000002,0.000000),(-0.000003,-0.000003),(-0.000002,0.000001),(-0.000001,-0.000004),(0.000000,-0.000002),(0.000001,-0.000005),(0.000002,-0.000001),(0.000001,0.000001),(0.000001,0.000002),(0.000000,-0.000001),(-0.000000,0.000000),(0.000000,-0.000001),(0.000000,-0.000001),(0.000002,0.000001),(0.000000,0.000001),(-0.000002,0.000001),(0.000001,0.000000),(0.000001,-0.000000),(-0.000001,-0.000000),(-0.000000,-0.000000),(-0.000001,0.000000),(0.000000,0.000015),(0.000000,0.000000),(0.000000,-0.000015),(-0.000001,-0.000000),(-0.000000,0.000000),(-0.000001,0.000000),(0.000001,0.000000),(0.000001,-0.000000),(-0.000002,-0.000001),(0.000000,-0.000001),(0.000002,-0.000001),(0.000000,0.000001),(0.000000,0.000001),(-0.000000,-0.000000),(0.000000,0.000001),(0.000001,-0.000002),(0.000001,-0.000001),(0.000002,0.000001),(0.000001,0.000005),(0.000000,0.000002),(-0.000001,0.000004),(-0.000002,-0.000001),(-0.000003,0.000003),(-0.000002,-0.000000),(-0.000001,-0.000001),(0.000001,-0.000000),(-0.000001,-0.000003),(-0.000001,0.000000),(-0.000001,-0.000000),(0.000000,0.000000),(-0.000000,0.000000),(-0.000000,-0.000001),(-0.000003,-0.000000),(0.000000,0.000000),(0.000001,-0.000000),(-0.000001,0.000001),(0.000001,0.000000),(-0.000000,0.000001),(-0.000000,-0.000000),(-0.000001,0.000001),(-0.000001,-0.000001),(-0.000000,0.000002),(-0.000001,0.000000),(-0.000001,-0.000001),(-0.000000,0.000000),(-0.000000,0.000001),(0.000000,0.000002),(-0.000001,0.000000),(0.000001,-0.000003),(0.000000,0.000001),(-0.000003,-0.000000),(0.000001,0.000001),(-0.000002,0.000001),(-0.000002,-0.000003),(0.000002,0.000004),(-0.000000,-0.000008),(-0.000002,-0.000002),(0.000000,-0.000005),(0.000002,0.000002),(0.000000,-0.000002),(0.000003,-0.000001),(-0.000001,0.000000),(0.000001,0.000001),(0.000001,-0.000001),(-0.000002,-0.000000),(0.000000,0.000000),(0.000006,-0.000000),(0.000000,0.000001),(-0.000000,0.000001),(-0.000001,-0.000001),(-0.000001,-0.000000),(0.000001,-0.000002),(0.000001,-0.000001),(-0.000000,0.000000),(-0.000000,0.000000),(-0.000001,-0.000000),(-0.000002,0.000001),(-0.000001,-0.000000),(0.000002,-0.000000),(0.000002,0.000001),(0.000002,-0.000000),(0.000000,-0.000001),(-0.000001,-0.000000),(0.000000,-0.000001),(0.000002,0.000001),(0.000002,0.000002),(0.000001,-0.000001),(-0.000001,0.000000),(-0.000001,-0.000001),(0.000003,-0.000000),(0.000006,0.000001),(0.000002,0.000007),(0.000002,0.000004),(-0.000002,0.000005),(-0.000005,0.000002),(-0.000004,0.000001),(-0.000001,-0.000001),(0.000000,0.000000),(-0.000005,-0.000001),(-0.000001,-0.000001),(-0.000000,0.000002),(-0.000001,-0.000001),(-0.000002,-0.000001),(-0.000002,-0.000001),(-0.000000,-0.000000),(-0.000001,-0.000000),(-0.000001,-0.000002),(0.000000,-0.000001),(-0.000001,0.000001),(-0.000001,-0.000002),(0.000000,-0.000002),(-0.000001,-0.000000),(0.000004,0.000005),(0.000002,-0.000001),(-0.000003,-0.000005),(-0.000000,-0.000001),(0.000000,-0.000006),(-0.000002,-0.000002),(0.000000,0.000004),(0.000001,0.000001),(-0.000004,-0.000001),(0.000000,-0.000001),(0.000001,-0.000005),(-0.000001,-0.000005),(0.000001,0.000001),(0.000001,-0.000002),(0.000001,-0.000009),(0.000000,-0.000007),(0.000019,255.999985),
used:419
[IFFT]
(1.000000,0.000000),(1.049083,-0.000000),(1.098135,0.000000),(1.147129,0.000000),(1.196034,-0.000000),(1.244821,0.000000),(1.293461,0.000000),(1.341924,-0.000000),(1.390181,-0.000000),(1.438202,-0.000000),(1.485960,0.000000),(1.533426,-0.000000),(1.580570,0.000000),(1.627363,-0.000000),(1.673780,0.000000),(1.719790,-0.000000),(1.765367,0.000000),(1.810483,-0.000000),(1.855110,0.000000),(1.899222,0.000000),(1.942793,-0.000000),(1.985796,-0.000000),(2.028205,-0.000000),(2.069995,0.000000),(2.111140,0.000000),(2.151616,-0.000000),(2.191399,0.000000),(2.230463,0.000000),(2.268787,0.000000),(2.306345,0.000000),(2.343118,0.000000),(2.379081,-0.000000),(2.414214,0.000000),(2.448494,-0.000000),(2.481902,-0.000000),(2.514418,0.000000),(2.546021,-0.000000),(2.576693,0.000000),(2.606415,0.000000),(2.635169,-0.000000),(2.662939,-0.000000),(2.689707,0.000000),(2.715457,-0.000000),(2.740173,-0.000000),(2.763843,-0.000000),(2.786448,0.000000),(2.807979,-0.000000),(2.828419,-0.000000),(2.847759,0.000000),(2.865985,0.000000),(2.883088,0.000000),(2.899056,-0.000000),(2.913881,0.000000),(2.927552,0.000000),(2.940063,-0.000000),(2.951404,0.000000),(2.961571,-0.000000),(2.970555,-0.000000),(2.978353,-0.000000),(2.984959,0.000000),(2.990369,0.000000),(2.994581,0.000000),(2.997591,-0.000000),(2.999398,0.000000),(3.000000,0.000000),(2.999398,0.000000),(2.997591,-0.000000),(2.994581,0.000000),(2.990369,-0.000000),(2.984959,0.000000),(2.978353,-0.000000),(2.970555,0.000000),(2.961571,0.000000),(2.951404,-0.000000),(2.940063,-0.000000),(2.927552,-0.000000),(2.913881,-0.000000),(2.899056,0.000000),(2.883088,-0.000000),(2.865985,0.000000),(2.847759,0.000000),(2.828419,0.000000),(2.807979,-0.000000),(2.786448,0.000000),(2.763842,0.000000),(2.740174,0.000000),(2.715457,-0.000000),(2.689707,0.000000),(2.662939,-0.000000),(2.635169,-0.000000),(2.606415,0.000000),(2.576692,-0.000000),(2.546021,0.000000),(2.514417,0.000000),(2.481902,-0.000000),(2.448494,0.000000),(2.414214,-0.000000),(2.379081,0.000000),(2.343118,-0.000000),(2.306346,-0.000000),(2.268786,-0.000000),(2.230463,-0.000000),(2.191399,-0.000000),(2.151616,0.000000),(2.111140,-0.000000),(2.069995,-0.000000),(2.028205,-0.000000),(1.985796,-0.000000),(1.942793,0.000000),(1.899222,-0.000000),(1.855110,-0.000000),(1.810483,0.000000),(1.765367,0.000000),(1.719790,-0.000000),(1.673779,0.000000),(1.627363,0.000000),(1.580569,0.000000),(1.533425,-0.000000),(1.485960,0.000000),(1.438202,-0.000000),(1.390180,-0.000000),(1.341923,0.000000),(1.293460,-0.000000),(1.244821,-0.000000),(1.196034,-0.000000),(1.147129,0.000000),(1.098135,-0.000000),(1.049082,0.000000),(1.000000,0.000000),(0.950917,-0.000000),(0.901865,-0.000000),(0.852871,0.000000),(0.803965,0.000000),(0.755178,0.000000),(0.706539,-0.000000),(0.658076,0.000000),(0.609819,-0.000000),(0.561798,-0.000000),(0.514039,0.000000),(0.466574,0.000000),(0.419430,-0.000000),(0.372637,-0.000000),(0.326220,-0.000000),(0.280210,0.000000),(0.234633,0.000000),(0.189517,-0.000000),(0.144890,-0.000000),(0.100777,-0.000000),(0.057207,0.000000),(0.014204,0.000000),(-0.028206,0.000000),(-0.069995,-0.000000),(-0.111141,0.000000),(-0.151616,0.000000),(-0.191399,-0.000000),(-0.230463,-0.000000),(-0.268787,-0.000000),(-0.306346,-0.000000),(-0.343118,0.000000),(-0.379081,0.000000),(-0.414214,0.000000),(-0.448494,-0.000000),(-0.481902,-0.000000),(-0.514418,-0.000000),(-0.546021,0.000000),(-0.576693,-0.000000),(-0.606415,-0.000000),(-0.635169,0.000000),(-0.662939,-0.000000),(-0.689707,0.000000),(-0.715457,0.000000),(-0.740174,-0.000000),(-0.763843,0.000000),(-0.786449,-0.000000),(-0.807979,0.000000),(-0.828419,-0.000000),(-0.847759,0.000000),(-0.865985,-0.000000),(-0.883088,0.000000),(-0.899056,0.000000),(-0.913881,-0.000000),(-0.927552,-0.000000),(-0.940063,0.000000),(-0.951404,-0.000000),(-0.961571,0.000000),(-0.970555,0.000000),(-0.978353,0.000000),(-0.984959,0.000000),(-0.990370,-0.000000),(-0.994581,-0.000000),(-0.997591,0.000000),(-0.999398,-0.000000),(-1.000000,0.000000),(-0.999398,-0.000000),(-0.997591,0.000000),(-0.994581,-0.000000),(-0.990369,0.000000),(-0.984959,-0.000000),(-0.978353,0.000000),(-0.970555,-0.000000),(-0.961571,0.000000),(-0.951404,0.000000),(-0.940063,0.000000),(-0.927552,0.000000),(-0.913880,0.000000),(-0.899056,-0.000000),(-0.883088,0.000000),(-0.865985,-0.000000),(-0.847759,0.000000),(-0.828419,0.000000),(-0.807978,0.000000),(-0.786448,-0.000000),(-0.763842,-0.000000),(-0.740174,-0.000000),(-0.715457,-0.000000),(-0.689707,-0.000000),(-0.662939,-0.000000),(-0.635169,-0.000000),(-0.606415,0.000000),(-0.576693,-0.000000),(-0.546021,0.000000),(-0.514417,-0.000000),(-0.481902,0.000000),(-0.448494,-0.000000),(-0.414213,-0.000000),(-0.379081,0.000000),(-0.343118,0.000000),(-0.306346,0.000000),(-0.268786,-0.000000),(-0.230463,0.000000),(-0.191398,0.000000),(-0.151616,-0.000000),(-0.111140,0.000000),(-0.069995,-0.000000),(-0.028205,0.000000),(0.014204,-0.000000),(0.057207,0.000000),(0.100778,0.000000),(0.144890,0.000000),(0.189517,-0.000000),(0.234633,0.000000),(0.280210,0.000000),(0.326221,-0.000000),(0.372637,-0.000000),(0.419431,-0.000000),(0.466575,-0.000000),(0.514040,-0.000000),(0.561798,0.000000),(0.609820,0.000000),(0.658077,-0.000000),(0.706540,0.000000),(0.755179,-0.000000),(0.803966,0.000000),(0.852871,0.000000),(0.901865,0.000000),(0.950918,-0.000000),
[KISS IN]
1.000000,1.049083,1.098135,1.147129,1.196034,1.244821,1.293461,1.341924,1.390181,1.438203,1.485960,1.533426,1.580569,1.627363,1.673780,1.719790,1.765367,1.810483,1.855110,1.899223,1.942793,1.985796,2.028205,2.069995,2.111140,2.151616,2.191399,2.230463,2.268787,2.306346,2.343118,2.379081,2.414214,2.448494,2.481902,2.514418,2.546021,2.576693,2.606415,2.635170,2.662939,2.689707,2.715457,2.740174,2.763843,2.786448,2.807979,2.828420,2.847759,2.865986,2.883088,2.899056,2.913881,2.927552,2.940063,2.951404,2.961571,2.970555,2.978353,2.984959,2.990369,2.994581,2.997591,2.999398,3.000000,2.999398,2.997591,2.994581,2.990369,2.984959,2.978353,2.970555,2.961571,2.951404,2.940063,2.927552,2.913881,2.899056,2.883088,2.865986,2.847759,2.828419,2.807979,2.786448,2.763842,2.740174,2.715457,2.689707,2.662939,2.635170,2.606415,2.576693,2.546021,2.514418,2.481902,2.448494,2.414214,2.379081,2.343118,2.306346,2.268786,2.230463,2.191398,2.151616,2.111140,2.069995,2.028205,1.985796,1.942793,1.899223,1.855110,1.810483,1.765367,1.719790,1.673780,1.627363,1.580569,1.533425,1.485960,1.438202,1.390181,1.341924,1.293461,1.244821,1.196034,1.147129,1.098135,1.049082,1.000000,0.950917,0.901865,0.852871,0.803965,0.755178,0.706539,0.658076,0.609819,0.561797,0.514040,0.466574,0.419430,0.372636,0.326220,0.280210,0.234633,0.189517,0.144890,0.100777,0.057206,0.014203,-0.028206,-0.069995,-0.111141,-0.151617,-0.191399,-0.230463,-0.268787,-0.306346,-0.343118,-0.379081,-0.414214,-0.448494,-0.481902,-0.514418,-0.546021,-0.576693,-0.606415,-0.635170,-0.662939,-0.689707,-0.715457,-0.740174,-0.763842,-0.786449,-0.807979,-0.828420,-0.847759,-0.865986,-0.883088,-0.899056,-0.913881,-0.927552,-0.940063,-0.951404,-0.961571,-0.970555,-0.978353,-0.984959,-0.990370,-0.994581,-0.997591,-0.999398,-1.000000,-0.999398,-0.997591,-0.994581,-0.990369,-0.984959,-0.978353,-0.970555,-0.961571,-0.951404,-0.940062,-0.927552,-0.913881,-0.899056,-0.883088,-0.865986,-0.847759,-0.828419,-0.807978,-0.786448,-0.763842,-0.740174,-0.715457,-0.689707,-0.662939,-0.635169,-0.606415,-0.576693,-0.546021,-0.514418,-0.481902,-0.448494,-0.414213,-0.379081,-0.343118,-0.306346,-0.268786,-0.230463,-0.191398,-0.151616,-0.111141,-0.069995,-0.028205,0.014204,0.057207,0.100778,0.144890,0.189517,0.234633,0.280210,0.326221,0.372637,0.419431,0.466575,0.514040,0.561798,0.609820,0.658077,0.706540,0.755179,0.803966,0.852871,0.901865,0.950918,
used:266
[KISS FFTR]
(256.000000,0.000000),(0.000015,-256.000000),(0.000000,0.000007),(0.000000,0.000008),(0.000001,0.000002),(0.000003,-0.000000),(-0.000001,0.000005),(0.000000,0.000003),(0.000000,0.000001),(-0.000005,-0.000000),(0.000001,-0.000001),(0.000002,-0.000004),(-0.000002,0.000002),(-0.000001,0.000004),(-0.000000,0.000001),(-0.000001,0.000002),(0.000002,0.000001),(0.000004,-0.000004),(-0.000001,0.000000),(0.000001,0.000001),(-0.000001,0.000002),(-0.000002,0.000000),(0.000000,0.000001),(-0.000002,0.000001),(-0.000001,0.000000),(0.000001,0.000002),(-0.000002,0.000001),(0.000001,0.000002),(-0.000001,0.000001),(-0.000002,-0.000003),(-0.000001,0.000001),(-0.000004,0.000000),(0.000000,0.000000),(-0.000005,-0.000009),(-0.000004,-0.000001),(-0.000003,-0.000002),(-0.000002,-0.000005),(0.000001,-0.000004),(0.000002,-0.000007),(0.000004,-0.000001),(0.000003,0.000000),(0.000001,0.000001),(-0.000001,-0.000000),(0.000002,0.000001),(0.000002,-0.000002),(0.000002,-0.000002),(0.000000,0.000001),(0.000002,-0.000000),(0.000000,0.000001),(0.000000,-0.000003),(0.000002,-0.000001),(0.000000,-0.000000),(-0.000001,0.000000),(-0.000000,-0.000001),(-0.000001,0.000000),(0.000000,0.000003),(-0.000000,-0.000000),(0.000000,0.000003),(0.000001,0.000002),(-0.000002,-0.000001),(-0.000001,0.000001),(-0.000001,0.000000),(0.000000,-0.000001),(0.000008,0.000008),(0.000000,0.000000),(-0.000000,-0.000015),(0.000001,0.000001),(0.000000,-0.000000),(-0.000001,-0.000000),(0.000003,0.000002),(0.000000,0.000002),(0.000002,-0.000005),(0.000000,0.000005),(-0.000001,0.000001),(-0.000000,0.000008),(-0.000000,-0.000004),(-0.000002,0.000003),(-0.000002,-0.000002),(0.000001,-0.000001),(-0.000003,0.000001),(0.000000,-0.000001),(-0.000000,-0.000000),(-0.000001,-0.000000),(0.000000,-0.000000),(-0.000000,-0.000001),(-0.000002,0.000001),(-0.000001,0.000001),(-0.000003,-0.000000),(-0.000000,-0.000002),(-0.000003,0.000001),(-0.000001,-0.000001),(0.000000,0.000002),(-0.000000,-0.000001),(0.000000,0.000000),(-0.000001,-0.000001),(-0.000003,0.000000),(0.000000,0.000000),(0.000000,-0.000002),(-0.000000,0.000001),(0.000001,0.000001),(0.000000,-0.000000),(-0.000002,-0.000001),(-0.000001,-0.000000),(-0.000001,0.000003),(0.000001,0.000000),(-0.000001,-0.000001),(-0.000002,0.000000),(-0.000003,-0.000003),(-0.000002,0.000001),(-0.000001,-0.000006),(0.000000,-0.000002),(0.000000,-0.000003),(0.000002,-0.000001),(0.000001,-0.000001),(0.000001,0.000002),(0.000001,-0.000001),(-0.000000,0.000000),(0.000002,-0.000000),(0.000000,-0.000001),(0.000004,0.000002),(0.000000,0.000001),(0.000002,0.000003),(0.000001,0.000000),(-0.000000,-0.000001),(-0.000001,-0.000000),(-0.000000,-0.000001),(-0.000001,0.000000),(-0.000000,0.000008),(0.000000,0.000000),
used:271
[KISS FFTRI]
255.999985,268.565155,281.122681,293.665039,306.184814,318.674255,331.125977,343.532471,355.886230,368.179810,380.405884,392.556885,404.625793,416.605103,428.487549,440.266235,451.933899,463.483582,474.908203,486.200928,497.355103,508.363831,519.220581,529.918701,540.451904,550.813721,560.998047,570.998535,580.809387,590.424561,599.838135,609.044739,618.038696,626.814575,635.367004,643.690857,651.781372,659.633423,667.242065,674.603333,681.712463,688.564941,695.156982,701.484375,707.543762,713.330811,718.842407,724.075439,729.026306,733.692322,738.070496,742.158325,745.953491,749.453369,752.656006,755.559509,758.162048,760.462158,762.458374,764.149536,765.534546,766.612793,767.383240,767.845764,768.000061,767.845825,767.383240,766.612671,765.534607,764.149536,762.458313,760.462158,758.162109,755.559509,752.655945,749.453308,745.953491,742.158447,738.070435,733.692261,729.026306,724.075378,718.842407,713.330811,707.543579,701.484436,695.156860,688.564941,681.712402,674.603394,667.242188,659.633301,651.781433,643.690918,635.366882,626.814453,618.038696,609.044800,599.838135,590.424500,580.809326,570.998535,560.997986,550.813843,540.451965,529.918762,519.220459,508.363831,497.355042,486.201050,474.908142,463.483582,451.933868,440.266205,428.487518,416.604980,404.625732,392.556946,380.405853,368.179810,355.886292,343.532410,331.125885,318.674316,306.184753,293.665039,281.122559,268.565125,255.999924,243.434814,230.877319,218.334961,205.815125,193.325638,180.874039,168.467529,156.113693,143.820190,131.594131,119.443008,107.374146,95.394913,83.512344,71.733749,60.066086,48.516418,37.091721,25.798996,14.644852,3.636108,-7.220612,-17.918701,-28.451920,-38.813812,-48.998016,-58.998550,-68.809433,-78.424576,-87.838135,-97.044739,-106.038696,-114.814545,-123.367004,-131.690857,-139.781403,-147.633438,-155.242157,-162.603409,-169.712479,-176.565033,-183.156982,-189.484436,-195.543777,-201.330917,-206.842438,-212.075409,-217.026367,-221.692368,-226.070511,-230.158371,-233.953522,-237.453400,-240.655975,-243.559525,-246.162048,-248.462158,-250.458282,-252.149551,-253.534607,-254.612701,-255.383240,-255.845810,-256.000061,-255.845856,-255.383240,-254.612671,-253.534607,-252.149567,-250.458313,-248.462158,-246.162109,-243.559509,-240.655945,-237.453308,-233.953461,-230.158478,-226.070450,-221.692261,-217.026306,-212.075378,-206.842316,-201.330750,-195.543625,-189.484497,-183.156860,-176.564941,-169.712372,-162.603302,-155.242218,-147.633377,-139.781448,-131.690948,-123.366882,-114.814453,-106.038605,-97.044815,-87.838165,-78.424515,-68.809326,-58.998566,-48.997925,-38.813721,-28.451981,-17.918762,-7.220490,3.636169,14.644958,25.799088,37.091965,48.516373,60.066132,71.733795,83.512482,95.395065,107.374344,119.443253,131.594086,143.820145,156.113708,168.467606,180.874176,193.325806,205.815414,218.334915,230.877380,243.434875,
256点 1000次,用时如下
复数fft 复数ifft
424ms 419ms
实数fft 实数ifft
266ms 271ms
所以一次实数fft计算大概在270uS左右。
对比某个risc平台soc,跑525MHz,大概在100uS左右,性能是相当的。
-
发表了主题帖:
【国民技术高性能MCU N32H487开发板】文件传输以及文件操作命令集
前言
前面实现了文件系统,可以进行文件的读写,继续来实现文件的传输和基本的文件操作命令集,方便后续操作。
代码见
https://github.com/qinyunti/N32H487.git
文件操作命令集合
shell_func.c中
添加命令
static void lsfilefunc(uint8_t* param);
static void rmfilefunc(uint8_t* param);
static void renamefilefunc(uint8_t* param);
static void touchfunc(uint8_t* param);
static void mkdirfunc(uint8_t* param);
static void pwdfunc(uint8_t* param);
static void cdfunc(uint8_t* param);
static void cpfilefunc(uint8_t* param);
static void freefunc(uint8_t* param);
{ (uint8_t*)"ls ", lsfilefunc, (uint8_t*)"ls path"},
{ (uint8_t*)"rm ", rmfilefunc, (uint8_t*)"rm path"},
{ (uint8_t*)"rename ", renamefilefunc, (uint8_t*)"rename path newpath"},
{ (uint8_t*)"touch ", touchfunc, (uint8_t*)"touch path size"},
{ (uint8_t*)"mkdir ", mkdirfunc, (uint8_t*)"mkdir path"},
{ (uint8_t*)"pwd ", pwdfunc, (uint8_t*)"pwd"},
{ (uint8_t*)"cd ", cdfunc, (uint8_t*)"cd path"},
{ (uint8_t*)"cp", cpfilefunc, (uint8_t*)"cp srcpath dstpath"},
{ (uint8_t*)"free", freefunc, (uint8_t*)"free path"},
实现如下
/***************
* 文件操作部分
**************/
/* List contents of a directory */
static FRESULT list_dir (const char *path)
{
FRESULT res;
DIR dir;
FILINFO fno;
int nfile, ndir;
res = f_opendir(&dir, path); /* Open the directory */
if (res == FR_OK) {
nfile = ndir = 0;
for (;;) {
res = f_readdir(&dir, &fno); /* Read a directory item */
if (res != FR_OK || fno.fname[0] == 0) break; /* Error or end of dir */
if (fno.fattrib & AM_DIR) { /* Directory */
xprintf(" <DIR> %s\n", fno.fname);
ndir++;
} else { /* File */
xprintf("%10u %s\n", fno.fsize, fno.fname);
nfile++;
}
}
f_closedir(&dir);
xprintf("%d dirs, %d files.\n", ndir, nfile);
} else {
xprintf("Failed to open \"%s\". (%u)\n", path, res);
}
return res;
}
void lsfilefunc(uint8_t* param)
{
char path[128];
if(1 == sscanf((const char*)param, "%*s %s", path))
{
list_dir((const char *)path);
}
else
{
xprintf("param err");
}
}
void rmfilefunc(uint8_t* param)
{
FRESULT res;
char path[128];
if(1 == sscanf((const char*)param, "%*s %s", path))
{
if(FR_OK != (res = f_unlink((const char *)path)))
{
xprintf("unlink %s err %d\r\n",path,res);
}
}
else
{
xprintf("param err");
}
}
void renamefilefunc(uint8_t* param)
{
FRESULT res;
char path[128];
char newpath[128];
if(2 == sscanf((const char*)param, "%*s %s %s", path, newpath))
{
if(FR_OK != (res = f_rename((const char *)path, (const char*)newpath)))
{
xprintf("rename %s to %s err %d\r\n",path,newpath,res);
}
}
else
{
xprintf("param err");
}
}
void touchfunc(uint8_t* param)
{
FIL fil;
char path[128];
int size;
if(2 == sscanf((const char*)param, "%*s %s %d", path, &size))
{
FRESULT res = f_open(&fil, path, FA_CREATE_NEW | FA_WRITE);
if (FR_OK == res)
{
if(FR_OK != (res = f_expand(&fil,size,1)))
{
xprintf("expand %s size to %d err %d\r\n",path,size,res);
}
if(FR_OK != (res = f_close(&fil)))
{
xprintf("close %s err %d\r\n",path,res);
}
}
else
{
xprintf("open %s err %d\r\n",path,res);
}
}
else
{
xprintf("param err");
}
}
void mkdirfunc(uint8_t* param)
{
char path[128];
FRESULT res;
if(1 == sscanf((const char*)param, "%*s %s", path))
{
if(FR_OK != (res=f_mkdir((const char*)path)))
{
xprintf("mkdir %s err %d",path,res);
}
}
else
{
xprintf("param err");
}
}
void pwdfunc(uint8_t* param)
{
(void)param;
FRESULT fr;
TCHAR str[128];
if(1 == sscanf((const char*)param, "%*s %s", str)){
if(FR_OK != (fr = f_getcwd(str, 128))) /* Get current directory path */
{
xprintf("getcwd err %d\r\n",fr);
}
else
{
xprintf("%s\r\n",str);
}
}else
{
xprintf("param err");
}
}
void cdfunc(uint8_t* param)
{
char path[128];
FRESULT res;
if(1 == sscanf((const char*)param, "%*s %s", path))
{
if(FR_OK != (res=f_chdir((const char*)path)))
{
xprintf("chdir to %s err %d",path,res);
}
}
else
{
xprintf("param err");
}
}
void freefunc(uint8_t* param)
{
char path[128];
FRESULT res;
if(1 == sscanf((const char*)param, "%*s %s", path))
{
FATFS *fs;
DWORD fre_clust, fre_sect, tot_sect;
/* Get volume information and free clusters of drive 1 */
res = f_getfree(path, &fre_clust, &fs);
if(res == FR_OK)
{
/* Get total sectors and free sectors */
tot_sect = (fs->n_fatent - 2) * fs->csize;
fre_sect = fre_clust * fs->csize;
/* Print the free space (assuming 512 bytes/sector) */
xprintf("%10lu KiB total drive space.\n%10lu KiB available.\n", tot_sect / 2, fre_sect / 2);
}
else
{
xprintf("getfree %s err %d\r\n",path,res);
}
}
else
{
xprintf("param err");
}
}
static int cp(const char* src, const char* dst)
{
FIL fr;
FIL fw;
BYTE buf[64] = {0x00};
FRESULT res;
size_t write_size; /*剩余待写入字节数*/
DWORD pos = 0;
UINT btr; /*一次试图写入字节数*/
UINT br; /*一次实际读到字节数*/
UINT bw; /*一次实际写入字节数*/
UINT size;
res = f_open(&fr, src, FA_READ);
if (res != FR_OK)
{
return -1;
}
res = f_open(&fw, dst, FA_WRITE | FA_CREATE_ALWAYS);
if (res != FR_OK)
{
f_close(&fr);
return -1;
}
write_size = f_size( &fr );
size = write_size;
do
{
btr = (write_size > sizeof(buf)) ? sizeof(buf) : write_size;
//res = f_lseek(&fr, pos);
res = f_read (&fr, buf, btr, &br);
if(res != FR_OK)
{
f_close(&fw);
f_close(&fr);
return -1;
}
//res = f_lseek(&fw, pos);
res = f_write(&fw, buf, br, &bw);
if((res != FR_OK) || (br != bw))
{
f_close(&fw);
f_close(&fr);
return -1;
}
//f_sync(&fw);
pos += br;
write_size -= br;
xprintf("\b\b%02d", 100 * (pos + 1) / size);
}while(write_size > 0);
xprintf("\b\b\b%d\r\n", 100);
res = f_close(&fw);
res = f_close(&fr);
return 0;
}
static void cpfilefunc(uint8_t * cmdbuf)
{
int len;
int res;
char path[32] = {0x00};
char dst[32] = {0x00};
char regexp[32];
memset((void *)path, 0, sizeof(path));
len = sscanf((char const *)cmdbuf, "%*s %31s %31s %31s", path,dst,regexp);
if (len == 2)
{
xprintf("\tcopy \"%s\" to \"%s\"...\r\n", path, dst);
res = cp(path, dst);
xprintf("f_cp result = %d\r\n", res);
}
else
{}
}
查看添加的命令
测试ls 0:
其他命令都测试OK。
Xmodem移植
时间戳获取函数
Main.c中初始化时
RCC_ClocksType RCC_clock;
RCC_GetClocksFreqValue(&RCC_clock);
SysTick_Config(RCC_clock.SysclkFreq/1000);
n32h47x_48x_it.c中
uint32_t g_sys_tick = 0;
void SysTick_Handler(void)
{
g_sys_tick++;
}
extern uint32_t g_sys_tick;
static uint32_t getms(void)
{
return g_sys_tick;
}
Xmodem的实现参考公众号文章
https://mp.weixin.qq.com/s/QSYKxND3DTyQZ0JtnSqkzQ
Xmodem.c
#include <string.h>
#include "xmodem.h"
/* 符号定义 */
#define SOH 0x01
#define STX 0x02
#define EOT 0x04
#define ACK 0x06
#define NAK 0x15
#define CAN 0x18
#define CTRLZ 0x1A
/* 状态 */
#define XMODEM_STATE_IDLE 0
#define XMODEM_STATE_RX_START_WAIT 1
#define XMODEM_STATE_RX_START_WAIT_HEAD 2
#define XMODEM_STATE_RX_DATA_WAIT 3
#define XMODEM_STATE_RX_DATA_WAIT_HEAD 4
#define XMODEM_STATE_TX_START_WAIT 1
#define XMODEM_STATE_TX_DATA 2
#define XMODEM_STATE_TX_ACK_WAIT 3
/**
* \struct xmodem_state_st
* 状态机结构体
*/
typedef struct
{
uint8_t state; /**< 状态机的状态 */
uint32_t getlen; /**< 接收到的数据个数 */
uint8_t pnum; /**< 包ID */
uint32_t ms; /**< 上一个状态mS时间戳 */
} xmodem_state_st;
static xmodem_cfg_st* s_cfg_pst = 0; /* 接口指针,用户初始化 */
static xmodem_state_st s_state_st;
/**
* crc计算参考https://www.iar.com/knowledge/support/technical-notes/general/checksum-generation/
*/
static const uint16_t t[] =
{
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
};
static uint16_t crc_nibble_rom(uint16_t sum, uint8_t* p, uint32_t len)
{
while (len--)
{
// hi nibble
sum = t[(sum>>12)^(*p >> 4)]^(sum<<4);
// lo nibble
sum = t[(sum>>12)^(*p++ & 0xF)]^(sum<<4);
}
return sum;
}
static int xmodem_check(uint16_t crc, uint8_t *buf, uint32_t sz)
{
if (crc != 0)
{
uint16_t crc = crc_nibble_rom(0, buf, sz);
uint16_t tcrc = ((uint16_t)(buf[sz]) << 8) + (uint16_t)(buf[sz + 1]);
if (crc == tcrc)
{
return 0;
}
}
else
{
uint8_t cks = 0;
for (uint32_t i = 0; i < sz; i++)
{
cks += buf[i];
}
if (cks == buf[sz])
{
return 0;
}
}
return -1;
}
static uint16_t xmodem_check_cal(uint16_t crc, uint8_t *buf, uint32_t sz)
{
if (crc != 0)
{
uint16_t check;
check = crc_nibble_rom(0, buf, sz);
buf[sz+1] = check & 0xFF;
buf[sz] = (check>>8) & 0xFF;
return check;
}
else
{
uint8_t cks = 0;
uint32_t i;
for (i = 0; i < sz; i++)
{
cks += buf[i];
}
buf[i] = cks;
return cks;
}
}
/**
* \fn xmodem_rx
* 接收处理, 在此之前必须要先调用xmodem_init_rx初始化
* \retval 0 正在处理,需要循环继续调用xmodem_rx处理
* \retval 1 接收正常完成
* \retval -1 参数错误,未初始化对应的接口
* \retval -2 未初始化,处于空闲状态
* \retval -3 发送方提前结束
* \retval -4 启动后超时未收到包头
* \retval -5 传输过程中,等待包头超时
* \retval -6 传输过程中,包ID错误,取消传输
* \retval -7 传输过程中,等待数据超时
* \retval -8 传输过程中,发送方取消
* \retval -9 传输过程中,写数据错误
*/
int xmodem_rx(void)
{
int res = 0;
uint8_t tmp = NAK;
uint32_t t = s_cfg_pst->getms();
uint8_t* buf;
uint16_t len;
uint32_t getlen;
if(s_cfg_pst == 0)
{
return -1;
}
if((s_cfg_pst->io_read == 0) || \
(s_cfg_pst->io_write == 0) || \
(s_cfg_pst->mem_write == 0) || \
(s_cfg_pst->buffer == 0) || \
(s_cfg_pst->getms == 0))
{
return -1;
}
switch(s_state_st.state)
{
case XMODEM_STATE_IDLE:
res = -2;
break;
case XMODEM_STATE_RX_START_WAIT:
/* 根据使用校验方式发送不同的启动字符,
* 然后等待对方发送第一个包的包头
*/
if(s_cfg_pst->crccheck)
{
tmp = 'C';
}
else
{
tmp = NAK;
}
s_cfg_pst->io_write(&tmp,1);
s_state_st.ms = t;
s_state_st.state = XMODEM_STATE_RX_START_WAIT_HEAD;
s_cfg_pst->xferlen = 0;
break;
case XMODEM_STATE_RX_START_WAIT_HEAD:
case XMODEM_STATE_RX_DATA_WAIT_HEAD:
buf = s_cfg_pst->buffer;
buf[0] = 0;
if(0 != s_cfg_pst->io_read(buf,1))
{
if((buf[0] == SOH) || (buf[0] == STX))
{
s_cfg_pst->plen = (buf[0] == SOH) ? 128 : 1024;
s_state_st.ms = t;
s_state_st.state = XMODEM_STATE_RX_DATA_WAIT;
s_state_st.getlen = 1;
}
/* 发送方结束 */
if(buf[0] == EOT)
{
tmp = ACK;
s_cfg_pst->io_write(&tmp,1);
s_state_st.state = XMODEM_STATE_IDLE;
if(s_cfg_pst->xferlen >= s_cfg_pst->totallen)
{
res = 1;
}
else
{
res = -3;
}
}
/* 发送方取消 */
if(buf[0] == CAN)
{
s_state_st.state = XMODEM_STATE_IDLE;
res = -8;
}
}
if((buf[0] != SOH) && (buf[0] != STX))
{
/* 非法值或者没有收到数据,继续等待直到超时 */
if((t - s_state_st.ms) >= s_cfg_pst->ack_timeout)
{
/* 超时未收到响应,继续重复发送启动字符
* 如果超过了设置的超时时间则退出
*/
if(s_cfg_pst->start_timeout <= 1)
{
/* 超时退出 */
s_state_st.state = XMODEM_STATE_IDLE;
res = -4;
}
else
{
/* 重新发送启动 */
if(s_state_st.state == XMODEM_STATE_RX_START_WAIT_HEAD)
{
s_cfg_pst->start_timeout--;
s_state_st.state = XMODEM_STATE_RX_START_WAIT;
}
else
{
/* 数据阶段等待头超时, 结束传输 */
s_state_st.state = XMODEM_STATE_IDLE;
res = -5;
}
}
}
else
{
/* 未超时继续等待*/
}
}
break;
case XMODEM_STATE_RX_DATA_WAIT:
buf = s_cfg_pst->buffer;
len = s_cfg_pst->plen + 3 + ((s_cfg_pst->crccheck == 0) ? 1 : 2);
getlen = s_cfg_pst->io_read(buf+s_state_st.getlen, len - s_state_st.getlen);
s_state_st.getlen += getlen;
if(s_state_st.getlen >= len)
{
/* 接收完,准备判断合法性 */
if(((uint8_t)(s_state_st.pnum + 1) != buf[1]) || ((buf[1] + buf[2]) != (uint8_t)255))
{
/* 包ID错误,取消传输 */
tmp = CAN;
s_cfg_pst->io_write(&tmp,1);
s_state_st.state = XMODEM_STATE_IDLE;
res = -6;
}
else
{
/* 校验正确 */
if(0 == xmodem_check(s_cfg_pst->crccheck, buf+3, s_cfg_pst->plen))
{
s_state_st.pnum = buf[1];
s_state_st.state = XMODEM_STATE_RX_DATA_WAIT_HEAD;
s_state_st.ms = t;
/* 调用写接口存储数据 */
if((s_cfg_pst->xferlen + s_cfg_pst->plen) >= s_cfg_pst->totallen)
{
if(s_cfg_pst->xferlen >= s_cfg_pst->totallen)
{
/* 已经收到了指定的数据量,但是发送方还在发送,则主动取消 */
tmp = CAN;
s_cfg_pst->io_write(&tmp,1);
s_state_st.state = XMODEM_STATE_IDLE;
res = 1;
}
else
{
tmp = ACK;
s_cfg_pst->io_write(&tmp,1);
s_cfg_pst->mem_write(s_cfg_pst->addr+s_cfg_pst->xferlen, buf+3 ,s_cfg_pst->totallen-s_cfg_pst->xferlen);
s_cfg_pst->xferlen = s_cfg_pst->totallen;
}
}
else
{
tmp = ACK;
s_cfg_pst->io_write(&tmp,1);
if(0 == s_cfg_pst->mem_write(s_cfg_pst->addr+s_cfg_pst->xferlen, buf+3 ,s_cfg_pst->plen))
{
/* 写错误,取消传输 */
tmp = CAN;
s_cfg_pst->io_write(&tmp,1);
s_state_st.state = XMODEM_STATE_IDLE;
res = -9;
}
else
{
s_cfg_pst->xferlen += s_cfg_pst->plen;
}
}
}
else
{
tmp = NAK;
s_cfg_pst->io_write(&tmp,1);
s_state_st.state = XMODEM_STATE_RX_DATA_WAIT_HEAD;
}
}
}
else
{
/* 未接收完判断超时 */
if((t - s_state_st.ms) >= s_cfg_pst->packet_timeout)
{
/* 超时退出 */
tmp = NAK;
s_cfg_pst->io_write(&tmp,1);
s_state_st.state = XMODEM_STATE_IDLE;
res = -7;
}
else
{
/* 未超时继续等待*/
}
}
break;
}
return res;
}
/**
* \fn xmodem_init_rx
* 接收初始化
* 以下成员必须初始化
* \param[in] cfg \ref xmodem_cfg_st 配置信息
*/
void xmodem_init_rx(xmodem_cfg_st* cfg)
{
s_cfg_pst = cfg;
s_state_st.state = XMODEM_STATE_RX_START_WAIT;
s_state_st.getlen = 0;
s_state_st.pnum = 0;
if(s_cfg_pst != 0)
{
if(s_cfg_pst->io_read_flush != 0)
{
s_cfg_pst->io_read_flush();
}
}
}
/**
* \fn xmodem_tx
* 发送处理, 在此之前必须要先调用xmodem_init_tx初始化
* \retval 0 正在处理,需要循环继续调用xmodem_tx处理
* \retval 1 发送正常完成
* \retval -1 参数错误,未初始化对应的接口
* \retval -2 未初始化,处于空闲状态
* \retval -3 接收方提前取消
* \retval -4 启动阶段超时未收到响应
* \retval -5 数据阶段超时未收到响应
*/
int xmodem_tx(void)
{
int res = 0;
uint8_t tmp = 0;
uint32_t t = s_cfg_pst->getms();
uint8_t* buf;
uint16_t len;
if(s_cfg_pst == 0)
{
return -1;
}
if((s_cfg_pst->io_read == 0) || \
(s_cfg_pst->io_write == 0) || \
(s_cfg_pst->mem_read == 0) || \
(s_cfg_pst->buffer == 0) || \
(s_cfg_pst->getms == 0))
{
return -1;
}
switch(s_state_st.state)
{
case XMODEM_STATE_IDLE:
res = -2;
break;
case XMODEM_STATE_TX_START_WAIT:
buf = s_cfg_pst->buffer;
if(0 != s_cfg_pst->io_read(buf,1))
{
if((buf[0] == 'C') || (buf[0] == NAK))
{
s_cfg_pst->crccheck = (buf[0] == 'C') ? 1 : 0;
s_state_st.ms = t;
s_state_st.state = XMODEM_STATE_TX_DATA;
}
if(buf[0] == CAN)
{
s_state_st.state = XMODEM_STATE_IDLE;
res = -3;
}
}
if((buf[0] != 'C') && (buf[0] != NAK) && (buf[0] != CAN))
{
/* 非法值或者没有收到数据,继续等待直到超时 */
if((t - s_state_st.ms) >= s_cfg_pst->ack_timeout)
{
/* 超时未收到响应,继续重复发送启动字符
* 如果超过了设置的超时时间则退出
*/
if(s_cfg_pst->start_timeout <= 1)
{
/* 超时退出 */
s_state_st.state = XMODEM_STATE_IDLE;
res = -4;
}
else
{
s_cfg_pst->start_timeout--;
}
s_state_st.ms = t;
}
else
{
/* 未超时继续等待*/
}
}
break;
case XMODEM_STATE_TX_DATA:
buf = s_cfg_pst->buffer;
buf[0] = (s_cfg_pst->plen == 1024)? STX : SOH;
buf[1] = s_state_st.pnum;
buf[2] = ~buf[1];
if((s_cfg_pst->xferlen + s_cfg_pst->plen) >= s_cfg_pst->totallen)
{
len = s_cfg_pst->mem_read(s_cfg_pst->addr+s_cfg_pst->xferlen, buf+3,s_cfg_pst->totallen-s_cfg_pst->xferlen);
}
else
{
len = s_cfg_pst->mem_read(s_cfg_pst->addr+s_cfg_pst->xferlen, buf+3,s_cfg_pst->plen);
}
if((len < s_cfg_pst->plen) && (len > 0))
{
memset(buf+3+len, CTRLZ, s_cfg_pst->plen - len);
}
if(len > 0)
{
xmodem_check_cal(s_cfg_pst->crccheck, buf+3, s_cfg_pst->plen);
len = s_cfg_pst->plen + 3 + ((s_cfg_pst->crccheck == 0) ? 1 : 2);
s_cfg_pst->io_write(buf,len);
s_state_st.state = XMODEM_STATE_TX_ACK_WAIT;
s_state_st.ms = t;
}
else
{
/* 读完 */
tmp = EOT;
s_cfg_pst->io_write(&tmp,1);
s_state_st.state = XMODEM_STATE_IDLE;
res = 1;
}
break;
case XMODEM_STATE_TX_ACK_WAIT:
buf = s_cfg_pst->buffer;
if(0 != s_cfg_pst->io_read(buf,1))
{
if(buf[0] == ACK)
{
/* 判断是否传输完,未传输完则发送下一包 */
if((s_cfg_pst->xferlen + s_cfg_pst->plen) >= s_cfg_pst->totallen)
{
/* 发送完 */
s_state_st.state = XMODEM_STATE_IDLE;
s_state_st.pnum++;
s_cfg_pst->xferlen += s_cfg_pst->plen;
if(s_cfg_pst->xferlen >= s_cfg_pst->totallen)
{
s_cfg_pst->xferlen = s_cfg_pst->totallen;
}
tmp = EOT;
s_cfg_pst->io_write(&tmp,1);
res = 1;
}
else
{
/* 发送下一包 */
s_state_st.state = XMODEM_STATE_TX_DATA;
s_state_st.pnum++;
s_cfg_pst->xferlen += s_cfg_pst->plen;
}
}
if(buf[0] == NAK)
{
/* 重发 */
s_state_st.state = XMODEM_STATE_TX_DATA;
}
if(buf[0] == CAN)
{
s_state_st.state = XMODEM_STATE_IDLE;
res = -3;
}
}
if((buf[0] != ACK) && (buf[0] != NAK) && (buf[0] != CAN))
{
/* 非法值或者没有收到数据,继续等待直到超时 */
if((t - s_state_st.ms) >= s_cfg_pst->ack_timeout)
{
/* 超时退出 */
s_state_st.state = XMODEM_STATE_IDLE;
res = -5;
}
else
{
/* 未超时继续等待*/
}
}
break;
}
return res;
}
/**
* \fn xmodem_init_tx
* 发送初始化
* 以下成员必须初始化
* \param[in] cfg \ref xmodem_cfg_st 配置信息
*/
void xmodem_init_tx(xmodem_cfg_st* cfg)
{
s_cfg_pst = cfg;
s_state_st.state = XMODEM_STATE_TX_START_WAIT; /* 等待接收端发送启动 */
s_state_st.getlen = 0;
s_state_st.pnum = 1;
if(s_cfg_pst != 0)
{
s_state_st.ms = s_cfg_pst->getms();
s_cfg_pst->xferlen = 0;
if(s_cfg_pst->io_read_flush != 0)
{
s_cfg_pst->io_read_flush();
}
}
}
Xmodem.h
#ifndef XMODEM_H
#define XMODEM_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
typedef uint32_t (*xmodem_io_read_pf)(uint8_t* buffer, uint32_t len); /**< 通讯接收接口 */
typedef uint32_t (*xmodem_io_write_pf)(uint8_t* buffer, uint32_t len);/**< 通讯发送接口 */
typedef void (*xmodem_read_flush_pf)(void); /**< 通讯接收flush接口 */
typedef void (*xmodem_write_flush_pf)(void); /**< 通讯发送flush接口 */
typedef uint32_t (*xmodem_mem_read_pf)(uint32_t addr, uint8_t* buffer, uint32_t len); /**< 读存储接口 */
typedef uint32_t (*xmodem_mem_write_pf)(uint32_t addr, uint8_t* buffer, uint32_t len); /**< 写存储接口 */
typedef uint32_t (*xmodem_getms_pf)(void); /**< 获取mS时间戳 */
/**
* \struct xmodem_cfg_st
* 接口,参数配置结构体
*/
typedef struct
{
xmodem_io_read_pf io_read; /**< 通讯接收接口 */
xmodem_io_read_pf io_write; /**< 通讯发送接口 */
xmodem_read_flush_pf io_read_flush; /**< 通讯接收flush接口 */
xmodem_write_flush_pf io_write_flush; /**< 通讯发送flush接口 */
xmodem_mem_read_pf mem_read; /**< 读存储接口 */
xmodem_mem_write_pf mem_write; /**< 写存储接口 */
xmodem_getms_pf getms; /**< 获取mS时间戳接口 */
uint32_t start_timeout; /**< 等待启动超时次数,单位每次超时为ack_timeout */
uint32_t packet_timeout; /**< 等待数据包超时时间mS */
uint32_t ack_timeout; /**< 等待响应(头)超时时间mS*/
uint8_t crccheck; /**< 对于接收时有效1使用CRC校验 0使用累加和校验 */
uint16_t plen; /**< 对于发送时有效指定包长时128还是1024 */
uint8_t* buffer; /**< 包缓冲区,用户提供,1024字节包需要1024+5 */
uint32_t addr; /**< 存储地址 */
uint32_t totallen; /**< 传输长度 */
uint32_t xferlen; /**< 已经传输长度 */
} xmodem_cfg_st;
/**
* \fn xmodem_rx
* 接收处理, 在此之前必须要先调用xmodem_init_rx初始化
* \retval 0 正在处理,需要循环继续调用xmodem_rx处理
* \retval 1 接收正常完成
* \retval -1 参数错误,未初始化对应的接口
* \retval -2 未初始化,处于空闲状态
* \retval -3 发送方提前结束
* \retval -4 启动后超时未收到包头
* \retval -5 传输过程中,等待包头超时
* \retval -6 传输过程中,包ID错误,取消传输
* \retval -7 传输过程中,等待数据超时
* \retval -8 传输过程中,发送方取消
* \retval -9 传输过程中,写数据错误
*/
int xmodem_rx(void);
/**
* \fn xmodem_init_rx
* 接收初始化
* 以下成员必须初始化
* \param[in] cfg \ref xmodem_cfg_st 配置信息
*/
void xmodem_init_rx(xmodem_cfg_st* cfg);
/**
* \fn xmodem_tx
* 发送处理, 在此之前必须要先调用xmodem_init_tx初始化
* \retval 0 正在处理,需要循环继续调用xmodem_tx处理
* \retval 1 发送正常完成
* \retval -1 参数错误,未初始化对应的接口
* \retval -2 未初始化,处于空闲状态
* \retval -3 接收方提前取消
* \retval -4 启动阶段超时未收到响应
* \retval -5 数据阶段超时未收到响应
*/
int xmodem_tx(void);
/**
* \fn xmodem_init_tx
* 发送初始化
* 以下成员必须初始化
* \param[in] cfg \ref xmodem_cfg_st 配置信息
*/
void xmodem_init_tx(xmodem_cfg_st* cfg);
#ifdef __cplusplus
}
#endif
#endif
Shell_func.h中
#include "xmodem.h"
static void rxfilefunc(uint8_t* param);
static void sxfilefunc(uint8_t* param);
{ (uint8_t*)"rxfile", rxfilefunc, (uint8_t*)"rxfile name len"},
{ (uint8_t*)"sxfile", sxfilefunc, (uint8_t*)"sxfile name len"},
/***************
* 文件传输部分
**************/
static uint8_t rxtx_buf[1029];
extern uint32_t g_sys_tick;
static uint32_t getms(void)
{
return g_sys_tick;
}
static uint32_t io_read(uint8_t* buffer, uint32_t len)
{
return uart_read(0,buffer, len);
}
static void io_read_flush(void)
{
uint8_t tmp;
while(0 != uart_read(0,&tmp, 1));
}
static uint32_t io_write(uint8_t* buffer, uint32_t len)
{
uart_send(0,buffer, len);
return len;
}
static FIL rx_fil; /* File object */
static int rx_file_open_flag = 0;
static int rx_file_open(char* name)
{
FRESULT res = f_open(&rx_fil, name, FA_CREATE_NEW | FA_WRITE);
if (FR_OK == res)
{
rx_file_open_flag = 1;
return 0;
}
else
{
xprintf("open %s err %d\r\n",name,res);
return -1;
}
}
static int rx_file_close(char* name)
{
(void)name;
if(rx_file_open_flag != 0)
{
rx_file_open_flag = 0;
FRESULT res = f_close(&rx_fil);
if(res != FR_OK)
{
xprintf("close err %d\r\n",res);
}
return 0;
}
else
{
return -1;
}
}
static uint32_t rx_file_write(uint32_t addr, uint8_t* buffer, uint32_t len)
{
(void)addr;
if(rx_file_open_flag != 0)
{
UINT bw;
FRESULT res = f_write(&rx_fil, buffer, len, &bw);
if ((bw != len) || (res != FR_OK))
{
xprintf("write err %d %d\r\n",bw,res);
}
return bw;
}
else
{
return 0;
}
}
void rxfilefunc(uint8_t* param)
{
char name[64];
uint32_t len;
int res = 0;
if(2 == sscanf((const char*)param, "%*s %s %d", name, &len))
{
xprintf("rxfile %s %ld\r\n",name,len);
if(0 == rx_file_open(name))
{
xmodem_cfg_st cfg=
{
.buffer = rxtx_buf,
.crccheck = 1,
.getms = getms,
.io_read = io_read,
.io_read_flush = io_read_flush,
.io_write = io_write,
.start_timeout = 60,
.packet_timeout = 2000,
.ack_timeout = 2000,
.mem_write = rx_file_write,
.addr = 0,
.totallen = len,
};
xmodem_init_rx(&cfg);
while((res = xmodem_rx()) == 0);
rx_file_close(name);
xprintf("res:%d\r\n",res);
}
else
{
xprintf("open:%s err\r\n",name);
}
}
}
static FIL tx_fil; /* File object */
static int tx_file_open_flag = 0;
static int tx_file_open(char* name)
{
FRESULT res = f_open(&tx_fil, name, FA_READ);
if (FR_OK == res)
{
tx_file_open_flag = 1;
return 0;
}
else
{
xprintf("open %s err %d\r\n",name,res);
return -1;
}
}
static int tx_file_close(char* name)
{
(void)name;
if(tx_file_open_flag != 0)
{
tx_file_open_flag = 0;
FRESULT res = f_close(&tx_fil);
if(res != FR_OK)
{
xprintf("close err %d\r\n",res);
}
return 0;
}
else
{
return -1;
}
}
static uint32_t tx_file_read(uint32_t addr, uint8_t* buffer, uint32_t len)
{
(void)addr;
UINT br;
FRESULT res = f_read(&tx_fil, buffer, len, &br);
if(res != 0)
{
xprintf("read err %d\r\n",res);
}
return br;
}
void sxfilefunc(uint8_t* param)
{
char name[64];
uint32_t len;
int res = 0;
if(2 == sscanf((const char*)param, "%*s %s %d", name, &len))
{
xprintf("sxfile %s %ld\r\n",name,len);
if(0 == tx_file_open(name))
{
xmodem_cfg_st cfg=
{
.buffer = rxtx_buf,
.plen = 1024,
.getms = getms,
.io_read = io_read,
.io_read_flush = io_read_flush,
.io_write = io_write,
.start_timeout = 60,
.packet_timeout = 1000,
.ack_timeout = 5000,
.mem_read = tx_file_read,
.addr = 0,
.totallen = len,
};
xmodem_init_tx(&cfg);
while((res = xmodem_tx()) == 0);
tx_file_close(name);
xprintf("res:%d\r\n",res);
}
else
{
xprintf("open:%s err\r\n",name);
}
}
}
看到添加的命令
导入文件测试,这里因为spi速度设置的比较低所以文件写比较慢,慢于xmodem传输速度。
导出文件测试
这里读文件比写文件块,速度大于xmodem传输速度,所以115200波特率,9KB/s基本跑满。
总结
以上完成了文件传输,和基本文件操作命令,后面就可以方便导入导出文件,以及进行文件操作。
-
发表了主题帖:
【国民技术高性能MCU N32H487开发板】移植FATFS文件系统读写文件测试
前言
前面实现了SPI FLASH的读写,这一篇来基于SPI FLASH来移植FATFS文件系统。
代码见:
https://github.com/qinyunti/N32H487.git
源码
添加源文件
设置头文件包含路径
配置
没有使用OS
ffconf.h中
#define FF_FS_REENTRANT0
不支持动态内存分配
Ffconf.h中
#define FF_USE_LFN2
此时无需ffsystem.c
diskio.c中,调用flash_itf.c的接口实现读写。
手里的是W25Q32FW 4MB
diskio.c中
根据实际大小修改
case GET_SECTOR_COUNT:
*(DWORD*)buff = 8192; /* 8192*512=4MB */
res = RES_OK;
测试
初始化挂载文件系统
#include ff.h
static FATFS fs; /* Filesystem object */
static BYTE work[FF_MAX_SS]; /* Work area (larger is better for processing time) */
static void fs_init(void)
{
FRESULT res; /* API result code */
if(FR_OK != (res = f_mount (&fs, "0:", 1)))
{
xprintf("mount err %d, mkfs\r\n",res);
res = f_mkfs("0:",0,work,sizeof(work));
if(res == 0)
{
xprintf("mkfs ok\r\n");
if(FR_OK == f_mount (&fs, "0:", 1))
{
xprintf("mount ok\r\n");
}
else
{
xprintf("mount err\r\n");
}
}
else
{
xprintf("mkfs err %d\r\n",res);
}
}
else
{
xprintf("mount ok\r\n");
}
}
shell_func.c中添加两个命令行
#include "ff.h"
static void printfilefunc(uint8_t* param);
static void writefilefunc(uint8_t* param);
{ (uint8_t*)"printfile", printfilefunc, (uint8_t*)"printfile path addr size"},
{ (uint8_t*)"writefile", writefilefunc, (uint8_t*)"writefile path addr[hex] hexstr"},
void printfilefunc(uint8_t* param)
{
char path[128];
uint8_t tmp[16];
uint32_t addr;
uint32_t size;
FRESULT res;
FIL fil;
UINT br;
uint32_t offset = 0;
if(3 == sscanf((const char*)param, "%*s %s %x %d", path, &addr, &size))
{
xprintf("hexdump %s 0x%x %d\r\n",path,addr,size);
if(FR_OK == (res=f_open(&fil,(const char*)path, FA_READ)))
{
xprintf("\r\n");
do
{
br = 0;
if(FR_OK == (res = f_read(&fil,tmp,(size>16)?16:size,&br)))
{
xprintf("%08x ",offset);
offset+=br;
for(uint32_t i=0;i<br;i++)
{
xprintf("%02x",(uint32_t)tmp);
}
xprintf(":");
for(uint32_t i=0;i<br;i++)
{
xprintf("%c",((tmp>0x1F)&&(tmp<0x7F))?(char)tmp:'.');
}
xprintf("\r\n");
size -= br;
}
else
{
break;
}
}while(br > 0);
if(FR_OK != (res = f_close(&fil)))
{
xprintf("close %s err %d\r\n",path,res);
}
}
else
{
xprintf("open %s err %d",path,res);
}
}
else
{
xprintf("param err");
}
}
void writefilefunc(uint8_t* param)
{
char path[128];
uint8_t hexstr[32+1];
uint8_t tmp[16];
uint32_t hexnum = 0;
uint32_t addr;
FRESULT res;
FIL fil;
UINT bw;
if(3 == sscanf((const char*)param, "%*s %s %x %s", path, &addr, hexstr))
{
xprintf("hexwrite %s 0x%x %s\r\n",path,addr,hexstr);
if(FR_OK == (res=f_open(&fil,(const char*)path, FA_WRITE | FA_CREATE_ALWAYS)))
{
xprintf("\r\n");
hexnum = str2hex((const char*)hexstr,tmp,32);
if(hexnum > 0)
{
if(FR_OK == (res=(f_lseek(&fil,addr))))
{
if(FR_OK != (res = f_write(&fil,tmp,hexnum,&bw)))
{
xprintf("write err %d\r\n",res);
}
}
else
{
xprintf("seek %d err %d\r\n",addr,res);
}
}
if(FR_OK != (res = f_close(&fil)))
{
xprintf("close %s err %d\r\n",path,res);
}
}
else
{
xprintf("open %s err %d",path,res);
}
}
else
{
xprintf("param err");
}
}
第一次运行,flash中没有文件系统,会执行格格式化,需要时间会久点。
Help查看增加的命令
些文件再读出
writefile 0:/test.txt 0 12345678
printfile 0:/test.txt 0 16
可以看到写入和读出的数据一致。
问题
杜邦线较长可能影响信号质量,可以适当降低spi速率
等待发送完改为
while(SPI_I2S_GetStatus(SPI1, SPI_I2S_BUSY_FLAG) != 0);
而不是SPI_I2S_TE_FLAG
CS初始化要拉高
GPIO_WriteBits(GPIOA, GPIO_PIN_4, Bit_SET);
FLASH大小至少要设置为4M
*(DWORD*)buff = 8192;
如果设置为2M
*(DWORD*)buff = 4096;
会
Nclst为0
nclst = (tsect - sysect) / fs->csize;/* Number of clusters */
if (nclst == 0) return FR_NO_FILESYSTEM;/* (Invalid volume size) */
-
发表了主题帖:
【国民技术高性能MCU N32H487开发板】spi测试与spi flash驱动
前言
这一篇,继续来测试SPI接口,实现SPI FLASH驱动,为后面文件系统做准备。
SPI驱动
添加spi的库
引脚这里使用SPI1 PA4/5/6/7 AF1
使用杜邦线外接SPI FLASH模块
Spi.c
初始化
#include "uart.h"
#include "fifo.h"
#include "n32h47x_48x.h"
#include "n32h47x_48x_spi.h"
#include "n32h47x_48x_rcc.h"
#include "n32h47x_48x_gpio.h"
void spi_init(int id, uint32_t baud, int mode)
{
if(id == 0){
/* PA4 NSS GPIO
* PB5 SCK AF1
* PB6 MISO AF1
* PB7 MOSI AF1
*/
RCC_EnableAHB1PeriphClk(RCC_AHB_PERIPHEN_GPIOA,ENABLE);
RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_SPI1,ENABLE);
GPIO_InitType GPIO_InitStructure;
/* Initialize GPIO_InitStructure */
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.GPIO_Alternate = GPIO_AF1;
GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_4;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
SPI_InitType SPI_InitStruct;
RCC_ClocksType RCC_clock;
RCC_GetClocksFreqValue(&RCC_clock);
uint32_t clk = RCC_clock.Pclk2Freq;
uint32_t div = clk/baud;
if(div<=2){
SPI_InitStruct.BaudRatePres = SPI_BR_PRESCALER_2;
}else if(div<=4){
SPI_InitStruct.BaudRatePres = SPI_BR_PRESCALER_4;
}else if(div<=8){
SPI_InitStruct.BaudRatePres = SPI_BR_PRESCALER_8;
}else if(div<=16){
SPI_InitStruct.BaudRatePres = SPI_BR_PRESCALER_16;
}else if(div<=32){
SPI_InitStruct.BaudRatePres = SPI_BR_PRESCALER_32;
}else if(div<=64){
SPI_InitStruct.BaudRatePres = SPI_BR_PRESCALER_64;
}else if(div<=128){
SPI_InitStruct.BaudRatePres = SPI_BR_PRESCALER_128;
}else{
SPI_InitStruct.BaudRatePres = SPI_BR_PRESCALER_256;
}
if(mode & 0x01){
SPI_InitStruct.CLKPHA = SPI_CLKPHA_SECOND_EDGE;
}else{
SPI_InitStruct.CLKPHA = SPI_CLKPHA_FIRST_EDGE;
}
if(mode & 0x02){
SPI_InitStruct.CLKPOL = SPI_CLKPOL_HIGH;
}else{
SPI_InitStruct.CLKPOL = SPI_CLKPOL_LOW;
}
SPI_InitStruct.CRCPoly = 0x0f;
SPI_InitStruct.DataDirection = SPI_DIR_DOUBLELINE_FULLDUPLEX;
SPI_InitStruct.DataLen = SPI_DATA_SIZE_8BITS;
SPI_InitStruct.FirstBit = SPI_FB_MSB;
SPI_InitStruct.NSS = SPI_NSS_SOFT;
SPI_InitStruct.SpiMode = SPI_MODE_MASTER;
SPI_Init(SPI1,&SPI_InitStruct);
SPI_Enable(SPI1,ENABLE);
}else if(id == 1){
}
}
传输接口
uint32_t spi_trans(int id, int cs, uint8_t* tx_buffer, uint8_t* rx_buffer, uint32_t len, int flag)
{
uint8_t rx;
if(id == 0){
if(cs == 0){
GPIO_WriteBits(GPIOA, GPIO_PIN_4, Bit_RESET);
}else if(cs == 1){
}
for(uint32_t i=0; i<len; i++){
while(SPI_I2S_GetStatus(SPI1, SPI_I2S_TE_FLAG) == 0);
if(tx_buffer != (uint8_t*)0){
SPI_I2S_TransmitData(SPI1, tx_buffer);
}else{
SPI_I2S_TransmitData(SPI1, 0xFF);
}
while(SPI_I2S_GetStatus(SPI1, SPI_I2S_RNE_FLAG) == 0);
rx = SPI_I2S_ReceiveData(SPI1);
if(rx_buffer != (uint8_t*)0){
rx_buffer = rx;
}
}
if(flag){
if(cs == 0){
GPIO_WriteBits(GPIOA, GPIO_PIN_4, Bit_SET);
}else if(cs == 1){
}
}
}else if(id == 1){
}
return len;
}
Spi.h
#ifndef SPI_H
#define SPI_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
void spi_init(int id, uint32_t baud, int mode);
uint32_t spi_trans(int id, int cs, uint8_t* tx_buffer, uint8_t* rx_buffer, uint32_t len, int flag);
#ifdef __cplusplus
}
#endif
#endif
SPI FLASH驱动
添加flash.c/h完全可移植
flash.c
#include <string.h>
#include "flash.h"
#define FLASH_CMD_WEL 0x06
#define FLASH_CMD_PAGEPROGRAM 0x02
#define FLASH_CMD_READ 0x03
#define FLASH_CMD_ERASESECTOR 0x20
#define FLASH_CMD_READSR1 0x05
#define FLASH_CMD_READSR2 0x35
#define FLASH_CMD_READSR3 0x15
#define FLASH_CMD_WRITESR1 0x01
#define FLASH_CMD_WRITESR2 0x31
#define FLASH_CMD_WRITESR3 0x11
#define FLASH_SR1_BUSY (1 << 0)
int flash_write_enable(flash_dev_st* dev)
{
uint8_t cmd = FLASH_CMD_WEL;
dev->spi_trans(&cmd, 0, 1, 1);
return 0;
}
int flash_read_sr1(flash_dev_st* dev, uint8_t* sr)
{
uint8_t cmd[2] = {FLASH_CMD_READSR1,0xFF};
uint8_t rx[2];
dev->spi_trans(cmd, rx, 2, 1);
*sr = rx[1];
return 0;
}
int flash_read_sr2(flash_dev_st* dev, uint8_t* sr)
{
uint8_t cmd[2] = {FLASH_CMD_READSR2,0xFF};
uint8_t rx[2];
dev->spi_trans(cmd, rx, 2, 1);
*sr = rx[1];
return 0;
}
int flash_read_sr3(flash_dev_st* dev, uint8_t* sr)
{
uint8_t cmd[2] = {FLASH_CMD_READSR3,0xFF};
uint8_t rx[2];
dev->spi_trans(cmd, rx, 2, 1);
*sr = rx[1];
return 0;
}
int flash_write_sr1(flash_dev_st* dev, uint8_t val)
{
uint8_t cmd[2] = {FLASH_CMD_WRITESR1,0};
cmd[1] = val;
dev->spi_trans(cmd, 0, 2, 1);
return 0;
}
int flash_write_sr2(flash_dev_st* dev, uint8_t val)
{
uint8_t cmd[2] = {FLASH_CMD_WRITESR2,0};
cmd[1] = val;
dev->spi_trans(cmd, 0, 2, 1);
return 0;
}
int flash_write_sr3(flash_dev_st* dev, uint8_t val)
{
uint8_t cmd[2] = {FLASH_CMD_WRITESR3,0};
cmd[1] = val;
dev->spi_trans(cmd, 0, 2, 1);
return 0;
}
int flash_wait_busy(flash_dev_st* dev)
{
uint8_t sr = 0;
do{
flash_read_sr1(dev, &sr);
} while(FLASH_SR1_BUSY & sr);
return 0;
}
int flash_erase_sector(flash_dev_st* dev, uint32_t addr)
{
uint8_t cmd[4];
flash_write_enable(dev);
cmd[0] = FLASH_CMD_ERASESECTOR;
cmd[1] = (uint8_t)(addr >> 16 & 0xFF);
cmd[2] = (uint8_t)(addr >> 8 & 0xFF);
cmd[3] = (uint8_t)(addr >> 0 & 0xFF);
dev->spi_trans(cmd, 0, 4, 1);
flash_wait_busy(dev);
return 0;
}
int flash_pageprogram(flash_dev_st* dev, uint8_t* buffer, uint32_t addr, uint32_t len)
{
uint8_t cmd[4];
cmd[0] = FLASH_CMD_PAGEPROGRAM;
cmd[1] = (uint8_t)(addr >> 16 & 0xFF);
cmd[2] = (uint8_t)(addr >> 8 & 0xFF);
cmd[3] = (uint8_t)(addr >> 0 & 0xFF);
flash_write_enable(dev);
dev->spi_trans(cmd, 0, 4, 0);
dev->spi_trans(buffer, 0, len, 1);
flash_wait_busy(dev);
return 0;
}
uint32_t flash_read(flash_dev_st* dev, uint8_t* buffer, uint32_t addr, uint32_t len)
{
uint8_t cmd[4];
cmd[0] = FLASH_CMD_READ;
cmd[1] = (uint8_t)(addr >> 16 & 0xFF);
cmd[2] = (uint8_t)(addr >> 8 & 0xFF);
cmd[3] = (uint8_t)(addr >> 0 & 0xFF);
dev->spi_trans(cmd, 0, 4, 0);
dev->spi_trans(0, buffer, len, 1);
return 0;
}
uint32_t flash_write(flash_dev_st* dev, uint8_t* buffer, uint32_t addr, uint32_t len)
{
/**
* | | | | |
* | |
* < len >
* addr
* <sec_head > < sec_tail >
* start_addr
*/
uint32_t sec_head;
uint32_t sec_tail = 0;
uint32_t sec_mid_num;
uint32_t start_addr;
uint32_t end_addr;
uint32_t fill;
start_addr = addr & (~(dev->sector_size-1));
end_addr = (addr+len) & (~(dev->sector_size-1));
sec_head = addr & (dev->sector_size-1);
if((end_addr != start_addr) || (sec_head == 0)){
sec_tail = (addr + len) & (dev->sector_size-1);
}
sec_mid_num = (end_addr - start_addr) >> dev->sector_bits;
if((sec_head != 0) || (sec_tail != 0)){
if(sec_mid_num > 1){
sec_mid_num--;
}else{
sec_mid_num = 0;
}
}
/* head */
if(sec_head > 0)
{
flash_read(dev,dev->buffer, start_addr, dev->sector_size);
fill =( len > (dev->sector_size-sec_head)) ? (dev->sector_size-sec_head) : len;
memcpy(dev->buffer+sec_head,buffer,len);
flash_erase_sector(dev,start_addr);
for (uint32_t j=0; j<16; j++) {
flash_pageprogram(dev,dev->buffer + (j<<dev->page_bits),start_addr + (j<<dev->page_bits), dev->page_size);
}
buffer += fill;
start_addr += dev->sector_size;
}
/* mid */
for(uint32_t i=0; i<sec_mid_num; i++)
{
flash_erase_sector(dev,start_addr);
for (uint32_t j=0; j<16; j++) {
flash_pageprogram(dev, buffer + (j<<dev->page_bits), start_addr + (j<<dev->page_bits), dev->page_size);
}
buffer += dev->sector_size;
start_addr += dev->sector_size;
}
/* tail */
if(sec_tail > 0)
{
flash_read(dev,dev->buffer+sec_tail, start_addr+sec_tail, dev->sector_size - sec_tail);
memcpy(dev->buffer,buffer,sec_tail);
flash_erase_sector(dev,start_addr);
for (uint32_t j=0; j<16; j++) {
flash_pageprogram(dev, dev->buffer + (j<<dev->page_bits),start_addr + (j<<dev->page_bits), dev->page_size);
}
}
return len;
}
flash.h
#ifndef FLASH_H
#define FLASH_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
typedef uint32_t (*flash_spi_io)(uint8_t* tx_buffer, uint8_t* rx_buffer, uint32_t len, int flag);
/**
* \struct flash_dev_st
* FLASH结构.
*/
typedef struct
{
flash_spi_io spi_trans; /**< spi传输接口 */
void* buffer; /**< sector缓存 */
uint32_t sector_size; /**< sector大小 */
uint32_t sector_bits; /**< sector大小 位数 */
uint32_t page_size; /**< page大小 */
uint32_t page_bits; /**< page大小 位数 */
} flash_dev_st;
/**
* \fn flash_read
* 读数据
* \param[in] dev \ref flash_dev_st
* \param[in] addr 读开始地址
* \param[out] buffer 存储读出的数据
* \param[in] len 待读出的长度
* \retval 返回实际读出的数据长度
*/
uint32_t flash_read(flash_dev_st* dev, uint8_t* buffer, uint32_t addr, uint32_t len);
/**
* \fn flash_write
* 写数据
* \param[in] dev \ref flash_dev_st
* \param[in] addr 写开始地址
* \param[out] buffer 存储待写的数据
* \param[in] len 待写入的长度
* \retval 返回实际写入的数据长度
*/
uint32_t flash_write(flash_dev_st* dev, uint8_t* buffer, uint32_t addr, uint32_t len);
#ifdef __cplusplus
}
#endif
#endif
Flash_itf.c/h实现接口
flash_itf.c
#include "flash_itf.h"
#include "flash.h"
#include "spi.h"
static flash_dev_st s_flash;
static uint8_t s_spiflash_buffer[4096];
static uint32_t spi_io(uint8_t* tx_buffer, uint8_t* rx_buffer, uint32_t len, int flag)
{
return spi_trans(0, 0, tx_buffer, rx_buffer, len, flag);
}
int flash_itf_init(void)
{
s_flash.spi_trans = spi_io;
s_flash.page_bits = 8;
s_flash.page_size = 256;
s_flash.sector_bits = 12;
s_flash.sector_size = 4096;
s_flash.buffer = s_spiflash_buffer;
return 0;
}
int flash_itf_deinit(void)
{
return 0;
}
uint32_t flash_itf_read(uint8_t* buffer, uint32_t addr, uint32_t len)
{
return flash_read(&s_flash, buffer, addr, len);
}
uint32_t flash_itf_write(uint8_t* buffer, uint32_t addr, uint32_t len)
{
return flash_write(&s_flash, buffer, addr, len);
}
flash_itf.h
#ifndef FLASH_ITF_H
#define FLASH_ITF_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/**
* \fn flash_itf_init
* 初始化
*/
int flash_itf_init(void);
/**
* \fn flash_itf_deinit
* 反初始化
*/
int flash_itf_deinit(void);
/**
* \fn flash_itf_read
* 读数据
* \param[in] addr 读开始地址
* \param[out] buffer 存储读出的数据
* \param[in] len 待读出的长度
* \retval 返回实际读出的数据长度
*/
uint32_t flash_itf_read(uint8_t* buffer, uint32_t addr, uint32_t len);
/**
* \fn flash_itf_write
* 写数据
* \param[in] addr 写开始地址
* \param[out] buffer 存储待写的数据
* \param[in] len 待写入的长度
* \retval 返回实际写入的数据长度
*/
uint32_t flash_itf_write(uint8_t* buffer, uint32_t addr, uint32_t len);
#ifdef __cplusplus
}
#endif
#endif
测试
shell_func.c中
#include "flash_itf.h"
static void printflashfunc(uint8_t* param);
static void writeflashfunc(uint8_t* param);
添加两行命令
{ (uint8_t*)"printflash", printflashfunc, (uint8_t*)"printflash addr[hex] len"},
{ (uint8_t*)"writeflash", writeflashfunc, (uint8_t*)"writeflash addr[hex] hexstr"},
实现如下
static int ascii2uc(const char c, unsigned char *uc)
{
if ((c >= '0') && (c <= '9')) {
*uc = c - '0';
} else if ((c >= 'a') && (c <= 'f')) {
*uc = c - 'a' + 10;
} else if ((c >= 'A') && (c <= 'F')) {
*uc = c - 'A' + 10;
} else {
return -1;
}
return 0;
}
static uint32_t str2hex(const char* str, unsigned char *buff, uint32_t len)
{
uint32_t num = 0;
uint8_t hex = 0;
while(1)
{
uint8_t tmp1;
uint8_t tmp2;
if(ascii2uc(*str++, &tmp1) < 0)
{
break;
}
if(ascii2uc(*str++, &tmp2) < 0)
{
break;
}
hex = tmp1*16 + tmp2;
*buff++ = hex;
num++;
if(num >= len)
{
break;
}
}
return num;
}
static void printflashfunc(uint8_t* param)
{
uint8_t buffer[16];
uint32_t addr;
uint32_t len;
if(2 == sscanf((const char*)param, "%*s %x %d", &addr, &len))
{
uint32_t toread;
uint32_t read = 0;
while(read < len)
{
toread = ((len-read) > sizeof(buffer)) ? sizeof(buffer) : (len-read);
flash_itf_read(buffer, addr+read, toread);
read += toread;
for(uint32_t i=0; i<toread ;i++)
{
xprintf("%02x ",buffer);
}
xprintf("\r\n");
}
}
}
static void writeflashfunc(uint8_t* param)
{
uint8_t buffer[32+1];
uint8_t hex[16];
uint32_t addr;
uint32_t len;
if(2 == sscanf((const char*)param, "%*s %x %s", &addr, buffer))
{
len = str2hex((const char*)buffer, hex, strlen((char*)buffer));
if(len>0)
{
flash_itf_write(hex,addr,len);
}
}
}
Main.c中初始化
#include "spi.h"
#include "flash_itf.h"
spi_init(0, 36000000ul, 0);
flash_itf_init();
看到增加了两个命令
读
写
读
可以看到写入后读出正确。
总结
以上实现了SPI驱动基于SPI FLASH驱动,可以进行FLASH的读写了,后面就可以基于此移植文件系统了。
-
发表了主题帖:
【国民技术高性能MCU N32H487开发板】标准输入输出和shell移植
前言
前面实现了串口的收发,基于此继续移植shell和printf,方便后面调试使用。
移植printf
这里移植xprintf,一个精简的标准输入输出库。
参考公众号文章
https://mp.weixin.qq.com/s/y4MHV3cd4T0b51L5M4J5Xg
代码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
适配接口
static void xprintf_out_port(int ch)
{
uint8_t val = ch;
uart_send(0,&val,1);
}
static int xprintf_in_port(void)
{
uint32_t len;
uint8_t val;
do
{
len = uart_read(0,&val,1);
}while(len == 0);
return val;
}
初始化指定接口
#include "xprintf.h"
xdev_out(xprintf_out_port);
xdev_in(xprintf_in_port);
移植shell
参考公众号文章
https://mp.weixin.qq.com/s/XLmbJn0SKoDT1aLdxHDrbg
适配接口
#include "shell.h"
#include "shell_func.h"
uint32_t shell_read(uint8_t *buff, uint32_t len)
{
return uart_read(0,buff,len);
}
void shell_write(uint8_t *buff, uint32_t len)
{
uart_send(0,buff,len);
}
shell_set_itf(shell_read, shell_write, (shell_cmd_cfg*)g_shell_cmd_list_ast, 1);
代码
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 64 /**< 命令缓冲区大小 */
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
#include <stdio.h>
#include "shell.h"
#include "shell_func.h"
#include "xprintf.h"
#include "uart.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},
};
static 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
测试
周期调用
shell_exec();
串口终端,输入help可以查看命令
总结
以上移植了标准输入输出接口,移植了shell,可以方便的增加命令,打印输出,进行调试了。
-
发表了主题帖:
【国民技术高性能MCU N32H487开发板】串口驱动与测试
前言
本文来测试串口收发,并基于fifo实现串口驱动,提供方便使用的串口读写接口。方便后续调试开发。
FIFO实现参考公众号文章
https://mp.weixin.qq.com/s/MvL9eDesyuxD60fnbl1nag
串口驱动实现参考上述公众号文章其他文章
引脚
使用PA9和PA10,连接到了板载的仿真器
串口初始化
引脚
PA9 AF17 TX
PA10 AF18 RX
引脚配置,时钟使能,串口配置,中断配置
RCC_EnableAHB1PeriphClk(RCC_AHB_PERIPHEN_GPIOA,ENABLE);
GPIO_InitType GPIO_InitStructure;
/* Initialize GPIO_InitStructure */
GPIO_InitStruct(&GPIO_InitStructure);
/* Configure USART3 Tx PA9 AF17 as alternate function push-pull */
GPIO_InitStructure.Pin = GPIO_PIN_9;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.GPIO_Alternate = GPIO_AF17;
GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
/* Configure USART3 Rx PA10 AF18 as alternate function push-pull */
GPIO_InitStructure.Pin = GPIO_PIN_10;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.GPIO_Alternate = GPIO_AF18;
GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_USART3,ENABLE);
USART_InitType USART_InitStructure;
/* USARTy and USARTz configuration */
USART_StructInit(&USART_InitStructure);
USART_InitStructure.BaudRate = baud;
USART_InitStructure.WordLength = USART_WL_8B;
USART_InitStructure.StopBits = USART_STPB_1;
USART_InitStructure.Parity = USART_PE_NO;
USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
USART_InitStructure.OverSampling = USART_16OVER;
USART_InitStructure.Mode = USART_MODE_RX | USART_MODE_TX;
/* Configure USART3 */
USART_Init(USART3, &USART_InitStructure);
/* Enable the USART3 */
USART_Enable(USART3, ENABLE);
USART_ConfigInt(USART3, USART_INT_RXDNE, ENABLE);
NVIC_SetPriority(USART3_IRQn,2);
NVIC_EnableIRQ(USART3_IRQn);
中断服务程序
收到数据写入fifo,并清除标志
void USART3_IRQHandler(void)
{
uint8_t ch;
ch = USART_ReceiveData(USART3);
USART_ClrFlag(USART3, USART_FLAG_RXDNE);
USART_ClrFlag(USART3, USART_FLAG_IDLEF);
USART_ClrFlag(USART3, USART_FLAG_OREF);
uart_rx_cb(0, &ch, 1);
}
发送
查询发送
uint32_t uart_send(int id, uint8_t* buffer, uint32_t len)
{
if(id == 0){
for(uint32_t i=0;i<len;i++)
{
while(USART_GetFlagStatus(USART3, USART_FLAG_TXC) == 0);
USART_SendData(USART3,buffer);
}
}else if(id == 1){
}
return len;
}
测试
Main.c中
#include "uart.h"
收到数据原样返回
int main(void)
{
uart_init(0,115200);
while (1)
{
uint8_t rx_buffer[64];
uint32_t len = uart_read(0,rx_buffer,sizeof(rx_buffer));
if(len > 0){
uart_send(0,rx_buffer,len);
}
}
}
上位机发送数据,板子原样返回
完整代码
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;
}
uint32_t fifo_getfree(fifo_st* dev)
{
if(dev == 0)
{
return 0;
}
return dev->buffer_len - dev->len;
}
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);
uint32_t fifo_getfree(fifo_st* dev);
#ifdef __cplusplus
}
#endif
#endif
Uart.c
#include "uart.h"
#include "fifo.h"
#include "n32h47x_48x.h"
#include "n32h47x_48x_rcc.h"
#include "n32h47x_48x_gpio.h"
#include "n32h47x_48x_exti.h"
#include "n32h47x_48x_usart.h"
#include "n32h47x_48x_dma.h"
#define CriticalAlloc()
#define EnterCritical() __disable_irq()
#define ExitCritical() __enable_irq()
uint8_t s_uart_rx0_buffer[1029];
uint8_t s_uart_rx1_buffer[16];
static fifo_st s_uart_fifo_dev[2]=
{
{
.in = 0,
.len = 0,
.out = 0,
.buffer = s_uart_rx0_buffer,
.buffer_len = sizeof(s_uart_rx0_buffer),
},
{
.in = 0,
.len = 0,
.out = 0,
.buffer = s_uart_rx1_buffer,
.buffer_len = sizeof(s_uart_rx1_buffer),
}
};
void uart_rx_cb(int id, uint8_t* buff, uint32_t len)
{
fifo_in(&(s_uart_fifo_dev[id]), buff, len);
}
void USART3_IRQHandler(void)
{
uint8_t ch;
ch = USART_ReceiveData(USART3);
USART_ClrFlag(USART3, USART_FLAG_RXDNE);
USART_ClrFlag(USART3, USART_FLAG_IDLEF);
USART_ClrFlag(USART3, USART_FLAG_OREF);
uart_rx_cb(0, &ch, 1);
}
void uart_init(int id, uint32_t baud)
{
if(id == 0){
RCC_EnableAHB1PeriphClk(RCC_AHB_PERIPHEN_GPIOA,ENABLE);
GPIO_InitType GPIO_InitStructure;
/* Initialize GPIO_InitStructure */
GPIO_InitStruct(&GPIO_InitStructure);
/* Configure USART3 Tx PA9 AF17 as alternate function push-pull */
GPIO_InitStructure.Pin = GPIO_PIN_9;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.GPIO_Alternate = GPIO_AF17;
GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
/* Configure USART3 Rx PA10 AF18 as alternate function push-pull */
GPIO_InitStructure.Pin = GPIO_PIN_10;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.GPIO_Alternate = GPIO_AF18;
GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_USART3,ENABLE);
USART_InitType USART_InitStructure;
/* USARTy and USARTz configuration */
USART_StructInit(&USART_InitStructure);
USART_InitStructure.BaudRate = baud;
USART_InitStructure.WordLength = USART_WL_8B;
USART_InitStructure.StopBits = USART_STPB_1;
USART_InitStructure.Parity = USART_PE_NO;
USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
USART_InitStructure.OverSampling = USART_16OVER;
USART_InitStructure.Mode = USART_MODE_RX | USART_MODE_TX;
/* Configure USART3 */
USART_Init(USART3, &USART_InitStructure);
/* Enable the USART3 */
USART_Enable(USART3, ENABLE);
USART_ConfigInt(USART3, USART_INT_RXDNE, ENABLE);
NVIC_SetPriority(USART3_IRQn,2);
NVIC_EnableIRQ(USART3_IRQn);
}else if(id == 1){
}
}
uint32_t uart_send(int id, uint8_t* buffer, uint32_t len)
{
if(id == 0){
for(uint32_t i=0;i<len;i++)
{
while(USART_GetFlagStatus(USART3, USART_FLAG_TXC) == 0);
USART_SendData(USART3,buffer[i]);
}
}else if(id == 1){
}
return len;
}
uint32_t uart_read(int id, uint8_t* buffer, uint32_t len)
{
uint32_t rlen;
CriticalAlloc();
EnterCritical();
rlen = fifo_out(&(s_uart_fifo_dev[id]), buffer, len);
ExitCritical();
return rlen;
}
Uart.h
#ifndef UART_H
#define UART_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
void uart_init(int id, uint32_t baud);
uint32_t uart_send(int id, uint8_t* buffer, uint32_t len);
uint32_t uart_read(int id, uint8_t* buffer, uint32_t len);
#ifdef __cplusplus
}
#endif
#endif
总结
以上实现了串口收发驱动,并进行了测试,提供了串口读写接口,方便后面使用。
-
发表了主题帖:
【国民技术高性能MCU N32H487开发板】系统跑240MHz并输出MCO时钟测试
前言
本文分享下系统使用HSE跑最大240MHz,并输出MCO时钟验证时钟正确性。
配置使用HSE
system_n32h47x_48x.c中
使用HSE PLL
#ifndef SYSCLK_SRC
#define SYSCLK_SRC SYSCLK_USE_HSE_PLL
#endif
HSE频率要和
n32h47x_48x.h中对应
#if !defined HSE_VALUE
#define HSE_VALUE (8000000U) /* Value of the External oscillator in Hz */
#endif /* HSE_VALUE */
原理图如下
J6 J9断开
默认系统跑240MHz
#ifndef SYSCLK_FREQ
#if defined (N32H473) || defined (N32H474)
#define SYSCLK_FREQ 200000000
#elif defined (N32H475) || defined (N32H482) || defined (N32H487)
#define SYSCLK_FREQ 240000000
#else
#error wrong macro definition
#endif
FLASH等待时间
如下自动根据系统频率设置FLASH等待时间,这里代码自动根据频率修改,无需手动去修改,更严谨,避免用户不知道或者忘记修改导致问题。
/* Flash wait state
0: HCLK <= 40M
1: HCLK <= 80M
2: HCLK <= 120M
3: HCLK <= 160M
4: HCLK <= 200M
5: HCLK <= 240M
*/
tmpregister = FLASH->AC;
tmpregister &= (uint32_t)((uint32_t)~FLASH_AC_LATENCY);
tmpregister |= (uint32_t)((SYSCLK_FREQ - 1) / 40000000);
FLASH->AC = tmpregister;
时钟输出
引脚
输出最大频率50MHz
测试
使用PLL分频
240MHz分频6得到40MHz,测试看到时钟是正确的。
void mco_init(void)
{
GPIO_InitType GPIO_InitStructure;
/* Initialize GPIO_InitStructure */
GPIO_InitStruct(&GPIO_InitStructure);
/* Configure MCO1 PA7 alternate function AF13 push-pull */
GPIO_InitStructure.Pin = GPIO_PIN_7;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.GPIO_Alternate = GPIO_AF13;
GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
RCC_ConfigMcoClkPre(RCC_MCO_PLLCLK_DIV6);
RCC_ConfigMco1(RCC_MCO_PLL_PRES);
}
实际直接输出系统时钟240MHz也是可以的,只是受限于引脚输出能力,幅值会无法达到摆幅。
RCC_ConfigMco1(RCC_MCO_SYSCLK);
总结
系统时钟可以跑240Mhz,时钟准确,这在MCU中是比较高的了。驱动库完善可以很方便的实现功能。库函数的注释也非常详细,参数注释详细,直接看h文件即可。
相比其他厂家同类型的库,这里在配置系统时钟后自动修改flash等待时间,相比其他库需要手动修改更严谨,避免用户忘记修改导致问题,这也体现厂家开发的细节值得点赞。
- 2025-03-30
-
发表了主题帖:
【国民技术高性能MCU N32H487开发板】开发环境搭建
前言
本文分享N32H48x的开发环境搭建。
官网下载资料
下载需要先注册登录
https://www.nationstech.com/support/dow/?typesof=1508下搜索N32H48
下载SDK
https://www.nationstech.com/support/dow/?typesof=1507下搜索N32H48
下载文档
下载开发板资料
https://bbs.eeworld.com.cn/elecplay/content/54b161d1
开发环境搭建
解压N32H48x_SDK.zip
双击
N32H48x_SDK\6-Software Development Kit\Nations.N32H48x_DFP.1.0.0.pack安装MDK的支持包。
如果提示错误,则右键点击pack文件,选择属性
打开方式选择为D:\Keil_v5\UV4\PackUnzip.exe
此时就可以直接双击安装。(我这里是MDK5.40)
安装位于
D:\Keil_v5\Packs\Nationstech\N32H48x_DFP\1.0.0
打开N32H48x_SDK\6-Software Development Kit\Nations.N32H47x_48x_Library.1.0.0\projects\n32h47x_48x_EVAL\examples\USART\Printf\MDK-ARM下的Printf.uvprojx
选择芯片型号
设置编译器
设置宏
修改选择编译的汇编文件
编译
设置仿真器
识别到芯片
添加下载算法
点击进入debug运行
看到串口打印如下,注意跳线连接
串口参数115200-8-n-1
总结
文档资料全面,比较规范,下载方便,在国内厂家中是非常难得的了。资料的搜索过滤批量下载也非常好用。
官网下载中心的文档最好按照芯片系列过滤划分,现在是所有的都是在一起的有点乱。
注意pack如果安装失败,需要选择关联程序PackUnzip.exe
建议mini USB换成type-c,至少也要换成micro usb了,mini usb线真的很少用了。
-
发表了主题帖:
【米尔-STM32MP257开发板试用体验】开箱与板载资源介绍视频
- 2025-03-25
-
回复了主题帖:
测评入围名单: 国民技术高性能MCU N32H487开发板
个人信息无误,确认可以完成测评分享计划
- 2025-03-14
-
回复了主题帖:
测评入围名单: 米尔-STM32MP257开发板
个人信息无误,确认可以完成评测计划
- 2025-03-09
-
回复了主题帖:
【EV1W0505B-Y-00A评测】隔离DC/DC选型?-看看MIE1W0505B
秦天qintian0303 发表于 2025-3-9 09:35
这个隔离高压有人测试吗?
这个不知道怎么测试,非专业人士,也没有设备。
不知道用打火机的打火器试试不知道可不可以
-
回复了主题帖:
【EV1W0505B-Y-00A评测】隔离DC/DC选型?-看看MIE1W0505B
lemonboard 发表于 2025-3-9 10:19
隔离高压没有办法测试吧!
难度 有点大吧!
这个不知道怎么测试,非专业人士,也没有设备。
不知道用打火机的打火器试试不知道可不可以
-
回复了主题帖:
【EV1W0505B-Y-00A评测】隔离DC/DC选型?-看看MIE1W0505B
PowerAnts 发表于 2025-3-9 10:19
十多年前我就预言,小功率转换器以后完全傻瓜化的,不管是什么应用,都是输入两个脚,输出两个脚。这一天应 ...
是的,集成度会越来越高,关注应用即可。