# 06.02_DSP-开方

## 测试步骤

使用硬件dsp进行除法计算

## 实测数据

a | DSP_Sqrt(a) | err
--- | --- | ---
0 (0x00000000) | 0 | 0
1 (0x00000001) | 1 | 0
10 (0x0000000a) | 3 | 0
100 (0x00000064) | 10 | 0
1000 (0x000003e8) | 31 | 0
10000 (0x00002710) | 100 | 0
32767 (0x00007fff) | 181 | 0
65535 (0x0000ffff) | 255 | 0
65536 (0x00010000) | 256 | 0
65536 (0x00010000) | 256 | 0
131072 (0x00020000) | 362 | 0
262144 (0x00040000) | 512 | 0
524288 (0x00080000) | 724 | 0
1048576 (0x00100000) | 1024 | 0
2097152 (0x00200000) | 1448 | 0
4194304 (0x00400000) | 2048 | 0
8388608 (0x00800000) | 2896 | 0
16777216 (0x01000000) | 4096 | 0
33554432 (0x02000000) | 5792 | 0
67108864 (0x04000000) | 8192 | 0
134217728 (0x08000000) | 11585 | 0
268435456 (0x10000000) | 16384 | 0
536870912 (0x20000000) | 23170 | 0
1073741824 (0x40000000) | 32768 | 0
2147483648 (0x80000000) | 46340 | 0
1 (0x00000001) | 1 | 0
3 (0x00000003) | 1 | 0
7 (0x00000007) | 2 | 0
15 (0x0000000f) | 3 | 0
31 (0x0000001f) | 5 | 0
63 (0x0000003f) | 7 | 0
127 (0x0000007f) | 11 | 0
255 (0x000000ff) | 15 | 0
511 (0x000001ff) | 22 | 0
1023 (0x000003ff) | 31 | 0
2047 (0x000007ff) | 45 | 0
4095 (0x00000fff) | 63 | 0
8191 (0x00001fff) | 90 | 0
16383 (0x00003fff) | 127 | 0
32767 (0x00007fff) | 181 | 0
65535 (0x0000ffff) | 255 | 0
8191 (0x00001fff) | 90 | 0
16383 (0x00003fff) | 127 | 0
32767 (0x00007fff) | 181 | 0
65535 (0x0000ffff) | 255 | 0
131071 (0x0001ffff) | 362 | 0
262143 (0x0003ffff) | 511 | 0
524287 (0x0007ffff) | 724 | 0
1048575 (0x000fffff) | 1023 | 0
2097151 (0x001fffff) | 1448 | 0
4194303 (0x003fffff) | 2047 | 0
8388607 (0x007fffff) | 2896 | 0
16777215 (0x00ffffff) | 4095 | 0
33554431 (0x01ffffff) | 5792 | 0
67108863 (0x03ffffff) | 8191 | 0
134217727 (0x07ffffff) | 11585 | 0
268435455 (0x0fffffff) | 16383 | 0
536870911 (0x1fffffff) | 23170 | 0
1073741823 (0x3fffffff) | 32767 | 0
2147483647 (0x7fffffff) | 46340 | 0
4294967295 (0xffffffff) | 65535 | 0

time = 107

## 参考代码

06.02_DSP_Sqrt.c

    /**
     * @brief DSP-开方
     * @details 使用硬件dsp进行除法计算
     */
    #include "lks32mc09x_dsp.h"
    #include "lks32mc09x_timer.h"
    volatile int a = 10000;
    volatile int y;
    volatile int time;
    void Timer0_Init(void);
    /**
     * @brief 主函数，用于测试HSI时钟输出及GPIO翻转
     */
    int main(void)
    {
        DSP_Init();
        Timer0_Init();

        while (1)
        {
            TIMER_StatisticsStart(TIMER0);
            y = DSP_Sqrt(a);
            time = TIMER_StatisticsStop(TIMER0);
        }
    }
    /**
     * @brief 配置定时器0，用来统计除法执行时间
     */
    void Timer0_Init(void)
    {
        TIMER_TimerInitTypeDef TIMER_InitStruct;
        TIMER_StructInit(&TIMER_InitStruct);

        TIMER_InitStruct.EN = 1;
        TIMER_InitStruct.TH = 0xffff;

        TIMER_Init(TIMER0, &TIMER_InitStruct);
        TIMER_Enable(TIMER0);
    }
    #include "math.h"

## 使用到的库函数

库函数部分代码

    #define REG_RESET(reg,mask) reg &= ~(mask)
    #define REG_SET(reg,mask) reg |= (mask)
    #define REG_WRITE(reg,mask) reg = (mask)
    #define SYS0 ((SYS_TypeDef *)(SYS_BASE))
    #define SYS_MODULE_DSP0 BIT17
    #define SYS_MODULE_TIMER0 BIT4
    #define SYS_MODULE_TIMER1 BIT5
    #define SYS_MODULE_TIMER2 BIT6
    #define TIMER0 ((TIMER_TypeDef *)TIMER0_BASE)
    #define TIMER1 ((TIMER_TypeDef *)TIMER1_BASE)
    #define TIMER2 ((TIMER_TypeDef *)TIMER2_BASE)
    /**
     * @brief Timer初始化结构体
     */
    typedef struct TIMER_TimerInitTypeDef {
        uint8_t EN;
        uint32_t CAP1_CLR_EN;
        uint32_t CAP0_CLR_EN;
        uint32_t ONE_TRIG;
        uint32_t CENTER;
        uint32_t DIR;
        uint32_t ClockDiv;
        uint32_t ETON;
        uint32_t GATE_EN;
        uint32_t RL_EN;
        uint32_t XCLK_EN;
        uint32_t SRC1;
        uint32_t CH1Output;
        uint32_t CH1_WorkMode;
        uint32_t CH1_FE_CAP_EN;
        uint32_t CH1_RE_CAP_EN;
        uint32_t SRC0;
        uint32_t CH0Output;
        uint32_t CH0_WorkMode;
        uint32_t CH0_FE_CAP_EN;
        uint32_t CH0_RE_CAP_EN;
        uint32_t TH;
        uint32_t CNT;
        uint32_t CHN0;
        uint32_t CHN1;
        uint32_t EVT;
        uint32_t FLT;
        uint32_t IE;
        uint32_t CMP0_TRIGGER_MODE;
        uint32_t CMP1_TRIGGER_MODE;
        uint32_t SHADOW;
        uint32_t CH1_DEFAULT;
        uint32_t CH0_DEFAULT;
        uint32_t HALT_PRT;
        uint32_t FAIL_SEL;
        uint32_t FAIL_POL;
        uint32_t FAIL_EN;
        uint32_t MOE;
    };
    /**
     * @brief Timer初始化
     * @param TIMERx Timer实例指针
     * @param TIMER_InitStruct Timer初始化结构体指针
     */
    void TIMER_Init(TIMER_TypeDef *TIMERx, TIMER_TimerInitTypeDef *TIMER_InitStruct)
    {
        uint32_t th = TIMER_InitStruct->TH;
        TIMER_Enable(TIMERx);
        if (TIMERx != TIMER2) // 只有timer2是32位定时器
        {
            if (th > 0xffff)
            {
                th = 0xffff;
            }
            else
            {
                __NOP();
            }
        }
        else
        {
            __NOP();
        }
        // 配置Timer寄存器
        TIMERx->CFG2 = (TIMER_InitStruct->EN << 15) |
                       (TIMER_InitStruct->ONE_TRIG << 9) |
                       (TIMER_InitStruct->CENTER << 8) |
                       (TIMER_InitStruct->DIR << 6) |
                       (TIMER_InitStruct->ClockDiv << 4) |
                       (TIMER_InitStruct->ETON << 3) |
                       (TIMER_InitStruct->GATE_EN << 2) |
                       (TIMER_InitStruct->RL_EN << 1) |
                       TIMER_InitStruct->XCLK_EN;

        TIMERx->CFG0 = (TIMER_InitStruct->CMP0_TRIGGER_MODE << 9) |
                       (TIMER_InitStruct->CAP0_CLR_EN << 8) |
                       (TIMER_InitStruct->SRC0 << 4) |
                       (TIMER_InitStruct->CH0Output << 3) |
                       (TIMER_InitStruct->CH0_WorkMode << 2) |
                       (TIMER_InitStruct->CH0_FE_CAP_EN << 1) |
                       (TIMER_InitStruct->CH0_RE_CAP_EN << 0);

        TIMERx->CFG1 = (TIMER_InitStruct->CMP1_TRIGGER_MODE << 9) |
                       (TIMER_InitStruct->CAP1_CLR_EN << 8) |
                       (TIMER_InitStruct->SRC1 << 4) |
                       (TIMER_InitStruct->CH1Output << 3) |
                       (TIMER_InitStruct->CH1_WorkMode << 2) |
                       (TIMER_InitStruct->CH1_FE_CAP_EN << 1) |
                       (TIMER_InitStruct->CH1_RE_CAP_EN << 0);

        TIMERx->CHN0 = TIMER_InitStruct->CHN0;
        TIMERx->CHN1 = TIMER_InitStruct->CHN1;
        TIMERx->TH   = th;
        TIMERx->CNT  = TIMER_InitStruct->CNT;
        TIMERx->EVT  = TIMER_InitStruct->EVT;
        TIMERx->FLT  = TIMER_InitStruct->FLT;
        TIMERx->IE   = TIMER_InitStruct->IE;

        TIMERx->IO = (TIMER_InitStruct->HALT_PRT << 7) |
                     (TIMER_InitStruct->CH0_DEFAULT << 8) |
                     (TIMER_InitStruct->CH1_DEFAULT << 9) |
                     (TIMER_InitStruct->MOE << 6) |
                     (TIMER_InitStruct->FAIL_SEL << 2) |
                     (TIMER_InitStruct->FAIL_POL << 1) |
                     (TIMER_InitStruct->FAIL_EN << 0);

        // 影子寄存器配置
        TIMERx->CFG2 |= (TIMER_InitStruct->SHADOW << 10);
    }
    /**
     * @brief Timer结构体初始化
     * @param TIMER_InitStruct Timer初始化结构体指针
     */
    void TIMER_StructInit(TIMER_TimerInitTypeDef *TIMER_InitStruct)
    {
        for (int i = 0; i < sizeof(TIMER_TimerInitTypeDef) / sizeof(uint32_t); i++)
        {
            ((uint32_t *)TIMER_InitStruct)[i] = 0;
        }
    }
    /**
     * @brief 使能Timer
     * @param TIMERx Timer实例指针
     */
    void TIMER_Enable(TIMER_TypeDef *TIMERx)
    {
        if (TIMERx == TIMER0)
        {
            SYS_ModuleClockCmd(SYS_MODULE_TIMER0, ENABLE);
        }
        else if (TIMERx == TIMER1)
        {
            SYS_ModuleClockCmd(SYS_MODULE_TIMER1, ENABLE);
        }
        else if (TIMERx == TIMER2)
        {
            SYS_ModuleClockCmd(SYS_MODULE_TIMER2, ENABLE);
        }
        else
        {
            __NOP();
        }
    }
    /**
     * @brief 初始化DSP模块
     *
     * 该函数用于初始化DSP模块，使其处于可用状态。
     */
    void DSP_Init(void)
    {
        SYS_ModuleClockCmd(SYS_MODULE_DSP0, ENABLE);
        SYS_SoftResetModule(SYS_MODULE_DSP0);
    }
    /**
     * @brief 数字模块时钟使能
     * @param nModule 模块编号
     * @param state 使能或禁用状态
     */
    void SYS_ModuleClockCmd(uint32_t nModule, uint8_t state)
    {
        REG_WRITE(SYS0->PROTECT, 0x7a83);
        if (state)
        {
            REG_SET(SYS0->CLK_FEN, nModule);
        }
        else
        {
            REG_RESET(SYS0->CLK_FEN, nModule);
        }
        REG_WRITE(SYS0->PROTECT, 0);
    }
    /**
     * @brief 计算平方根
     *
     * @param val 输入值
     * @return 平方根值
     */
    uint16_t DSP_Sqrt(uint32_t val)
    {
        DSP0_RAD = val;
        return DSP0_SQRT;
    }
    /**
     * @brief 软复位模块
     * @param nModule 模块编号
     */
    void SYS_SoftResetModule(uint32_t nModule)
    {
        REG_WRITE(SYS0->PROTECT, 0x7a83);
        REG_SET(SYS0->SFT_RST, nModule);
        REG_RESET(SYS0->SFT_RST, nModule); // 触发复位后需清除复位位
        REG_WRITE(SYS0->PROTECT, 0);
    }