/* * 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_uwb.h" #include "mk_reset.h" #include "mk_clock.h" #include "mk_trace.h" #include "mk_misc.h" #include "mk_aes.h" #include "mk_lsp.h" #include "mk_power.h" #include "board.h" #ifndef RSSI_EN #define RSSI_EN 0 #endif // single tone power range: -20dBm ~ 10dBm, step: 0.5dB (+/-0.2dB); tx power = -20dBm + 0.5 * power_level (+/- 1.5dB). static const uint8_t power_table_CH9[][5] = { {0x0, 0x0, 0x0, 0x2, 0x2}, {0x0, 0x0, 0x0, 0x2, 0x2}, {0x0, 0x0, 0x0, 0x2, 0x2}, {0x0, 0x0, 0x0, 0x2, 0x2}, {0x0, 0x3, 0x0, 0x2, 0x2}, {0x1, 0x0, 0x0, 0x2, 0x2}, {0x1, 0x2, 0x0, 0x2, 0x2}, {0x0, 0x5, 0x1, 0x2, 0x2}, {0x2, 0x2, 0x0, 0x2, 0x2}, {0x3, 0x1, 0x0, 0x2, 0x2}, {0x2, 0x1, 0x1, 0x2, 0x2}, {0x2, 0x4, 0x1, 0x2, 0x2}, {0x1, 0x2, 0x2, 0x2, 0x2}, {0x1, 0x4, 0x2, 0x2, 0x2}, {0x3, 0x4, 0x1, 0x2, 0x2}, {0x2, 0x2, 0x2, 0x2, 0x2}, {0x2, 0x5, 0x2, 0x2, 0x2}, {0x0, 0x2, 0x7, 0x2, 0x2}, {0x0, 0x4, 0x7, 0x2, 0x2}, {0x0, 0x6, 0x7, 0x2, 0x2}, {0x1, 0x2, 0x7, 0x2, 0x2}, {0x1, 0x4, 0x7, 0x2, 0x2}, {0x1, 0x6, 0x7, 0x2, 0x2}, {0x2, 0x3, 0x7, 0x2, 0x2}, {0x2, 0x5, 0x7, 0x2, 0x2}, {0x3, 0x2, 0x7, 0x2, 0x2}, {0x3, 0x4, 0x7, 0x2, 0x2}, {0x4, 0x2, 0x7, 0x2, 0x2}, {0x4, 0x4, 0x7, 0x2, 0x2}, {0x4, 0x6, 0x7, 0x2, 0x2}, {0x5, 0x1, 0x7, 0x2, 0x2}, {0x5, 0x3, 0x7, 0x2, 0x2}, {0x5, 0x5, 0x7, 0x2, 0x2}, {0x6, 0x2, 0x7, 0x2, 0x2}, {0x6, 0x4, 0x7, 0x2, 0x2}, {0x6, 0x6, 0x7, 0x2, 0x2}, {0x7, 0x4, 0x7, 0x2, 0x2}, {0x8, 0x1, 0x7, 0x2, 0x2}, {0x9, 0x0, 0x7, 0x2, 0x2}, {0x9, 0x1, 0x7, 0x2, 0x2}, {0x9, 0x3, 0x7, 0x2, 0x2}, {0xa, 0x0, 0x7, 0x2, 0x2}, {0xa, 0x2, 0x7, 0x2, 0x2}, {0xb, 0x0, 0x7, 0x2, 0x2}, {0xb, 0x2, 0x7, 0x2, 0x2}, {0xc, 0x0, 0x7, 0x2, 0x2}, {0xb, 0x6, 0x7, 0x2, 0x2}, {0xc, 0x4, 0x7, 0x2, 0x2}, {0xc, 0x6, 0x7, 0x2, 0x2}, {0xd, 0x3, 0x7, 0x2, 0x3}, {0xc, 0x0, 0x7, 0x3, 0x3}, {0xc, 0x2, 0x7, 0x3, 0x3}, {0xc, 0x5, 0x7, 0x3, 0x3}, {0xc, 0x7, 0x7, 0x3, 0x3}, {0xd, 0x5, 0x7, 0x3, 0x3}, {0xd, 0x7, 0x7, 0x3, 0x3}, {0xd, 0x7, 0x7, 0x3, 0x3}, {0xd, 0x7, 0x7, 0x3, 0x3}, {0xd, 0x7, 0x7, 0x3, 0x3}, {0xd, 0x7, 0x7, 0x3, 0x3}, {0xd, 0x7, 0x7, 0x3, 0x3}, }; static const uint8_t power_table_CH5[][5] = { {0x0, 0x0, 0x0, 0x2, 0x2}, {0x0, 0x0, 0x0, 0x2, 0x2}, {0x0, 0x0, 0x0, 0x2, 0x2}, {0x0, 0x0, 0x0, 0x2, 0x2}, {0x0, 0x0, 0x0, 0x2, 0x2}, {0x0, 0x0, 0x0, 0x2, 0x2}, {0x0, 0x1, 0x0, 0x2, 0x2}, {0x0, 0x4, 0x0, 0x2, 0x2}, {0x0, 0x7, 0x0, 0x2, 0x2}, {0x1, 0x1, 0x0, 0x2, 0x2}, {0x1, 0x4, 0x0, 0x2, 0x2}, {0x1, 0x7, 0x0, 0x2, 0x2}, {0x2, 0x3, 0x0, 0x2, 0x2}, {0x1, 0x4, 0x1, 0x2, 0x2}, {0x1, 0x6, 0x1, 0x2, 0x2}, {0x3, 0x5, 0x0, 0x2, 0x2}, {0x2, 0x4, 0x1, 0x2, 0x2}, {0x3, 0x1, 0x1, 0x2, 0x2}, {0x3, 0x3, 0x1, 0x2, 0x2}, {0x4, 0x1, 0x1, 0x2, 0x2}, {0x4, 0x4, 0x1, 0x2, 0x2}, {0x2, 0x6, 0x2, 0x2, 0x2}, {0x3, 0x2, 0x2, 0x2, 0x2}, {0x1, 0x6, 0x3, 0x2, 0x2}, {0x2, 0x2, 0x3, 0x2, 0x2}, {0x1, 0x2, 0x7, 0x2, 0x2}, {0x1, 0x4, 0x7, 0x2, 0x2}, {0x3, 0x3, 0x3, 0x2, 0x2}, {0x2, 0x4, 0x4, 0x2, 0x2}, {0x2, 0x5, 0x7, 0x2, 0x2}, {0x3, 0x1, 0x7, 0x2, 0x2}, {0x3, 0x5, 0x4, 0x2, 0x2}, {0x4, 0x1, 0x7, 0x2, 0x2}, {0x4, 0x3, 0x7, 0x2, 0x2}, {0x5, 0x6, 0x3, 0x2, 0x2}, {0x5, 0x0, 0x7, 0x2, 0x2}, {0x5, 0x2, 0x7, 0x2, 0x2}, {0x5, 0x4, 0x7, 0x2, 0x2}, {0x6, 0x0, 0x7, 0x2, 0x2}, {0x6, 0x2, 0x7, 0x2, 0x2}, {0x6, 0x5, 0x7, 0x2, 0x2}, {0x6, 0x7, 0x7, 0x2, 0x2}, {0x7, 0x4, 0x7, 0x2, 0x2}, {0x7, 0x7, 0x4, 0x2, 0x2}, {0x8, 0x2, 0x7, 0x2, 0x2}, {0x8, 0x5, 0x7, 0x2, 0x2}, {0x9, 0x1, 0x7, 0x2, 0x2}, {0x9, 0x4, 0x7, 0x2, 0x2}, {0xa, 0x0, 0x7, 0x2, 0x2}, {0xa, 0x3, 0x7, 0x2, 0x2}, {0xa, 0x6, 0x7, 0x2, 0x2}, {0xb, 0x2, 0x7, 0x2, 0x2}, {0xb, 0x5, 0x7, 0x2, 0x2}, {0xc, 0x1, 0x7, 0x2, 0x2}, {0xc, 0x5, 0x7, 0x2, 0x2}, {0xd, 0x2, 0x7, 0x2, 0x2}, {0xc, 0x1, 0x7, 0x3, 0x3}, {0xc, 0x6, 0x7, 0x3, 0x3}, {0xd, 0x2, 0x7, 0x3, 0x3}, {0xe, 0x2, 0x7, 0x3, 0x3}, {0xe, 0x7, 0x7, 0x3, 0x3}, }; static const uint8_t power_table_CH2[][5] = { {0x0, 0x7, 0x0, 0x2, 0x2}, {0x1, 0x0, 0x0, 0x2, 0x2}, {0x0, 0x4, 0x1, 0x2, 0x2}, {0x0, 0x7, 0x1, 0x2, 0x2}, {0x2, 0x2, 0x0, 0x2, 0x2}, {0x1, 0x1, 0x1, 0x2, 0x2}, {0x1, 0x6, 0x1, 0x2, 0x2}, {0x3, 0x5, 0x0, 0x2, 0x2}, {0x4, 0x2, 0x0, 0x2, 0x2}, {0x2, 0x6, 0x1, 0x2, 0x2}, {0x3, 0x0, 0x1, 0x2, 0x2}, {0x3, 0x5, 0x1, 0x2, 0x2}, {0x5, 0x3, 0x0, 0x2, 0x2}, {0x4, 0x5, 0x1, 0x2, 0x2}, {0x2, 0x4, 0x2, 0x2, 0x2}, {0x2, 0x7, 0x2, 0x2, 0x2}, {0x5, 0x3, 0x1, 0x2, 0x2}, {0x5, 0x6, 0x1, 0x2, 0x2}, {0x6, 0x0, 0x1, 0x2, 0x2}, {0x6, 0x3, 0x1, 0x2, 0x2}, {0x2, 0x5, 0x3, 0x2, 0x2}, {0x2, 0x6, 0x3, 0x2, 0x2}, {0x1, 0x6, 0x4, 0x2, 0x2}, {0x1, 0x6, 0x7, 0x2, 0x2}, {0x2, 0x3, 0x4, 0x2, 0x2}, {0x2, 0x3, 0x7, 0x2, 0x2}, {0x2, 0x6, 0x7, 0x2, 0x2}, {0x3, 0x2, 0x7, 0x2, 0x2}, {0x3, 0x5, 0x7, 0x2, 0x2}, {0x3, 0x7, 0x7, 0x2, 0x2}, {0x4, 0x7, 0x4, 0x2, 0x2}, {0x5, 0x1, 0x4, 0x2, 0x2}, {0x5, 0x1, 0x7, 0x2, 0x2}, {0x5, 0x3, 0x7, 0x2, 0x2}, {0x5, 0x6, 0x7, 0x2, 0x2}, {0x6, 0x2, 0x7, 0x2, 0x2}, {0x6, 0x5, 0x7, 0x2, 0x2}, {0x7, 0x1, 0x7, 0x2, 0x2}, {0x7, 0x4, 0x7, 0x2, 0x2}, {0x8, 0x1, 0x4, 0x2, 0x2}, {0x8, 0x2, 0x7, 0x2, 0x2}, {0x8, 0x5, 0x7, 0x2, 0x2}, {0x9, 0x3, 0x4, 0x2, 0x2}, {0x9, 0x4, 0x7, 0x2, 0x2}, {0xa, 0x0, 0x7, 0x2, 0x2}, {0xa, 0x2, 0x7, 0x2, 0x2}, {0xa, 0x5, 0x7, 0x2, 0x2}, {0xa, 0x7, 0x7, 0x2, 0x2}, {0xb, 0x3, 0x7, 0x2, 0x2}, {0xb, 0x6, 0x7, 0x2, 0x2}, {0xc, 0x1, 0x7, 0x2, 0x2}, {0xc, 0x4, 0x7, 0x2, 0x2}, {0xd, 0x1, 0x7, 0x2, 0x2}, {0xe, 0x0, 0x7, 0x2, 0x2}, {0xe, 0x4, 0x7, 0x2, 0x2}, {0xf, 0x1, 0x7, 0x2, 0x2}, {0xf, 0x5, 0x7, 0x2, 0x2}, {0xe, 0x4, 0x7, 0x3, 0x3}, {0xf, 0x3, 0x7, 0x3, 0x3}, {0xf, 0x7, 0x7, 0x3, 0x3}, {0xf, 0x7, 0x7, 0x3, 0x3}, }; static const uint8_t power_table_CH12[][5] = { {0x0, 0x3, 0x2, 0x1, 0x0}, {0x0, 0x5, 0x2, 0x1, 0x0}, {0x0, 0x1, 0x3, 0x1, 0x0}, {0x0, 0x3, 0x3, 0x1, 0x0}, {0x1, 0x0, 0x3, 0x1, 0x0}, {0x1, 0x2, 0x3, 0x1, 0x0}, {0x2, 0x0, 0x3, 0x1, 0x0}, {0x2, 0x2, 0x3, 0x1, 0x0}, {0x3, 0x2, 0x3, 0x1, 0x0}, {0x3, 0x4, 0x3, 0x1, 0x0}, {0x4, 0x2, 0x3, 0x1, 0x0}, {0x0, 0x0, 0x3, 0x2, 0x0}, {0x0, 0x3, 0x3, 0x2, 0x0}, {0x0, 0x6, 0x3, 0x2, 0x0}, {0x1, 0x0, 0x3, 0x2, 0x0}, {0x1, 0x3, 0x3, 0x2, 0x0}, {0x1, 0x6, 0x3, 0x2, 0x0}, {0x2, 0x1, 0x3, 0x2, 0x0}, {0x2, 0x4, 0x3, 0x2, 0x0}, {0x2, 0x7, 0x3, 0x2, 0x0}, {0x3, 0x3, 0x3, 0x2, 0x0}, {0x0, 0x1, 0x7, 0x3, 0x0}, {0x0, 0x6, 0x7, 0x3, 0x0}, {0x1, 0x0, 0x4, 0x3, 0x0}, {0x1, 0x0, 0x7, 0x3, 0x0}, {0x1, 0x4, 0x7, 0x3, 0x0}, {0x1, 0x7, 0x7, 0x3, 0x0}, {0x2, 0x0, 0x7, 0x3, 0x0}, {0x2, 0x4, 0x7, 0x3, 0x0}, {0x2, 0x7, 0x7, 0x3, 0x0}, {0x3, 0x2, 0x7, 0x3, 0x0}, {0x3, 0x6, 0x7, 0x3, 0x0}, {0x4, 0x2, 0x7, 0x3, 0x0}, {0x4, 0x6, 0x7, 0x3, 0x0}, {0x5, 0x1, 0x4, 0x3, 0x0}, {0x5, 0x2, 0x7, 0x3, 0x0}, {0x5, 0x6, 0x7, 0x3, 0x0}, {0x6, 0x0, 0x7, 0x3, 0x0}, {0x6, 0x4, 0x7, 0x3, 0x0}, {0x6, 0x7, 0x7, 0x3, 0x0}, {0x7, 0x3, 0x7, 0x3, 0x0}, {0x7, 0x7, 0x7, 0x3, 0x0}, {0x8, 0x2, 0x7, 0x3, 0x0}, {0x8, 0x6, 0x7, 0x3, 0x0}, {0x9, 0x2, 0x7, 0x3, 0x0}, {0x9, 0x6, 0x7, 0x3, 0x0}, {0xa, 0x2, 0x7, 0x3, 0x0}, {0xa, 0x7, 0x7, 0x3, 0x0}, {0xb, 0x5, 0x7, 0x3, 0x0}, {0xc, 0x3, 0x7, 0x3, 0x0}, {0xc, 0x7, 0x7, 0x3, 0x0}, {0xd, 0x7, 0x7, 0x3, 0x0}, {0xe, 0x7, 0x7, 0x3, 0x0}, {0xe, 0x6, 0x7, 0x4, 0x0}, {0xe, 0x7, 0x7, 0x4, 0x3}, {0xe, 0x7, 0x7, 0x4, 0x3}, {0xe, 0x7, 0x7, 0x4, 0x3}, {0xe, 0x7, 0x7, 0x4, 0x3}, {0xe, 0x7, 0x7, 0x4, 0x3}, {0xe, 0x7, 0x7, 0x4, 0x3}, {0xe, 0x7, 0x7, 0x4, 0x3}, }; // DK G-001 static const int8_t uwb_power_table_CH2[] = { -29, -28, -28, -27, -27, -26, -26, -25, -25, -24, -24, -23, -23, -22, -22, -22, -21, -20, -20, -19, -19, -19, -18, -18, -17, -17, -16, -16, -15, -15, -14, -14, -14, -13, -13, -12, -11, -11, -10, -10, -9, -9, -8, -8, -8, -7, -7, -6, -6, -5, -5, -4, -4, -3, -2, -2, -1, -1, 0, 0, }; static const int8_t uwb_power_table_CH5[] = { -25, -25, -25, -25, -25, -25, -25, -25, -24, -24, -23, -22, -22, -22, -21, -21, -20, -20, -19, -19, -18, -18, -17, -17, -17, -16, -15, -15, -14, -14, -13, -13, -12, -12, -12, -11, -10, -10, -9, -9, -8, -8, -7, -7, -6, -6, -5, -5, -4, -3, -3, -2, -2, -2, -1, 0, 0, 1, 1, 2, }; static const int8_t uwb_power_table_CH9[] = { -27, -27, -27, -27, -27, -26, -26, -25, -25, -24, -23, -23, -22, -22, -22, -21, -21, -20, -20, -19, -19, -18, -18, -17, -17, -16, -16, -15, -15, -14, -14, -13, -13, -12, -12, -11, -10, -10, -9, -9, -8, -8, -7, -6, -6, -5, -5, -4, -4, -3, -3, -2, -2, -2, -1, -1, -1, -1, -1, -1, }; static const uint8_t (*power_table)[5] = power_table_CH9; extern int16_t ranging_ant_delays_get(uint8_t ant_idx); extern void ranging_ant_delays_set(uint8_t ant_idx, int16_t delay_ps); extern int pdoa_ant_delays_get(int16_t *delays, uint8_t rx_ant_num); extern int pdoa_ant_delays_set(int16_t *delays, uint8_t rx_ant_num); extern int pdoa_ant_space_set(int16_t ant_space); extern int pdoa_gain_set(int16_t *gain, uint8_t rx_ant_num); extern int pdoa_angle_offset_set(int16_t *angle_offset); __WEAK int16_t ranging_ant_delays_get(uint8_t ant_idx) { return 0; } __WEAK void ranging_ant_delays_set(uint8_t ant_idx, int16_t delay_ps) { } __WEAK int pdoa_ant_delays_get(int16_t *delays, uint8_t rx_ant_num) { return 0; } __WEAK int pdoa_ant_delays_set(int16_t *delays, uint8_t rx_ant_num) { return 0; } __WEAK int pdoa_ant_space_set(int16_t ant_space) { return 0; } __WEAK int pdoa_gain_set(int16_t *gain, uint8_t rx_ant_num) { return 0; } __WEAK int pdoa_angle_offset_set(int16_t *angle_offset) { return 0; } int uwb_open(void) { reset_module(RESET_MODULE_DPRX); reset_module(RESET_MODULE_DPTX); aes_open(AES_ID0, NULL); #ifdef UWB_AUDIO_EN #ifdef CELL_PHONE_EN mac_init(IRQ_PRIORITY_HIGH, 6, 1, PHY_PAYLOAD_LEN_MAX); #else mac_init(IRQ_PRIORITY_HIGH, 1, 6, PHY_PAYLOAD_LEN_MAX); #endif #else lsp_open(0, NULL); mac_init(IRQ_PRIORITY_HIGH, 3, 3, PHY_PAYLOAD_LEN_MAX); #endif #if RSSI_EN mac_rssi_calculation_en(1); #endif phy_init(IRQ_PRIORITY_NORMAL); phy_timer_open(1, IRQ_PRIORITY_HIGH); //LOG_INFO(TRACE_MODULE_DRIVER, "uwb_open\r\n"); return 0; } int uwb_close(void) { power_off_radio(); #ifndef UWB_AUDIO_EN lsp_close(); #endif aes_close(AES_ID0); clock_disable(CLOCK_MAC); mac_timer_close(); phy_timer_close(); return 0; } void uwb_rx_antenna_open(enum UWB_RX_ANT_T antenna_idx) { if (antenna_idx == UWB_RX_ANT_ALL) { // lna scan en REG_WRITE(0x40000628, 0x00); } else { // lna scan dis REG_WRITE(0x40000628, (1 << 6) | rx_ant_code[antenna_idx & 0x03]); #ifndef RADAR_EN LOG_INFO(TRACE_MODULE_DRIVER, "Open ANT%d\r\n", antenna_idx & 0x03); #endif } } void uwb_channel_switch(uint8_t ch_num) { // CH_NUM uint32_t value = REG_READ(0x40000404) & (~0xFU); REG_WRITE(0x40000404, value | ch_num); // LO calibrate REG_WRITE(0x40006000, 0x80000400); while ((REG_READ(0x40006004) & 0x00000008) == 0) { } if (ch_num >= 10) { #if HIGH_PERFORMANCE_MODE_EN REG_WRITE(0x40000600, 0x05000500); // rx LNA BM/CTANK port1 port0 REG_WRITE(0x40000604, 0x05000500); // rx LNA BM/CTANK port3 port2 #else REG_WRITE(0x40000600, 0x04000400); // rx LNA BM/CTANK port1 port0 REG_WRITE(0x40000604, 0x04000400); // rx LNA BM/CTANK port3 port2 #endif } else if (ch_num >= 5) { #if HIGH_PERFORMANCE_MODE_EN REG_WRITE(0x40000600, 0x05030503); // rx LNA BM/CTANK port1 port0 REG_WRITE(0x40000604, 0x05000500); // rx LNA BM/CTANK port3 port2 #else REG_WRITE(0x40000600, 0x04030403); // rx LNA BM/CTANK port1 port0 REG_WRITE(0x40000604, 0x04000400); // rx LNA BM/CTANK port3 port2 #endif } else { // low band #if HIGH_PERFORMANCE_MODE_EN REG_WRITE(0x40000600, 0x050f050f); // rx LNA BM/CTANK port1 port0 REG_WRITE(0x40000604, 0x050f050f); // rx LNA BM/CTANK port3 port2 #else REG_WRITE(0x40000600, 0x040f040f); // rx LNA BM/CTANK port1 port0 REG_WRITE(0x40000604, 0x040f040f); // rx LNA BM/CTANK port3 port2 #endif } if (ch_num == 12) { power_table = power_table_CH12; } else if (ch_num >= 9) { power_table = power_table_CH9; } else if (ch_num >= 5) { power_table = power_table_CH5; } else { // low band power_table = power_table_CH2; } } void uwb_tx_power_set(uint8_t tx_power_level) { uint32_t value; // PA value = REG_READ(0x400060c4) & ~((0x7fU << 7) | (0x7fU << 15) | (1U << 22)); uint32_t pa_code = ((uint32_t)(power_table[tx_power_level][0] & 0xF) << 3) | (power_table[tx_power_level][1] & 0x7); REG_WRITE(0x400060c4, value | (pa_code << 15) | (1U << 14) | (pa_code << 7) | (1U << 6)); // vgate // REG_WRITE(0x400060c8, 0xa013277d); value = REG_READ(0x400060c8) & ~((0x7U << 3) | (1U << 2)); uint32_t vgate_code = power_table[tx_power_level][2] & 0x7; REG_WRITE(0x400060c8, value | (vgate_code << 3) | (1U << 2)); // TXDAC config value = REG_READ(0x40000610) & ~(0x1fU); uint32_t txdac_cfg = ((power_table[tx_power_level][3] & 0x7U) << 2) | (power_table[tx_power_level][4] & 0x3); REG_WRITE(0x40000610, value | (txdac_cfg)); // dac dc offset REG_WRITE(0x4000602c, 0x000aa001); REG_WRITE(0x4000602c, 0x000aa000); delay_us(100); } int8_t uwb_tx_power_get(uint8_t ch_num, uint8_t tx_power_level) { int8_t uwb_power; if (ch_num >= 9) { uwb_power = uwb_power_table_CH9[tx_power_level]; } else if (ch_num >= 5) { uwb_power = uwb_power_table_CH5[tx_power_level]; } else { uwb_power = uwb_power_table_CH2[tx_power_level]; } return uwb_power; } static void uwb_tx_init(uint8_t tx_power_level) { // TX tank REG_WRITE(0x400060a0, 0x003ea812); REG_WRITE(0x400060a4, 0x5a9bd79d); REG_WRITE(0x400060a8, 0x49bd79d5); REG_WRITE(0x400060ac, 0x00000015); uint32_t value = REG_READ(0x40000234); REG_WRITE(0x40000234, value | 0x40); value = REG_READ(0x40000614) & ~(0x7U << 12); REG_WRITE(0x40000614, value | (2 << 12)); uwb_tx_power_set(tx_power_level); LOG_INFO(TRACE_NO_REPORT_HOST | TRACE_MODULE_DRIVER, "uwb_tx_init, power level %d\r\n", tx_power_level); } static void uwb_rx_init(void) { REG_WRITE(0x40006054, 0x00820820); REG_WRITE(0x40006058, 0x00820820); REG_WRITE(0x4000605c, 0x00820820); REG_WRITE(0x40006060, 0x00820820); REG_WRITE(0x40006050, 0x000FD502); REG_WRITE(0x40006090, 0x00550202); REG_WRITE(0x40006098, 0x00540001); REG_WRITE(0x40006098, 0x00540000); delay_us(100); REG_WRITE(0x40006090, 0x00540001); REG_WRITE(0x40006090, 0x00540000); delay_us(100); // Bypass LPF_DAC1 calibration REG_WRITE(0x40006090, 0x00540004); #if 0 // fix agc gain uint32_t filter_gain = 25; uint32_t lna_gain = 5; uint32_t gain = (1U << 31) | ((filter_gain & 0x1f) << 16) | (lna_gain & 0x7); REG_WRITE(0x40000700, gain); #endif LOG_INFO(TRACE_NO_REPORT_HOST | TRACE_MODULE_DRIVER, "uwb_rx_init\r\n"); } void uwb_calibration_params_set(uint8_t ch_num) { uint8_t ch_idx = CALIB_CH(ch_num); for (uint8_t i = 0; i < 4; i++) { ranging_ant_delays_set(i, board_param.ant_delays[ch_idx][i]); } LOG_INFO(TRACE_MODULE_DRIVER, "ToF ant delays %d %d %d %d\r\n", board_param.ant_delays[ch_idx][0], board_param.ant_delays[ch_idx][1], board_param.ant_delays[ch_idx][2], board_param.ant_delays[ch_idx][3]); pdoa_ant_delays_set(&board_param.pdoa_delays[ch_idx][0], 4); LOG_INFO(TRACE_MODULE_DRIVER, "PDoA delays %d %d %d %d\r\n", board_param.pdoa_delays[ch_idx][0], board_param.pdoa_delays[ch_idx][1], board_param.pdoa_delays[ch_idx][2], board_param.pdoa_delays[ch_idx][3]); pdoa_gain_set(&board_param.pdoa_gains[ch_idx][0], 4); LOG_INFO(TRACE_MODULE_DRIVER, "PDoA gains %d %d %d %d\r\n", board_param.pdoa_gains[ch_idx][0], board_param.pdoa_gains[ch_idx][1], board_param.pdoa_gains[ch_idx][2], board_param.pdoa_gains[ch_idx][3]); pdoa_ant_space_set(board_param.pdoa_ant_space); LOG_INFO(TRACE_MODULE_DRIVER, "PDoA ant space %d\r\n", board_param.pdoa_ant_space); pdoa_angle_offset_set(board_param.pdoa_offsets); LOG_INFO(TRACE_MODULE_DRIVER, "PDoA angle offsets %d %d\r\n", board_param.pdoa_offsets[0], board_param.pdoa_offsets[1]); } void *uwb_configure(uint8_t mode, uint8_t tx_power_level, const struct UWB_CONFIG_T *ppdu_params) { // RF config uwb_channel_switch(ppdu_params->ch_num); uwb_rx_antenna_open((enum UWB_RX_ANT_T)ppdu_params->rx_ant_id); // Generate PHY configuration void *sets_a = phy_params_generate(mode, HIGH_PERFORMANCE_MODE_EN, ppdu_params, NULL); LOG_INFO(TRACE_MODULE_DRIVER, "PHY params sets %08x\r\n", (uint32_t)sets_a); #if 0 // Update ppdu_params to generate a new parameter sets static uint32_t sets_b[128]; phy_params_generate(mode, HIGH_PERFORMANCE_MODE_EN, ppdu_params, sets_b); #endif // Select a PHY parameter sets to configure uwb_params_sets_switch(mode, sets_a); if (mode & PHY_TX) { uwb_tx_init(tx_power_level); } if (mode & PHY_RX) { uwb_rx_init(); } // MAC config mac_crc_mode_configure(ppdu_params->fcs_type); return sets_a; } void uwb_params_sets_switch(uint8_t mode, void *sets) { phy_params_sets_enable(sets); if (mode & PHY_TX) { phy_tx_regs_config(sets); } if (mode & PHY_RX) { phy_rx_regs_config(sets); } } /* 0: Immediately 1: Defer to TX 2: CSMA-CA TX */ int uwb_tx(uint8_t *pkt_data, uint16_t pkt_len, uint8_t scheduled_mode, uint32_t target_time) { int ret = 0; if (scheduled_mode == 2) { // Power on radio power_on_radio(1, 1); ret = mac_tx(EVT_MODE_MAC_FIX_PHY_ASAP, target_time, 0, pkt_data, pkt_len); } else if (scheduled_mode == 1) { power_on_radio(1, 0); ret = mac_tx(EVT_MODE_MAC_ASAP_PHY_FIX, target_time, 0, pkt_data, pkt_len); } else { power_on_radio(1, 0); ret = mac_tx(EVT_MODE_MAC_PHY_ASAP, 0, 0, pkt_data, pkt_len); } mac_start(); // LOG_INFO(TRACE_MODULE_DRIVER, "UWB TX %d\r\n", pkt_len); return ret; } int uwb_rx(uint8_t scheduled_mode, uint32_t target_time, uint32_t timeout_us) { int ret = 0; // Power on radio power_on_radio(0, 1); uint32_t lock = int_lock(); if (scheduled_mode) { ret = mac_rx(EVT_MODE_MAC_ASAP_PHY_FIX, target_time, US_TO_PHY_TIMER_COUNT(timeout_us)); } else { ret = mac_rx(EVT_MODE_MAC_PHY_ASAP, 0, US_TO_PHY_TIMER_COUNT(timeout_us)); } mac_start(); int_unlock(lock); // LOG_INFO(TRACE_MODULE_DRIVER, "UWB RX %d\r\n", timeout_us); return ret; } // cannot work at scheduled mode void uwb_rx_force_off(uint8_t int_rpt_dis) { while ((REG_READ(0x40000400) & 0x0f) == 6) { } if ((REG_READ(0x40000400) & 0x0f) == 7) { uint32_t lock = int_lock(); uint32_t ts = phy_timer_count_get() + 250; /* 2us timeout */ REG_WRITE(0x40000408, ts); /* cfg the rx timeout */ if (int_rpt_dis) { mac_current_rx_report_discard(); } int_unlock(lock); } } void uwb_tx_carrier_only(uint8_t on, uint8_t ch_num, uint8_t tx_power_level) { static uint32_t pwr_reg_value = 0; if (on) { // start uwb_tx_init(tx_power_level); uwb_channel_switch(ch_num); // Enable datapath TX clock SYSCON->SYS_CMU |= (1U << CLOCK_TX); pwr_reg_value = REG_READ(0x4000002C); REG_WRITE(0x4000002C, 0x42700000); REG_WRITE(0x40000704, 0x80000011); } else { // stop REG_WRITE(0x40000704, 0x0); if (pwr_reg_value != 0) { REG_WRITE(0x4000002C, pwr_reg_value); } // Disable datapath TX clock SYSCON->SYS_CMU &= ~(1U << CLOCK_TX); } } static uint8_t flag_uwb_sw_trx_start = 0; void uwb_blocking_tx_start(const uint8_t *pkt_data, uint16_t pkt_len, uint32_t timeout_ms) { flag_uwb_sw_trx_start = 1; LOG_INFO(TRACE_MODULE_DRIVER, "uwb_blocking_tx_start\r\n"); // Disable MAC interrupt NVIC_DisableIRQ(MAC_IRQn); // MAC_MODE_CONTROL REG_WRITE(0x5000A004, 0x00000009); REG_WRITE(0x5000A004, 0x0000000D); phy_tx_payload(pkt_data, pkt_len); // MAC_SOFT_MODE_CFG uint32_t value = REG_READ(0x5000A12C); uint16_t tx_buf_start = (TX_PAYLOAD_ADDR - 0x02080000) >> 2; REG_WRITE(0x5000A12C, (value & 0xffe00000) | (uint32_t)((pkt_len) << 11) | tx_buf_start); // SM 0 - immediate TRX, 1 - deferred TXR REG_READ(0x40000434); // TRIGGER_TIMING REG_READ(0x40000424); // mask tx int // value = REG_READ(0x5000A020) | (1 << 21) | (0x1f << 15); value = ~(4U << 15); REG_WRITE(0x5000A020, value); // Enable TX // MAC_SOFT_MODE_TRIG REG_WRITE(0x5000A130, 0x1); uint32_t elapsed_time = 0; uint32_t count = 0; uint32_t start = sys_timer_get(); while (flag_uwb_sw_trx_start) { while (sys_timer_get() - start < 624) // 10us { } // Trigger TX REG_WRITE(0x40000430, 0x1); start = sys_timer_get(); if (timeout_ms) { count++; if (count >= 100) { count = 0; elapsed_time++; if (elapsed_time >= timeout_ms) { flag_uwb_sw_trx_start = 0; } } } } #if 0 // wait TX done while ((REG_READ(0x5000A024) & (1 << 17)) == 0) { delay_us(100); } // Clear done flag REG_WRITE(0x5000A028, 0xFFFFFFFF); #endif LOG_INFO(TRACE_MODULE_DRIVER, "uwb_blocking_tx_start exit\r\n"); mac_restart(); } void uwb_blocking_rx_start(uint32_t timeout_ms, drv_callback_t callback) { flag_uwb_sw_trx_start = 1; LOG_INFO(TRACE_MODULE_DRIVER, "uwb_blocking_rx_start\r\n"); // Disable MAC interrupt NVIC_DisableIRQ(MAC_IRQn); // MAC_MODE_CONTROL - clear MAC (bug in software mode) REG_WRITE(0x5000A004, 0x00000009); REG_WRITE(0x5000A004, 0x0000000D); // MAC_SOFT_MODE_CFG uint32_t value = REG_READ(0x5000A12C); uint16_t rx_buf_start = (RX_PAYLOAD_ADDR - 0x02080000) >> 2; value = value & ~(0x7ffU << 21); REG_WRITE(0x5000A12C, value | (uint32_t)(rx_buf_start << 21)); // SM 0 - immediate TRX, 1 - deferred TXR REG_READ(0x40000434); // TRIGGER_TIMING REG_READ(0x40000424); // LOG_INFO(TRACE_MODULE_DRIVER, "MAC S %x\r\n", REG_READ(0x5000A024)); // mask rx int // value = REG_READ(0x5000A020) | (1 << 21) | (0x1f << 15); value = ~(2U << 15); REG_WRITE(0x5000A020, value); // Enable RX // MAC_SOFT_MODE_TRIG REG_WRITE(0x5000A130, 0x2); uint32_t elapsed_time = 0; uint32_t start; while (flag_uwb_sw_trx_start) { start = sys_timer_get(); // RX_TIMEOUT_CNT - 50ms value = REG_READ(0x40000418); REG_WRITE(0x40000408, value + MS_TO_PHY_TIMER_COUNT(50)); // Trigger RX REG_WRITE(0x40000430, 0x2); // wait RX done // wait MAC RX done // while ((REG_READ(0x5000A024) & (1 << 16)) == 0) // wait PHY RX done while ((REG_READ(0x40002038) & (1 << 26)) == 0) { delay_us(10); if (sys_timer_get() - start > __MS_TO_TICKS(51)) { LOG_INFO(TRACE_MODULE_DRIVER, "RX-Done wasn't set\r\n"); break; } } // Clear done flag REG_WRITE(0x5000A028, 0xFFFFFFFF); if (callback) { // TODO: report RX packet } if (timeout_ms) { elapsed_time += __TICKS_TO_MS(sys_timer_get() - start); if (elapsed_time >= timeout_ms) { flag_uwb_sw_trx_start = 0; } } } LOG_INFO(TRACE_MODULE_DRIVER, "uwb_blocking_rx_start exit\r\n"); mac_restart(); } void uwb_blocking_trx_stop(void) { flag_uwb_sw_trx_start = 0; LOG_INFO(TRACE_MODULE_DRIVER, "uwb_blocking_trx_stop\r\n"); }