/* * 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 nTimer) { uint32_t i=0; for(i=0;i> 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); }