打印
[LKS32 软件]

LKS32AT085评测+DSP评测第二篇

[复制链接]
688|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zhanzr21|  楼主 | 2022-8-17 19:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 zhanzr21 于 2022-8-17 19:03 编辑

#申请原创#
上一篇文章中讲到DSP作为LKS32AT085的外设,  这个DSP还可以独立运行作为协处理器工作. 它与LKS32AT085的主核心CortexM0的区别如下:
1. 需要Cortex M0初始化代码和数据, 无法自动从Flash启动
2. 本身无中断, 可以引起Cortex M0的中断
3. 无Stack概念, 即DSP上运行的代码不能调用函数.
除此之外, 这个DSP属于凌欧的自主指令集, 目前是没有高级语言编译器的, 只有一个汇编器+模拟器的工具. 目前看来在上面开发程序还是比较费人工的, 希望厂家继续提高此处的开发者体验.

DSP程序运行基本模式

首先DSP中的代码不能自动启动,  需要Cortex M0初始化Code和data段. 一旦运行起来, Cortex M0即可以去做其他工作. 等DSP上的代码运行完了,  可以通过指令发起Cortex M0的外设中断, Cortex M0可以来取数据以及初始化下一次的运算.

这里以一个小例子来看看基本的DSP代码开发与使用: arctan和直角三角形求斜边长度的运算
DSP有一个数学函数, 输入直角三角形的两边(X,Y), 可以求取夹角以及斜边长度.

DSP作为外设
代码如下:

typedef struct str_arctan_result {
  uint16_t arctan;
  uint16_t mod;
} arctan_result;

typedef struct str_arctan_input {
  uint16_t x;
  uint16_t y;
} arctan_input;

arctan_result cpu_issue_arctan_mod(arctan_input input) {
  DSP_SC &= (~BIT2);
  DSP_CORDIC_X = input.x;
  DSP_CORDIC_Y = input.y;

  arctan_result res;
  res.arctan = DSP_CORDIC_ARCTAN;
  res.mod = DSP_CORDIC_MOD;

  return res;
}
验证一下结果:
DSP as a periph delta:0
2AAB, 2002
角度: 0x2AAB/0x7FFF = 0.33335367900631735 大约是π/3, 也就是60度.
斜边长: 0x2002 约等于0x1000的两倍. 可以看出是个30度,60度的直角三角形.

DSP单独运行

首先要写DSP上运行的代码
    LDRDHI  R3 R4 0x0
    ARCTAN  R5 R3 R4

        # insert dummy inst to wait for arctan finish
        ADD     R0 R0 R0
    ADD     R0 R0 R0
    ADD     R0 R0 R0
        ADD     R0 R0 R0
    ADD     R0 R0 R0
    ADD     R0 R0 R0
        ADD     R0 R0 R0
    ADD     R0 R0 R0
    ADD     R0 R0 R0
    ADD     R0 R0 R0
    ADD     R0 R0 R0
    ADD     R0 R0 R0
    ADD     R0 R0 R0
    ADD     R0 R0 R0
    ADD     R0 R0 R0
        # arctan is stored at 0x5 in dsp's data mem
        STRWI   R5 0x5
        # module is stored at 0x6 in dsp's data mem        
        STRWI        R6 0x6
    IRQ

    ADD     R0 R0 R0
    ADD     R0 R0 R0
    ADD     R0 R0 R0
    ADD     R0 R0 R0
将以上代码保存为arctan_simple.code, 其中arctan_simple为工程名
再准备一个DSP的数据文件, 保存为arctan_simple.data, 内容如下:
0x10001BB6
        0x00000000
其中0x10001BB6即为要运算的X,Y值. 0x00000000为对齐值, 实际使用中如果发现不补齐, 运算出问题. 原因文档中没有找到.
将上述两个文件放在模拟器相同的目录, 修改工程配置文件:
prj: arctan_simple
再运行模拟器(此处模拟器其实是模拟器+汇编器二合一).
$ ./LKS081DSP_Emulator.exe
LKS081 DSP Emulator v1.1
Released on 2020-3-9
Author: zhangwl@linkosemi.com
Copyright. 2020 LINKO Semiconductor Co.,Ltd. All Rights Reserved.
Current project is <arctan_simple>.
Reading in <arctan_simple.code>...
<arctan_simple.code> contains 24 asm instructions
Reading in <arctan_simple.data>...
<arctan_simple.data> contains 2 words

2022-08-17 11:38:53
<arctan_simple> Emulation is starting ...
Info: at Line 24: IRQ
IRQ generated and DSP halted when PC = 19.
<arctan_simple> Emulation Finished
3132us elapsed on Emulator.
24Cycles elapsed on DSP.

Final GPR snapshot is as below:
PC = 0x0000
R0 = 0x00000000
R1 = 0x00000000
R2 = 0x00000000
R3 = 0x00001000
R4 = 0x00001bb6
R5 = 0x00002aa0
R6 = 0x00001ff0
R7 = 0x00000000
请按任意键继续. . .
以上操作等于 汇编+模拟. 在同级目录下面可以看到output目录, 里面有模拟的日志和汇编出来的二进制代码.
二进制代码和上述.data文件拷贝到MCU的工程中, 就可以对DSP做初始化了.
Note: 对于同样的输入, 模拟器运行的结果与DSP作为外设时不一致.
0x2AAB vs 0x2AA0
0x2002 vs 0x1FF0
貌似误差很小, 其实是需要凌鸥的工程师重点看看, 误差从何而来.

打开output目录中arctan_simple.hex
0x0000f01c,
0x0000792b,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x0000b145,
0x0000b186,
0x0000e000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
这就是DSP要运行的二进制代码, 拷贝到MCU工程中去, 使之成为一个const的数组.
const uint32_t test_code_arctan_simple[] = {
0x0000f01c,
0x0000792b,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x0000b145,
0x0000b186,
0x0000e000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
};
另外上文的.data文件也需要类似处理:
const uint32_t test_data_arctan_simple[] = {
0x10001BB6,
0x00000000,
};
这一点实在想吐槽, 为啥生成代码时不能自动生成C语言的数组呢, 希望凌鸥的工程师能发发力, 把细节做好一点.
以下是MCU中初始化DSP的代码与数据的代码样例, 为简便没有使能DSP的中断, 使用了不断poll标志位的方式.
arctan_result dsp_issue_arctan_mod_poll(const uint32_t *code_ptr,
                                        const uint16_t code_u32_len,
                                        const uint32_t *data_ptr,
                                        const uint8_t data_u32_len) {
  volatile uint16_t arctan, mod;
  uint32_t i;

  // dsp data mem flush
  for (i = 0; i < 64; i++) {
    REG32(DSP_DATA_MEM_BASE + i * 4) = 0;
  }

  // dsp code mem flush
  for (i = 0; i < 512; i++) {
    REG32(DSP_CODE_MEM_BASE + i * 4) = 0;
  }

  // dsp data mem init
  for (i = 0; i < data_u32_len; i++) {
    REG32(DSP_DATA_MEM_BASE + i * 4) = data_ptr[i];
  }

  // dsp code mem init
  // code length 200 half word
  for (i = 0; i < code_u32_len; i++) {
    REG32(DSP_CODE_MEM_BASE + i * 4) = code_ptr[i];
  }

        // Pause DSP
        DSP_SC |= BIT1;
        // Reset DSP PC
        DSP_SC |= BIT2;
        // Clear the IRQ flag
        DSP_SC |= BIT0;

        // Start DSP
        DSP_SC = BIT0;
        
        // wait until irq set and dsp paused
        while ((BIT0) != (DSP_SC & (BIT0))) {
      __WFI();
        }
        
  arctan_result res;
  res.arctan = REG32(DSP_DATA_MEM_BASE + 5 * 4);
  res.mod = REG32(DSP_DATA_MEM_BASE + 6 * 4);
  return res;
}
来看看结果:
DSP standalone delta:1
2AAC, 2002
Note: 对于同样的输入, 模拟器运行的结果/DSP作为外设/DSP单独运行全部不一致.
0x2AAB        vs                0x2AA0                  vs               0x2AAC
0x2002         vs                0x1FF0                  vs               0x2002
貌似误差很小, 但作者实在想知道究竟是哪个地方不精确呢.

希望官方工程师能注意到这些误差, 后面能做相应的更正.

DSP指令一览
如上所述, 这个DSP没有Stack的概念, 导致不能调用函数, 这个不算bug, 因为本身设计目标不是一个完整的内核, 而是辅助数**算的协处理器.
这里把它的指令集和与Cortex M0的指令集放在一起做一个简短的对比.
Cortex M0指令集DSP指令集
整数运算ADCSADD
ADDADDI
ANDSSUB
ASRSASR
CMNASRI
CMPLSL
EORSLSLI
LSLSMAC
LSRSMACI
MULSDIV
ORRSSAT
REVSATI
REV16
REVSH
RORS
RSBS
SBCS
SUB
SXTB
SXTH
TST
BICS
UXTB
UXTH
三角函数SIN_COS
ARCTAN
其他函数SQRT
数据存取ADRLDRWI
LDMLDRDHI
LDRSTRWI
LDRB
LDRHSTRDHI
LDRSB
LDRSH
MOV
MRS
MSR
PUSH
POP
STM
STR
STRB
STRH
分支跳转BJUMP
BXJUMPI
JLE
JLEI
控制BKPTIRQ
WFINOP
WFE
CPSID
CPSIE
DMB
DSB
ISB
MVNS
NOP
SEV
SVC
总体而言, 这个DSP内核缺乏Stack相关指令, 缺乏条件判断指令, 缺乏中断相关指令, 比起Cortex M0, 多了一些数学函数, 多了除法指令. 这也是符合本身的定位的.

本文完整的测试代码下载地址点这里.





使用特权

评论回复
沙发
明天真的好| | 2022-8-23 09:10 | 只看该作者
这个做的很不错了,感谢楼主的分享。

使用特权

评论回复
板凳
kiwis66| | 2022-8-23 20:51 | 只看该作者
那俩图,想表达什么

使用特权

评论回复
地板
鸥芯电驱港港| | 2022-10-11 20:59 | 只看该作者
感谢楼主的分享,这篇DSP测评全是干货。

使用特权

评论回复
5
zhanzr21|  楼主 | 2022-10-12 21:53 | 只看该作者
如果有机会, 我想跟官方的工程师交流下, 关于模拟器/硬件DSP 计算结果目前有些不一致, 虽然不算大问题, 想搞清楚原因

使用特权

评论回复
6
上下而求索| | 2022-10-13 08:50 | 只看该作者
zhanzr21 发表于 2022-10-12 21:53
如果有机会, 我想跟官方的工程师交流下, 关于模拟器/硬件DSP 计算结果目前有些不一致, 虽然不算大问题, 想 ...

这个可以的,zhaojie@linkosemi.com,可以把联系方式发邮箱里。

使用特权

评论回复
7
laocuo1142| | 2022-10-13 16:19 | 只看该作者
这是一篇受官方认可的测评贴啊,点赞支持

使用特权

评论回复
评论
zhanzr21 2022-10-13 20:56 回复TA
互相学习 
8
lcr12| | 2022-10-17 16:07 | 只看该作者
lks08系列带dsp核,可以计算电机相关的参数,而电网的相关参数跟三相资粮电机的参数非常相似,既然能计算电机的数据,也可以用到电网上计算FFT实现谐波计算

使用特权

评论回复
9
大道知简行不简| | 2022-12-19 00:18 | 只看该作者
这么测试DSP, 还是没有发挥出应有的性能,例程太简单,远不如直接用官方的Clark park PID纯DSP独立运行例程测试来的直接。可能维护论坛的原厂工程师对DSP也不大熟悉吧。评测第一名,有点水。。。@zhanzr21 @鸥芯电驱港港 @上下而求索

使用特权

评论回复
10
zhanzr21|  楼主 | 2022-12-19 10:58 | 只看该作者
本帖最后由 zhanzr21 于 2022-12-19 11:19 编辑
大道知简行不简 发表于 2022-12-19 00:18
这么测试DSP, 还是没有发挥出应有的性能,例程太简单,远不如直接用官方的Clark park PID纯DSP独立运行例程 ...

谢谢指点,这个确实是我学习凌鸥的硬件DSP的第一篇评测,理解还不深.
选简单的例子是为了说明硬件特性.
发评测贴主要希望分享交流.

使用特权

评论回复
11
Cheky| | 2022-12-19 23:14 | 只看该作者
大道知简行不简 发表于 2022-12-19 00:18
这么测试DSP, 还是没有发挥出应有的性能,例程太简单,远不如直接用官方的Clark park PID纯DSP独立运行例程 ...

官方的Clark park PID纯DSP独立运行例程哪里下载??

使用特权

评论回复
12
大道知简行不简| | 2023-1-13 12:05 | 只看该作者
Cheky 发表于 2022-12-19 23:14
官方的Clark park PID纯DSP独立运行例程哪里下载??

发个官方的参考DSP代码

foc_app.rar

2.23 KB

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:每天都進步

91

主题

1011

帖子

34

粉丝