chen
2024-11-08 cc432b761c884a0bd8e9d83db0a4e26109fc08b1
keil/include/drivers/mk_misc.c
对比新文件
@@ -0,0 +1,529 @@
/*
 * Copyright (c) 2019-2023 Beijing Hanwei Innovation Technology Ltd. Co. and
 * its subsidiaries and affiliates (collectly called MKSEMI).
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form, except as embedded into an MKSEMI
 *    integrated circuit in a product or a software update for such product,
 *    must reproduce the above copyright notice, this list of conditions and
 *    the following disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * 3. Neither the name of MKSEMI nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * 4. This software, with or without modification, must only be used with a
 *    MKSEMI integrated circuit.
 *
 * 5. Any software provided in binary form under this license must not be
 *    reverse engineered, decompiled, modified and/or disassembled.
 *
 * THIS SOFTWARE IS PROVIDED BY MKSEMI "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL MKSEMI OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "mk_misc.h"
#include "mk_dual_timer.h"
#include "mk_clock.h"
#include "mk_trace.h"
#include "mk_sleep_timer.h"
#include "mk_reset.h"
// #include "board.h"
uint32_t mk_chip_id(void)
{
    return REG_READ(0x4000000C);
}
void mk_chip_uuid(uint8_t *uuid)
{
    ASSERT(uuid, "uuid is null");
    uint8_t y = REG_READ_BYTE(0x40010074);
    uint8_t x = REG_READ_BYTE(0x40010075);
    uint8_t w = REG_READ_BYTE(0x40010076);
    uint8_t l = REG_READ_BYTE(0x4001007F) - 'A';
    uuid[0] = ((l << 3) & 0x80) | (y & 0x7F);
    uuid[1] = ((l << 4) & 0x80) | (x & 0x7f);
    uuid[2] = ((l << 5) & 0xE0) | (w & 0x1f);
    uuid[3] = REG_READ_BYTE(0x4001007A);
    uuid[4] = REG_READ_BYTE(0x4001007B);
    uuid[5] = REG_READ_BYTE(0x4001007C);
    uuid[6] = REG_READ_BYTE(0x4001007D);
    uuid[7] = REG_READ_BYTE(0x4001007E);
}
/* BOD */
static const struct BOD_BOR_CFG_T default_bod_cfg = {
    .level = BOD_BOR_TH_LVL0,
    .hyst = BOD_BOR_HYST_LVL0,
};
void bod_open(const struct BOD_BOR_CFG_T *cfg)
{
    const struct BOD_BOR_CFG_T *config = (cfg == NULL) ? &default_bod_cfg : cfg;
    // enable BOD
    uint32_t bod_bor_cfg = SYSCON->BOD_BOR;
    bod_bor_cfg &= 0xFF00FFFF;
    bod_bor_cfg |= SYSCON_BOD_EN_MSK | SYSCON_BOD_TH_SEL(config->level) | SYSCON_BOD_HYST_SEL(config->hyst);
    SYSCON->BOD_BOR = bod_bor_cfg;
    NVIC_SetPriority(BOD_IRQn, IRQ_PRIORITY_NORMAL);
    NVIC_ClearPendingIRQ(BOD_IRQn);
    NVIC_EnableIRQ(BOD_IRQn);
}
void bod_close(void)
{
    // disable BOD
    SYSCON->BOD_BOR &= ~SYSCON_BOD_EN_MSK;
    NVIC_DisableIRQ(BOD_IRQn);
    NVIC_ClearPendingIRQ(BOD_IRQn);
}
void BOD_IRQHandler(void)
{
}
/* BOR */
static const struct BOD_BOR_CFG_T default_bor_cfg = {
    .level = BOD_BOR_TH_LVL0,
    .hyst = BOD_BOR_HYST_LVL0,
};
void bor_open(const struct BOD_BOR_CFG_T *cfg)
{
    const struct BOD_BOR_CFG_T *config = (cfg == NULL) ? &default_bor_cfg : cfg;
    // enable BOR
    uint32_t bod_bor_cfg = SYSCON->BOD_BOR;
    bod_bor_cfg &= 0xFFFFFF00;
    bod_bor_cfg |= SYSCON_BOR_EN_MSK | SYSCON_BOR_TH_SEL(config->level) | SYSCON_BOR_HYST_SEL(config->hyst);
    SYSCON->BOD_BOR = bod_bor_cfg;
}
void bor_close(void)
{
    // disable BOD
    SYSCON->BOD_BOR &= ~SYSCON_BOR_EN_MSK;
}
/* SYS Timer */
uint32_t sys_timer_freq = 0;
void sys_timer_open(void)
{
    // DIV = 1    (max: ~68.8s,     resolution: ~16ns)
    // DIV = 16   (max: ~1101.2s,   resolution: ~256ns)
    // DIV = 256  (max: ~17620.3s   resolution: ~65us)
    struct DUAL_TIMER_CFG_T sys_timer_cfg = {
        .type = DUAL_TIMER_TYPE_FREERUNNING,
        .prescale = DUAL_TIMER_PRESCALE_DIV1,
        .width = DUAL_TIMER_SIZE_32BIT,
        .int_en = false,
        .load = 0xffffffff,
        .callback = NULL,
    };
    dual_timer_open(DUAL_TIMER_ID0, &sys_timer_cfg);
    dual_timer_start(DUAL_TIMER_ID0, sys_timer_cfg.load);
    uint16_t div = sys_timer_cfg.prescale == DUAL_TIMER_PRESCALE_DIV1 ? 1 : sys_timer_cfg.prescale == DUAL_TIMER_PRESCALE_DIV16 ? 16 : 256;
    sys_timer_freq = clock_get_frequency(CLOCK_APB_CLK) / div;
}
void sys_timer_close(void)
{
    dual_timer_close(DUAL_TIMER_ID0);
}
uint32_t sys_timer_get(void)
{
    return -dual_timer_get(DUAL_TIMER_ID0);
}
// max: 68829 us  (DIV = 1)
void sys_timer_delay_us(uint32_t time_us)
{
    uint32_t start = dual_timer_get(DUAL_TIMER_ID0);
    uint32_t ticks = __US_TO_TICKS(time_us);
    while (start - dual_timer_get(DUAL_TIMER_ID0) < ticks)
    {
    }
}
// max: 68829 ms  (DIV = 1)
void sys_timer_delay_ms(uint32_t time_ms)
{
    uint32_t start = dual_timer_get(DUAL_TIMER_ID0);
    uint32_t ticks = __MS_TO_TICKS(time_ms);
    while (start - dual_timer_get(DUAL_TIMER_ID0) < ticks)
    {
    }
}
/* MAC timer */
void mac_timer_open(drv_callback_t callback)
{
    // DIV = 1    (max: ~68.8s,     resolution: ~16ns)
    // DIV = 16   (max: ~1101.2s,   resolution: ~256ns)
    // DIV = 256  (max: ~17620.3s   resolution: ~65us)
    struct DUAL_TIMER_CFG_T mac_timer_cfg = {
        .type = DUAL_TIMER_TYPE_ONESHOT,
        .prescale = DUAL_TIMER_PRESCALE_DIV1,
        .width = DUAL_TIMER_SIZE_32BIT,
        .int_en = true,
        .load = 0xffffffff,
        .callback = NULL,
    };
    mac_timer_cfg.callback = callback;
    dual_timer_open(DUAL_TIMER_ID1, &mac_timer_cfg);
}
void mac_timer_close(void)
{
    dual_timer_close(DUAL_TIMER_ID1);
}
void mac_timer_start(uint32_t count)
{
    dual_timer_start(DUAL_TIMER_ID1, count);
    // board_led_on(BOARD_LED_1);
}
void mac_timer_stop(void)
{
    dual_timer_stop(DUAL_TIMER_ID1);
    // board_led_off(BOARD_LED_1);
}
/* SYS Tick */
static struct SYS_TICK_ENV_T sys_tick_env = {0};
void sys_tick_start(uint32_t ticks)
{
    ASSERT(ticks <= SysTick_LOAD_RELOAD_Msk + 1, "Reload value impossible\r\n");
    SysTick->LOAD = (uint32_t)(ticks - 1UL);                            /* set reload register */
    NVIC_SetPriority(SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL);    /* set Priority for Systick Interrupt */
    SysTick->VAL = 0;                                                   /* A write of any value clears the field to 0 */
    SysTick->CTRL = SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
}
uint32_t sys_tick_us(void)
{
    uint32_t lock = int_lock();
    uint32_t count = sys_tick_env.count;
    uint32_t load = SysTick->LOAD + 1;
    uint32_t val = SysTick->VAL;
    uint32_t flag_pending = REG_READ(0xE000ED04) & (1 << 26);
    if (flag_pending)
    {
        count += 1;
        val = load;
    }
    else if (val == 0)
    {
        val = load;
    }
    uint32_t tick_us = (count * 328 + (load - val)) * 30;
    int_unlock(lock);
    return tick_us;
}
uint32_t sys_tick_ms(void)
{
    uint32_t lock = int_lock();
    uint32_t count = sys_tick_env.count;
    uint32_t load = SysTick->LOAD + 1;
    uint32_t val = SysTick->VAL;
    uint32_t flag_pending = REG_READ(0xE000ED04) & (1 << 26);
    if (flag_pending)
    {
        count += 1;
        val = load;
    }
    else if (val == 0)
    {
        val = load;
    }
    uint32_t tick_ms = (count * 10 + (load - val) * 10 / 328);
    int_unlock(lock);
    return tick_ms;
}
uint32_t sys_tick_get(void)
{
    return sys_tick_env.count;
}
void sys_tick_callback_set(void (*callback)(void))
{
    sys_tick_env.callback = callback;
}
uint32_t sys_tick_elapse_ms(void)
{
    uint32_t lock = int_lock();
    uint32_t load = SysTick->LOAD + 1;
    uint32_t val = SysTick->VAL;
    uint32_t flag_pending = REG_READ(0xE000ED04) & (1 << 26);
    if (flag_pending)
    {
        val = 0;
    }
    else if (val == 0)
    {
        val = load;
    }
    uint32_t elapse_ms = (load - val) * 10 / 328;
    int_unlock(lock);
    return elapse_ms;
}
void sys_tick_pause(void)
{
    // Stop SysTick
    SysTick->CTRL = 0;
    uint32_t val = SysTick->VAL;
    uint32_t load = SysTick->LOAD + 1;
    uint32_t flag_pending = REG_READ(0xE000ED04) & (1 << 26);
    if (flag_pending)
    {
        sys_tick_env.count += 1;
        val = load;
        // clear pending systick interrupt
        REG_WRITE(0xE000ED04, (1 << 25));
    }
    else if (val == 0)
    {
        val = load;
    }
    // Store SysTick counter
    sys_tick_env.load = load;
    // SysTick->VAL cannot be set
    sys_tick_env.elapse += (load - val);
}
void sys_tick_resume(void)
{
    sys_tick_start(sys_tick_env.load);
    uint32_t slp_cnt = high_xtal_off_time();
    uint32_t cnt = slp_cnt / sys_tick_env.load;
    sys_tick_env.elapse += (slp_cnt - cnt * sys_tick_env.load);
    while (sys_tick_env.elapse >= sys_tick_env.load)
    {
        sys_tick_env.elapse -= sys_tick_env.load;
        cnt += 1;
    }
    sys_tick_env.count += cnt;
    if ((sys_tick_env.callback != NULL) && (cnt))
    {
        sys_tick_env.callback();
    }
}
void SysTick_Handler(void)
{
    // board_led_on(BOARD_LED_2);
    sys_tick_env.count++;
    if (sys_tick_env.callback != NULL)
    {
        sys_tick_env.callback();
    }
    // board_led_off(BOARD_LED_2);
}
void sys_reset(uint32_t error)
{
    //LOG_INFO(TRACE_MODULE_DRIVER, "system reboot%x", error);
    delay_us(10000);
    // reboot
    reset_module(RESET_MODULE_REBOOT);
}
void delay_us(uint32_t cnt)
{
#define SYSTEM_CLOCK_MHZ 62.4
// the larger LSLS bits the more accurate of this delay function but the shorter of available delay time
#define SYSTEM_CLOCK_LSLS_BITS 5
#define SYSTEM_CLOCK_LSLS (uint16_t)(SYSTEM_CLOCK_MHZ * (1 << SYSTEM_CLOCK_LSLS_BITS))
// you should adjust these num manually if SYSTEM_CLOCK_MHZ or SYSTEM_CLOCK_LSLS_BITS changes
#define SYSTEM_CLOCK_MULT_HI 0x07 // (uint8_t)((SYSTEM_CLOCK_LSLS & 0xFF00) >> 8)
#define SYSTEM_CLOCK_MULT_LO 0xCD // (uint8_t)(SYSTEM_CLOCK_LSLS & 0x00FF)
#define AAPCS_PREP_CYCLES 18
#define DELAY_LOOP_CYCLES 4
#if defined(__GNUC__) && !defined(__ARMCC_VERSION)
    __asm volatile(".syntax unified\n");
#endif
    __asm volatile(
        "cmp r0, #0\n"
        "beq exit%=\n"
        "push {r4,r5}\n"
        "movs r5, %[mult_hi]\n"
        "lsls r4, r5, #8\n"
        "movs r5, %[mult_lo]\n"
        "adds r4, r4, r5\n"
        "muls r0, r4\n"
        "lsrs r0, r0, %[shift]\n"
        "subs r0, r0, %[adjust]\n"
        "loop%=:\n"
        "subs r0, r0, %[decr]\n"
        "bhi loop%=\n"
        "pop {r4,r5}\n"
        "exit%=:\n"
    :
    : [mult_hi] "i"(SYSTEM_CLOCK_MULT_HI), [mult_lo] "i"(SYSTEM_CLOCK_MULT_LO), [shift] "i"(SYSTEM_CLOCK_LSLS_BITS), [adjust] "i"(AAPCS_PREP_CYCLES),
        [decr] "i"(DELAY_LOOP_CYCLES));
#if defined(__GNUC__) && !defined(__ARMCC_VERSION)
    __asm volatile(".syntax divided\n");
#endif
}
uint8_t count_bits(uint32_t value)
{
    uint8_t count = 0;
    while (value)
    {
        value &= value - 1;
        count++;
    }
    return count;
}
uint8_t search_byte_right_one(uint8_t value)
{
    uint8_t index = 1;
    if (value == 0)
    {
        return 0;
    }
    if ((value & 0x0F) == 0)
    {
        value >>= 4;
        index += 4;
    }
    if ((value & 0x03) == 0)
    {
        value >>= 2;
        index += 2;
    }
    if ((value & 0x01) == 0)
    {
        index += 1;
    }
    return index;
}
uint8_t byte_right_one_mask(uint8_t value)
{
    return (value & (~value + 1));
}
int32_t average_filter(int32_t input)
{
#define TOTAL_SAMPLES (5)
#if 1
    // arithmetical averaging
    static int32_t data_buffer[TOTAL_SAMPLES] = {0};
    static uint8_t data_num = 0;
    int64_t sum = 0;
    // if buffer is full, remove the oldest data
    if (data_num == TOTAL_SAMPLES)
    {
        data_num--;
    }
    // add a new data in buffer
    for (int i = data_num; i > 0; i--)
    {
        data_buffer[i] = data_buffer[i - 1];
        sum += data_buffer[i];
    }
    data_buffer[0] = input;
    sum += data_buffer[0];
    data_num++;
    return (int32_t)(sum / data_num);
#else
    // weighted averaging
#endif
}
int16_t mk_q7_to_s16(int16_t data)
{
    return (data / 128);
}
int16_t mk_s16_to_q7(int16_t data)
{
    return (data * 128);
}
float mk_q7_to_f32(int16_t data)
{
    return (float)(data / 128.0);
}
int16_t mk_f32_to_q7(float data)
{
    return (int16_t)(data * 128);
}