This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] MSP430FR5994:使用 LEA 进行矩阵多路复用

Guru**** 2388090 points
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1071474/msp430fr5994-using-lea-for-matrix-multiplications

部件号:MSP430FR5994

我希望在 LEA 上实施矩阵乘法。 我的每个操作阶段的矩阵尺寸依次如下:

[1,256]*[256,20]-->[1,20]*[1,10]-->[1,10]*[10,2]-->[1,2]

检查完 DSPLIB 提供的可用文档后,我发现由于 地址范围不足,乘法终止,因此无法使用 LEA 上的[256,20]矩阵。 此外,我更喜欢不使用“msp_match_mpy15()”函数,因为它与定点表示法配合使用,我不能承受矩阵乘法的下半部分。 我发现的另一种方法是使用 LEA 命令执行矩阵乘法和参考指南[slau850]- https://www.ti.com/lit/ug/slau850/slau850.pdf?ts=1642755710288&ref_url=https%253A%252F%252Fwww.ti.com%252Fproduct%252FMSP430FR5043%253FkeyMatch%253DMSP430FR5043 - 根据本指南,LEACMD_MAC,LEACMD_MPYMATRIX,LEACMD_MPYLONGMATRIX 函数也可用于执行上述操作。 不过,我在此有以下问题:

LEA 是否可以通过任何方式从存储在 MSP430普通内存中的位置访问大矩阵,而不是共享内存?

考虑到矩阵的各个方面,首先使用 LEA 是否有意义,因为我在整个论坛上读到,要建立 LEA 需要增加60-70个周期?

此外,我还看到“sp_match_mpy15()”函数包含一个使用硬件乘数的选项-如何启用硬件乘数来执行矩阵乘法,而不是因为我有一个可以在 MPY32上执行所需操作的平滑运行函数?  

如果需要更多信息,请告诉我。 谢谢你。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好,Siddhant,

    很抱歉稍后再回复。

    您想计算[256,20]矩阵吗?   

    这种尺寸应该小于8K,我认为这可以正常工作。

    并附上 LEA 代码示例(注册级别),可能对您有用。

    e2e.ti.com/.../LEACMD_5F005F00_MPYMATRIX.zip

    谢谢!

    此致

    约翰逊

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    谢谢你。 我将查看代码,然后尽早更新线程!

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    在所附的示例中,我尝试运行一个非常基本的示例,如下所示:  

    #include "msp430fr5994.h"
    
    #include "lea_params.h"
    #include "reference/reference_c.h"
    
    #include <math.h>
    #include <stdio.h>
    #include <stdint.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdbool.h>
    
    // Convert MSP430 address to internal LEA address mapping.
    #define LEA_CONVERT_ADDRESS(x)    ((uint16_t)(((uintptr_t)(x) >> 2) & 0xffff))
    
    // Convert LEA address to MSP430 address mapping.
    #define LEA_REVERT_ADDRESS(x)     ((uintptr_t)(((uint32_t)(x) << 2)))
    
    // Test Size
    #define VECTOR_SIZE       2
    
    // Q15 format -> 0.5 -> 0.5*2^15 = 32768
    const int16_t initInputA[VECTOR_SIZE][VECTOR_SIZE] = {{559, 393},
                                                          {444, 980}};
    const int16_t initInputB[VECTOR_SIZE][VECTOR_SIZE] = {{1,0},
                                                          {1,0}};
    
    #pragma DATA_SECTION(inputA, ".leaRAM");
    #pragma DATA_ALIGN(inputA, 4);
    int16_t inputA[VECTOR_SIZE][VECTOR_SIZE];
    
    #pragma DATA_SECTION(inputB, ".leaRAM");
    #pragma DATA_ALIGN(inputB, 4);
    int16_t inputB[VECTOR_SIZE][VECTOR_SIZE];
    
    #pragma DATA_SECTION(output, ".leaRAM");
    #pragma DATA_ALIGN(output, 4);
    int16_t output[VECTOR_SIZE][VECTOR_SIZE];
    
    #pragma DATA_SECTION(params, ".leaRAM");
    #pragma DATA_ALIGN(params, 4);
    LEA_raddmlParams params;
    
    int16_t outputGolden[VECTOR_SIZE][VECTOR_SIZE];
    
    volatile bool success = false;
    volatile uint16_t benchmark;
    
    void main(void)
    {
    
        WDTCTL = WDTPW | WDTHOLD;       // Stop watchdog timer
        PM5CTL0 &= ~LOCKLPM5;           // Clear lock bit
    
        CSCTL0_H = CSKEY_H;
        CSCTL3 = 0;
        CSCTL0_H = 0;
    
        /* Initialize LEASC. */
        LEACNF0 = LEALPR | LEAILPM;
        LEASCCNF1 = 0;
        LEASCCNF2 = 0;
        LEASCCNF2 |= LEASCMT >> 2;
        LEASCPMS1 = 0;
        LEASCPMS0 = 0;
        LEASCPMDST = 0;
        LEASCPMCTL |= LEASCCMDEN;  // Enable LEA by setting command enable
        LEASCIFG = LEASCPMCMDIFG | LEASCSDIIFG | LEASCOORIFG | LEASCCOVLIFG; // Clear all interrupt flags
        LEASCIE |= LEASCPMCMDIE; // Enable the command complete interrupt
    
        /* Load input data */
        memcpy(inputA,initInputA,sizeof(initInputA));
        memcpy(inputB,initInputB,sizeof(initInputB));
    
        /* Set parameters */
        params.vectorSize = VECTOR_SIZE;
        params.input2 = LEA_CONVERT_ADDRESS(inputB);
        params.output = LEA_CONVERT_ADDRESS(output);
        params.input1Offset = 1;
        params.input2Offset = 1;
        params.outputOffset = 1;
    
        /* Load source arguments to LEA. */
        LEASCPMS0 = LEA_CONVERT_ADDRESS(inputA);
        LEASCPMS1 = LEA_CONVERT_ADDRESS(&params);
    
        /* Invoke RAM command with interrupts. */
        LEAPMCB = LEACMD__MPYMATRIX | LEAITFLG1;
    
        /* Enable Interrupt & enter LPM0 mode. */
        __bis_SR_register(GIE + LPM0_bits);
    
        /* BREAK HERE, RAM version */
        __no_operation();
    
        while(1);
    }
    

    现在,我没有获得{559,0},{444,0}}作为输出-我只收到[0.0],[0]]。 如果将2x2矩阵视为4个元素的数组或1x4矩阵(如样本中给出的数组),情况也是如此。  据我所知,这必须是因为结果正确切换15次。 这正是我遇到问题的地方,我需要的是原始值,而不是偏移的结果。 是否可以获得原始格式的答案-在这种情况下,答案应该 是 -{559,0},{444,0}}? 如果需要更多信息,请告诉我。 谢谢你

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    如果使用 Q31例程,您可以或多或少地获得所需的内容。 您必须将数据存储为32位整数,这将占用您现有空间不足的空间。 硬件将来自自然 Q62的数据转换为 Q63。 因此,你必须撤消这64位的剩余位移。

    直接使用硬件乘积函数更好。 您可以一次将数据移动到一个256元素行以执行 LEA 点产品,但乘法所节省的电能可能会在移动数据时丢失。

    如果你只是坐着等待 LEA 硬件完成其操作,我看不到它如何节省大量能源。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    感谢大卫的详细回答。 这确实非常有帮助。 我将再次查看这些选项,并相应地继续操作。 我会将问题标记为已解决。