From 08ce770c988ff9c5add3826a9fcaf6e0bb062aa6 Mon Sep 17 00:00:00 2001 From: "qing.han" Date: Wed, 17 Nov 2021 19:47:51 +0800 Subject: [PATCH 1/2] update code from chip_phy6220 --- components/controller/rf_phy_driver.h | 79 +---- components/driver/inc/flash_phy6220.h | 163 +++++++++ components/driver/inc/gpio.h | 1 + components/driver/src/clock.c | 2 + components/driver/src/gpio.c | 14 + components/driver/src/kscan.c | 1 - components/driver/src/phy_adc.c | 91 ++--- components/driver/src/pinmux.c | 3 + components/dut/dut_test.c | 202 ++++++++++-- components/inc/mcu.h | 6 +- components/osal/include/comdef.h | 2 + csi_drivers/ck_irq.c | 16 +- csi_drivers/dw_dmac.c | 28 +- csi_drivers/dw_usart.c | 359 ++++++++++++++++++-- csi_drivers/dw_wdt.c | 9 +- csi_drivers/phy_rtc.c | 4 +- csi_drivers/spif.c | 210 +++++++++++- flash/TG7120B_Flash.elf | Bin 79664 -> 81844 bytes include/dw_dmac.h | 1 + include/soc.h | 3 +- include/spif.h | 49 +++ misc/rom_sym_def.h | 12 +- package.yaml | 1 + phy_pmu.c | 25 +- pm.c | 459 +++++++++++++++++++++----- port_s.S | 2 +- reboot.c | 45 ++- startup.S | 3 - system.c | 27 +- trap_c.c | 18 +- 30 files changed, 1503 insertions(+), 332 deletions(-) create mode 100644 components/driver/inc/flash_phy6220.h diff --git a/components/controller/rf_phy_driver.h b/components/controller/rf_phy_driver.h index 79449bd..b09f10e 100755 --- a/components/controller/rf_phy_driver.h +++ b/components/controller/rf_phy_driver.h @@ -270,6 +270,9 @@ extern volatile uint32_t g_dtmAccessCode ; #define RF_PHY_DTM_MANUL_MAX_GAIN 0x08 #define RF_PHY_DTM_MANUL_ALL 0xFF + +#define RF_PHY_DEFAULT_XTAL_CAP 0x09 +#define RF_PHY_DEFAULT_FREQOFF RF_PHY_FREQ_FOFF_00KHZ /******************************************************************************* * FUNCION DEFINE */ @@ -295,74 +298,18 @@ uint8_t rf_phy_direct_test_ate(uint32_t cmdWord, uint8_t regPatchNum, uint32 void rf_phy_dtm_zigbee_pkt_gen(void); -/************************************************************************************** - * @fn rf_phy_dtm_ext_rx_demod_burst - * - * @brief This function process for rf phy direct test, test mode interup - * - * input parameters - * - * @param rfChnIdx : rf channel = 2402+(rfChnIdx<<1) - * rfFoff : rf freq offset = rfFoff*4KHz - * pktLength : pkt length(Byte) - * rxWindow : rx demod window length(us) - * rxTimeOut : rx on time (ms) - * - * output parameters - * - * @param rxEstFoff : rx demod estimated frequency offset - * rxEstRssi : rx demod estimated rssi - * rxEstCarrSens : rx demod estimated carrier sense - * rxPktNum : rx demod received pkt number - * - * @return none - */ +void rf_phy_dtm_ext_tx_singleTone(uint8_t txPower, uint8_t rfChnIdx,uint8_t xtal_cap,int8_t rfFoff ,uint32 testTimeUs); +void rf_phy_dtm_ext_tx_modulation(uint8_t txPower, uint8_t rfChnIdx,uint8_t xtal_cap,int8_t rfFoff ,uint8_t pktType,uint32 testTimeUs); +void rf_phy_dtm_ext_tx_mod_burst(uint8_t txPower, uint8_t rfChnIdx,uint8_t xtal_cap,int8_t rfFoff , + uint8_t pktType, uint8_t pktLength,uint32 txPktNum,uint32 txPktIntv); void rf_phy_dtm_ext_rx_demod_burst(uint8_t rfChnIdx,int8_t rfFoff,uint8_t xtal_cap,uint8_t pktLength,uint32 rxTimeOut,uint32 rxWindow, int16_t* rxEstFoff,uint8_t* rxEstRssi,uint8_t* rxEstCarrSens,uint16_t* rxPktNum); - -/************************************************************************************** - * @fn rf_phy_dtm_ext_tx_mt_burst - * - * @brief This function process for rf phy direct test, test mode interup - * - * input parameters - * - * @param txPower : rf tx power - * rfChnIdx : rf channel = 2402+(rfChnIdx<<1) - * rfFoff : rf freq offset = rfFoff*4KHz - * pktType : modulaiton data type, 0: prbs9, 1: 1111000: 2 10101010 - * pktLength : pkt length(Byte) - * - * txPktNum : burst pkt tx number - * txPktIntv : txPkt intv,0 txPkt intv is pkt interval = ceil((L+249)/625) * 625 - * - * output parameters - * - * @param none - * - * @return none - */ -void rf_phy_dtm_ext_tx_mod_burst(uint8_t txPower, uint8_t rfChnIdx,uint8_t xtal_cap,int8_t rfFoff , +void rf_phy_dtm_tx_singleTone(uint8_t rfPhyPktFmt,uint8_t txPower, uint8_t rfChnIdx,uint8_t xtal_cap,int8_t rfFoff ,uint32 testTimeUs); +void rf_phy_dtm_tx_modulation(uint8_t rfPhyPktFmt,uint8_t txPower, uint8_t rfChnIdx,uint8_t xtal_cap,int8_t rfFoff ,uint8_t pktType,uint32 testTimeUs); +void rf_phy_dtm_tx_mod_burst(uint8_t rfPhyPktFmt,uint8_t txPower, uint8_t rfChnIdx,uint8_t xtal_cap,int8_t rfFoff , uint8_t pktType, uint8_t pktLength,uint32 txPktNum,uint32 txPktIntv); +void rf_phy_dtm_rx_demod_burst(uint8_t rfPhyPktFmt,uint8_t rfChnIdx,int8_t rfFoff,uint8_t xtal_cap,uint8_t pktLength,uint32 rxTimeOut,uint32 rxWindow, + int16_t* rxEstFoff,uint8_t* rxEstRssi,uint8_t* rxEstCarrSens,uint16_t* rxPktNum); -/************************************************************************************** - * @fn rf_phy_dtm_ext_tx_singleTone - * - * @brief This function process for rf phy direct test, test mode interup - * - * input parameters - * - * @param txPower : rf tx power - * rfChnIdx : rf channel = 2402+(rfChnIdx<<1) - * rfFoff : rf freq offset = rfFoff*4KHz - * testTimeUs : test loop active time(ms) - * - * output parameters - * - * @param none - * - * @return none - */ -void rf_phy_dtm_ext_tx_singleTone(uint8_t txPower, uint8_t rfChnIdx,uint8_t xtal_cap,int8_t rfFoff ,uint32 testTimeUs); - +void rf_phy_dtm_ext_acc_code_set(uint32 accCode); #endif diff --git a/components/driver/inc/flash_phy6220.h b/components/driver/inc/flash_phy6220.h new file mode 100644 index 0000000..61ac26b --- /dev/null +++ b/components/driver/inc/flash_phy6220.h @@ -0,0 +1,163 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/******************************************************************************* +* @file flash.h +* @brief Contains all functions support for flash driver +* @version 0.0 +* @date 27. Nov. 2017 +* @author qing.han +* +* Copyright(C) 2016, PhyPlus Semiconductor +* All rights reserved. +* +*******************************************************************************/ +#ifndef _FLASH_H_ +#define _FLASH_H_ + +#include "rom_sym_def.h" + +#include "types.h" +#include "gpio.h" + + + +//define flash ucds +#define FLASH_UCDS_ADDR_BASE 0x11005000 + +#define CHIP_ID_LENGTH 64 +#define CHIP_ID_PID_LEN 16 +#define CHIP_ID_LID_LEN 10 +#define CHIP_ID_MID_LEN 16 +#define CHIP_ID_TID_LEN 14 +#define CHIP_ID_SID_LEN 8 + +#define CHIP_MADDR_LEN 6 + +typedef enum { + CHIP_ID_UNCHECK, + CHIP_ID_EMPTY, + CHIP_ID_VALID, + CHIP_ID_INVALID, +} CHIP_ID_STATUS_e; + +typedef struct { + CHIP_ID_STATUS_e chipIdStatus; + uint8_t pid[CHIP_ID_PID_LEN]; + uint8_t lid[CHIP_ID_LID_LEN]; + uint8_t mid[CHIP_ID_MID_LEN]; + uint8_t tid[CHIP_ID_TID_LEN]; + uint8_t sid[CHIP_ID_SID_LEN]; +} chipId_t; + +typedef struct { + CHIP_ID_STATUS_e chipMAddrStatus; + uint8_t mAddr[CHIP_MADDR_LEN]; +} chipMAddr_t; + +extern chipId_t g_chipId; +extern chipMAddr_t g_chipMAddr; + + +uint32_t WriteFlash(uint32_t offset, uint8_t *pvalue, uint32_t len); +uint32_t WriteFlashByte(uint32_t offset, uint8_t value); +uint32_t WriteFlashShort(uint32_t offset, uint16_t value); +uint32_t WriteFlashWord(uint32_t offset, uint32_t value); + +uint32_t ReadFlash(uint32_t offset, uint8_t *value, uint32_t len); +uint32_t ReadFlashByte(uint32_t offset, uint8_t *value); +uint32_t ReadFlashShort(uint32_t offset, uint16_t *value); +uint32_t ReadFlashWord(uint32_t offset, uint32_t *value); + +uint32_t flash_block64_erase(uint32_t addr); +uint32_t flash_sector_erase(uint32_t addr); +uint32_t flash_all_erase(void); + +uint8_t flash_write_ucds(uint32_t addr, uint32_t value); +uint32_t flash_read_ucds(uint32_t addr); +void flash_erase_ucds_all(void); +uint8_t flash_erase_ucds(uint32_t addr); +uint8_t flash_write_ucds_block(uint32_t addr, uint32_t length, uint32_t *buf); +uint8_t flash_read_ucds_block(uint32_t addr, uint32_t length, uint32_t *tobuf); +uint8_t flash_write_ucds_block_byte(uint32_t addr, uint32_t length, uint8_t *buf); +uint8_t flash_read_ucds_block_byte(uint32_t addr, uint32_t length, uint8_t *tobuf); + + +void check_chip_id(void); +void check_chip_mAddr(void); +void LOG_CHIP_ID(void); +void LOG_CHIP_MADDR(void); + +/******************************************************************************* + * @fn pplus_enter_programming_mode + * + * @brief force deive enter to programing mode. + * + * input parameters + * + * @param none. + * + * output parameters + * + * @param none. + * + * @return none. + */ +void pplus_enter_programming_mode(void); + + +/******************************************************************************* + * @fn pplus_LoadMACFromChipMAddr + * + * @brief Used to load MAC Address from chip Maddr + * + * input parameters + * + * @param None. + * + * output parameters + * + * @param None. + * + * @return CHIP_ID_STATUS_e. + */ +extern CHIP_ID_STATUS_e pplus_LoadMACFromChipMAddr(void); + +#endif + + + + + + + + diff --git a/components/driver/inc/gpio.h b/components/driver/inc/gpio.h index 3176428..d23a22d 100644 --- a/components/driver/inc/gpio.h +++ b/components/driver/inc/gpio.h @@ -204,5 +204,6 @@ int phy_gpioretention_unregister(gpio_pin_e pin); int phy_gpioretention_register(gpio_pin_e pin); void phy_gpioretention_prepare_sleep_action(void); void phy_gpioretention_prepare_wakeup_action(void); +__attribute__((section(".__sram.code"))) void phy_gpioretention_disable(void); #endif diff --git a/components/driver/src/clock.c b/components/driver/src/clock.c index f8a0d55..8d7b0f3 100644 --- a/components/driver/src/clock.c +++ b/components/driver/src/clock.c @@ -254,9 +254,11 @@ void hal_rtc_clock_config(CLK32K_e clk32Mode) subWriteReg(&(AP_AON->PMCTL0), 31, 27, 0x16); //pGlobal_config[LL_SWITCH]&=0xffffffee; } +#if !(defined(CONFIG_SYS_CLK_XTAL_16M) && CONFIG_SYS_CLK_XTAL_16M > 0) //ZQ 20200812 for rc32k wakeup subWriteReg(&(AP_AON->PMCTL0),28,28,0x1);//turn on 32kxtal subWriteReg(&(AP_AON->PMCTL1),18,17,0x0);// reduce 32kxtal bias current +#endif } uint32_t hal_systick(void) diff --git a/components/driver/src/gpio.c b/components/driver/src/gpio.c index d170f4c..99e0f11 100644 --- a/components/driver/src/gpio.c +++ b/components/driver/src/gpio.c @@ -553,6 +553,20 @@ __attribute__((section(".__sram.code"))) void phy_gpioretention_prepare_sleep_ac } } +__attribute__((section(".__sram.code"))) void phy_gpioretention_disable(void) +{ + gpio_pin_e pin=0; + + for(pin=0;pinPMCTL0 &= ~BIT(retention_reg[pin][1]); + } else { + AP_AON->IOCTL[retention_reg[pin][0]] &= ~BIT(retention_reg[pin][1]); + } + } +} + __attribute__((section(".__sram.code"))) void phy_gpioretention_prepare_wakeup_action(void) { gpio_pin_e pin=0; diff --git a/components/driver/src/kscan.c b/components/driver/src/kscan.c index 94173d4..506df7a 100644 --- a/components/driver/src/kscan.c +++ b/components/driver/src/kscan.c @@ -54,7 +54,6 @@ //#include "log.h" #include "jump_function.h" #include "comdef.h" - typedef struct { bool enable; kscan_Cfg_t cfg; diff --git a/components/driver/src/phy_adc.c b/components/driver/src/phy_adc.c index 0cd4bda..b8d641c 100644 --- a/components/driver/src/phy_adc.c +++ b/components/driver/src/phy_adc.c @@ -1,46 +1,4 @@ -/************************************************************************************************** - - Phyplus Microelectronics Limited confidential and proprietary. - All rights reserved. - - IMPORTANT: All rights of this software belong to Phyplus Microelectronics - Limited ("Phyplus"). Your use of this Software is limited to those - specific rights granted under the terms of the business contract, the - confidential agreement, the non-disclosure agreement and any other forms - of agreements as a customer or a partner of Phyplus. You may not use this - Software unless you agree to abide by the terms of these agreements. - You acknowledge that the Software may not be modified, copied, - distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy - (BLE) integrated circuit, either as a product or is integrated into your - products. Other than for the aforementioned purposes, you may not use, - reproduce, copy, prepare derivative works of, modify, distribute, perform, - display or sell this Software and/or its documentation for any purposes. - - YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE - PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, - INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, - NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL - PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, - NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER - LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES - INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE - OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT - OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES - (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. - -**************************************************************************************************/ - -/******************************************************************************* -* @file adc.c -* @brief Contains all functions support for adc driver -* @version 0.0 -* @date 18. Oct. 2017 -* @author qing.han -* -* Copyright(C) 2016, PhyPlus Semiconductor -* All rights reserved. -* -*******************************************************************************/ + #include #include "error.h" #include "gpio.h" @@ -384,7 +342,7 @@ int phy_adc_config_channel(adc_Cfg_t cfg, adc_event_cb_t evt_handler) for (i = 2; i < 8; i++) { if (cfg.channel & BIT(i)) { gpio_pin_e pin = s_pinmap[i]; - phy_gpio_pull_set(pin,GPIO_FLOATING); + phy_gpio_pull_set(pin,GPIO_FLOATING); phy_gpio_ds_control(pin, Bit_ENABLE); phy_gpio_cfg_analog_io(pin, Bit_ENABLE); @@ -470,7 +428,7 @@ int phy_adc_config_channel(adc_Cfg_t cfg, adc_event_cb_t evt_handler) //LOG("%d %d %x\n",pin,pin_neg,*(volatile int*)0x40003800); phy_gpio_pull_set(pin,GPIO_FLOATING); - phy_gpio_pull_set(pin_neg,GPIO_FLOATING); + phy_gpio_pull_set(pin_neg,GPIO_FLOATING); phy_gpio_cfg_analog_io(pin, Bit_ENABLE); phy_gpio_cfg_analog_io(pin_neg, Bit_ENABLE); //LOG("%d %d %x\n",pin,pin_neg,*(volatile int*)0x40003800); @@ -537,13 +495,16 @@ int phy_adc_stop(void) **************************************************************************************/ static void phy_adc_load_calibration_value(void) { - if (adc_cal_read_flag == FALSE) { - adc_cal_read_flag = TRUE; - adc_cal_negtive = read_reg(0x11001000) & 0x0fff; - adc_cal_postive = (read_reg(0x11001000) >> 16) & 0x0fff; - //printf("->adc_cal_negtive:%x\n",adc_cal_negtive); - //printf("->adc_cal_postive:%x\n",adc_cal_postive); - } + if (adc_cal_read_flag == FALSE) { + adc_cal_read_flag = TRUE; + adc_cal_negtive = read_reg(0x11001000) & 0x0fff; + adc_cal_postive = (read_reg(0x11001000) >> 16) & 0x0fff; + + if((adc_cal_negtive < 0x733)||(adc_cal_negtive > 0x8cc) ||(adc_cal_postive < 0x733)||(adc_cal_postive > 0x8cc)){ + adc_cal_negtive = 0xfff; + adc_cal_postive = 0xfff; + } + } } @@ -561,13 +522,26 @@ const unsigned int adc_Lambda[ADC_CH_NUM] = 4047198,//P20, 0,//GPIO_DUMMY, //ADC_CH_VOICE =8, + }; //#elif(SDK_VER_CHIP == __DEF_CHIP_TSOP16__) /* +const unsigned short adc_Lambda[ADC_CH_NUM] = +{ + 0, //ADC_CH0 =0, + 0, //ADC_CH1 =1, + 867,//P11, + 0,//P23, + 0,//P24, + 857,//P14, + 800,//P15, + 780,//P20, + 0,//GPIO_DUMMY, //ADC_CH_VOICE =8, }; */ //#endif + int phy_adc_value_cal(adc_CH_t ch, uint16_t *buf, uint32_t size, bool high_resol, bool diff_mode) { volatile float result = 0.0; @@ -575,7 +549,7 @@ int phy_adc_value_cal(adc_CH_t ch, uint16_t *buf, uint32_t size, bool high_resol phy_adc_load_calibration_value(); result = (float)buf[0]; //printf("\n->%d %d %d %d\n",ch,adc_Lambda[ch],(int)result,size); - //printf("\n->%d\n",(int)result); + //printf("[%d]",(int)result); if((adc_cal_postive!=0xfff)&&(adc_cal_negtive!=0xfff)){ float delta = ((int)(adc_cal_postive-adc_cal_negtive))/2.0; if(ch&0x01) @@ -606,6 +580,8 @@ int phy_adc_value_cal(adc_CH_t ch, uint16_t *buf, uint32_t size, bool high_resol } + + /* */ #include @@ -636,6 +612,7 @@ adc_handle_t drv_adc_initialize(int32_t idx, adc_event_cb_t cb_event) adc_priv->evt_handler = cb_event; hal_clk_reset(MOD_ADCC); + hal_clk_gate_enable(MOD_ADCC); phy_adc_init(); @@ -654,7 +631,7 @@ int32_t drv_adc_uninitialize(adc_handle_t handle) //hal_pwrmgr_register(MOD_ADCC,NULL,NULL); phy_clear_adcc_cfg(); //hal_adc_init(); - AP_AON->PMCTL2_1 = 0x00; + AP_AON->PMCTL2_1 =0x00; hal_clk_gate_disable(MOD_ADCC); return 0; @@ -909,9 +886,8 @@ static int read_multiple_channel_n(adc_handle_t handle, uint32_t *data, uint32_t ch_cur=(ch%2)?(ch-1):(ch+1); - ++i; - i=i%8; - + ++i; + i&=0x07; adc_sum = 0; for (n = 0; n < 29; n++) { adc_sum += (uint16_t)(read_reg(ADC_CH_BASE + (ch_cur * 0x80) + ((n+2) * 4))&0xfff); @@ -926,6 +902,7 @@ static int read_multiple_channel_n(adc_handle_t handle, uint32_t *data, uint32_t //printf("[%x %x ]",s_adc_cfg.is_high_resolution,s_adc_cfg.is_differential_mode); //printf("[%d %d %d]",i,high_resol,diff_mode); data[i] = phy_adc_value_cal(ch,adc_avg,1,high_resol,diff_mode); + //printf("[%d %d %d ] ",i,data[i],ch_cur); ch++; diff --git a/components/driver/src/pinmux.c b/components/driver/src/pinmux.c index ac79aea..78c2554 100644 --- a/components/driver/src/pinmux.c +++ b/components/driver/src/pinmux.c @@ -35,6 +35,7 @@ #define writel(b,addr) (void)((*(volatile unsigned int *) (addr)) = (b)) uint8_t uart_tx_rx_pin[4] = {0xff,0xff,0xff,0xff}; + /** \brief initial hobbit pinmux. \return none @@ -43,12 +44,14 @@ void ioreuse_initial(void) { } + /** \brief config the pin function. \param[in] pin refs to pin_name_e. \param[in] pin_func refs to pin_func_e. \return 0-success or -1-failure */ + int32_t drv_pinmux_config(pin_name_e pin, pin_func_e pin_func) { if (pin_func == PIN_FUNC_GPIO) { diff --git a/components/dut/dut_test.c b/components/dut/dut_test.c index 3867434..f1169cb 100755 --- a/components/dut/dut_test.c +++ b/components/dut/dut_test.c @@ -15,12 +15,19 @@ #include "pm.h" #include #include +#include "drv/gpio.h" +#include "pinmux.h" +#include "pin_name.h" /* Must be aligned with 4 Bytes */ typedef struct { uint8_t mac[6]; uint8_t reserved1[2]; +#ifdef CONFIG_CALIBRATE_WITH_FREQOFF + uint32_t freqoff; +#else uint32_t xtalcap; +#endif uint8_t reserved[CONFIG_USER_FACTORY_DATA_SIZE]; } dut_factory_data_t; @@ -91,7 +98,7 @@ int dut_hal_factorydata_read(uint32_t offset, uint8_t *buffer, uint32_t length) return -1; } - int real_off = sizeof(dut_factory_data->mac) + sizeof(dut_factory_data->reserved1) + sizeof(dut_factory_data->xtalcap) + offset; + int real_off = sizeof(dut_factory_data->mac) + sizeof(dut_factory_data->reserved1) + sizeof(uint32_t) + offset; ret = nvram_read(real_off, buffer, length); if (ret < 0) { @@ -155,6 +162,7 @@ int dut_hal_sleep(uint8_t mode) subWriteReg(0x4000f01c, 6, 6, 0x00); //disable software control enter_sleep_off_mode(SYSTEM_OFF_MODE); } + return 0; } @@ -214,12 +222,66 @@ int dut_hal_mac_store(uint8_t addr[6]) return 0; } -/* - Attetion: This function will be called by system, should not printf here. - Here, we use XIP address to get value directly. - Since aos_malloc depend on aos system init, but dut_hal_xtalcap_get will be called - in hal_rfphy_init(), in that time aos was not init yet. -*/ +#ifdef CONFIG_CALIBRATE_WITH_FREQOFF +int dut_hal_freqoff_get(int32_t *freqoff) +{ + uint32_t freqoff_xip = (*(volatile unsigned int *)(CONFIG_FCDS_XTALCAP)); + + if (freqoff == NULL) { + return -1; + } + + if ((RF_PHY_FREQ_FOFF_N200KHZ > ((int32_t)freqoff_xip) || + ((int32_t)freqoff_xip) > RF_PHY_FREQ_FOFF_200KHZ) || + (freqoff_xip == 0xffffffff)) { + *freqoff = RF_PHY_DEFAULT_FREQOFF << 2; + } else { + *freqoff = (int32_t)freqoff_xip << 2; + } + + return 0; +} + +int dut_hal_freqoff_store(int32_t freqoff) +{ + dut_factory_data_t *dut_factory_data = NULL; + int ret = -1; + int real_off = 0; + int real_freqoff = 0; + + real_freqoff = (freqoff - freqoff % 20)/4; + + if (real_freqoff < RF_PHY_FREQ_FOFF_N200KHZ || real_freqoff > RF_PHY_FREQ_FOFF_200KHZ) { + return -1; + } + + dut_factory_data = (dut_factory_data_t *)aos_malloc(sizeof(dut_factory_data_t)); + if (dut_factory_data == NULL) { + return -1; + } + + ret = nvram_read(real_off, (uint8_t *)dut_factory_data, sizeof(dut_factory_data_t)); + if (ret < 0) { + aos_free(dut_factory_data); + return -1; + } + + dut_factory_data->freqoff = (uint32_t)real_freqoff; + + ret = nvram_write((uint8_t *)dut_factory_data, sizeof(dut_factory_data_t)); + if (ret < 0) { + aos_free(dut_factory_data); + return -1; + } + + aos_free(dut_factory_data); + + g_rfPhyFreqOffSet = real_freqoff; + + return 0; +} +#else +/* Attetion: This function will be called by system, should not printf here */ int dut_hal_xtalcap_get(uint32_t *xtalcap) { uint32_t xtalcap_xip = (*(volatile unsigned int *)(CONFIG_FCDS_XTALCAP)); @@ -263,6 +325,7 @@ int dut_hal_xtalcap_store(uint32_t xtalcap) return 0; } +#endif /* API for ble test */ /************************************************************************************** @@ -289,7 +352,7 @@ int dut_hal_ble_tx_single_tone(uint8_t phy_fmt, uint8_t rf_chn_idx, uint32_t xta { uint32 testTimeUs = 1000; - if (phy_fmt != PKT_FMT_BLE1M) { + if (!(phy_fmt == PKT_FMT_BLE1M||phy_fmt ==PKT_FMT_BLE2M||phy_fmt ==PKT_FMT_BLR500K||phy_fmt ==PKT_FMT_BLR125K)) { return -2; } @@ -297,11 +360,20 @@ int dut_hal_ble_tx_single_tone(uint8_t phy_fmt, uint8_t rf_chn_idx, uint32_t xta return -3; } - if (rf_chn_idx > 39) { - return -4; + uint32_t cap = RF_PHY_DEFAULT_XTAL_CAP; + /* + singletone test, if flash have no data, we test with 0; + else we need use value from flash. + */ + int32_t freqoff = RF_PHY_FREQ_FOFF_00KHZ; + int ret = dut_hal_freqoff_get(&freqoff); + if (ret == 0 && freqoff != 0) { + g_rfPhyFreqOffSet = freqoff >> 2; + freqoff = g_rfPhyFreqOffSet; } + //printf("%s, g_freqoff = %d,freqoff = %d\n", __func__, g_rfPhyFreqOffSet, freqoff); - rf_phy_dtm_ext_tx_singleTone(txpower, rf_chn_idx, xtalcap, 0, testTimeUs); + rf_phy_dtm_ext_tx_singleTone(txpower, rf_chn_idx, cap, freqoff, testTimeUs); return 0; } @@ -335,7 +407,7 @@ int dut_hal_ble_tx_mod_burst(uint8_t phy_fmt, uint8_t rf_chn_idx,uint32_t xtalca uint8_t pktLength = 37; //max pkt length in 625us uint32_t txPktNum = 1000; //send 1000 pkt - if (phy_fmt != PKT_FMT_BLE1M) { + if (!(phy_fmt == PKT_FMT_BLE1M||phy_fmt ==PKT_FMT_BLE2M||phy_fmt ==PKT_FMT_BLR500K||phy_fmt ==PKT_FMT_BLR125K)) { return -2; } @@ -343,15 +415,19 @@ int dut_hal_ble_tx_mod_burst(uint8_t phy_fmt, uint8_t rf_chn_idx,uint32_t xtalca return -3; } - if (rf_chn_idx > 39) { - return -4; - } - - if (pkt_type > 3) { + if (pkt_type > 5) { return -5; } + uint32_t cap = RF_PHY_DEFAULT_XTAL_CAP; + int32_t freqoff = RF_PHY_FREQ_FOFF_00KHZ; + int ret = dut_hal_freqoff_get(&freqoff); + if (ret == 0 && freqoff != 0) { + g_rfPhyFreqOffSet = freqoff >> 2; + freqoff = g_rfPhyFreqOffSet; + } + //printf("%s, g_freqoff = %d,freqoff = %d\n", __func__, g_rfPhyFreqOffSet, freqoff); - rf_phy_dtm_ext_tx_mod_burst(txpower, rf_chn_idx, xtalcap, 0, pkt_type, pktLength, txPktNum, txPktIntv); + rf_phy_dtm_ext_tx_mod_burst(txpower, rf_chn_idx, cap, freqoff, pkt_type, pktLength, txPktNum, txPktIntv); return 0; } @@ -386,15 +462,20 @@ int dut_hal_ble_rx_demod_burst(uint8_t phy_fmt, uint8_t rf_chn_idx, uint32_t xta uint32 rxWindow = 625; //pkt interval unit:us uint32 rxTimeOut = 625; //1000 pkt cost 625ms unit:ms - if (phy_fmt != PKT_FMT_BLE1M) { + if (!(phy_fmt == PKT_FMT_BLE1M||phy_fmt ==PKT_FMT_BLE2M||phy_fmt ==PKT_FMT_BLR500K||phy_fmt ==PKT_FMT_BLR125K)) { return -2; } - if (rf_chn_idx > 39) { - return -4; + uint32_t cap = RF_PHY_DEFAULT_XTAL_CAP; + int32_t freqoff = RF_PHY_FREQ_FOFF_00KHZ; + int ret = dut_hal_freqoff_get(&freqoff); + if (ret == 0 && freqoff != 0) { + g_rfPhyFreqOffSet = freqoff >> 2; + freqoff = g_rfPhyFreqOffSet; } + //printf("%s, g_freqoff = %d,freqoff = %d\n", __func__, g_rfPhyFreqOffSet, freqoff); - rf_phy_dtm_ext_rx_demod_burst(rf_chn_idx, 0, xtalcap, pktLength, rxTimeOut, rxWindow, rx_freq_off, rx_rssi, rx_carr_sens, rx_pkt_num); + rf_phy_dtm_ext_rx_demod_burst(rf_chn_idx, freqoff, cap, pktLength, rxTimeOut, rxWindow, rx_freq_off, rx_rssi, rx_carr_sens, rx_pkt_num); return 0; } @@ -404,3 +485,80 @@ int dut_hal_ble_transmit_stop(void) rf_phy_dtm_stop(); return 0; } + +int dut_hal_rx_current_test(uint32_t sleep_time) +{ + int16_t rxEstFoff = 0; + uint8_t rx_est_rssi = 0; + uint8_t rx_est_carrsens = 0; + uint16_t rx_pkt_num = 0; + uint8_t rfChnIdx = 0; + uint8_t pktLength = 37; //max pkt length in 625us + uint32 rxWindow = 625; //pkt interval unit:us + + if (sleep_time < 10) { + sleep_time = 10; + } + + uint32_t cap = RF_PHY_DEFAULT_XTAL_CAP; + int32_t freqoff = RF_PHY_FREQ_FOFF_00KHZ; + int ret = dut_hal_freqoff_get(&freqoff); + if (ret == 0 && freqoff != 0) { + g_rfPhyFreqOffSet = freqoff >> 2; + freqoff = g_rfPhyFreqOffSet; + } + //printf("%s, g_freqoff = %d,freqoff = %d\n", __func__, g_rfPhyFreqOffSet, freqoff); + + drv_pm_sleep_enable(); + + rf_phy_dtm_ext_rx_demod_burst(rfChnIdx, freqoff, cap, pktLength, sleep_time, rxWindow, + &rxEstFoff, &rx_est_rssi, &rx_est_carrsens, &rx_pkt_num); + + rf_phy_dtm_stop(); + drv_pm_sleep_disable(); + + return OK; +} + + +int dut_hal_test_gpio_write(uint8_t wrgpio, uint8_t value) +{ + int ret; + gpio_pin_handle_t *pin = NULL; + + if (wrgpio >= GPIO_NUM) { + return -1; + } + + drv_pinmux_config(wrgpio, PIN_FUNC_GPIO); + pin = csi_gpio_pin_initialize(wrgpio, NULL); + + ret = csi_gpio_pin_config_direction(pin, GPIO_DIRECTION_OUTPUT); + if(ret < 0){ + return ret; + } + csi_gpio_pin_write(pin, value); + return 0; +} + +int dut_hal_test_gpio_read(uint8_t wrgpio, uint8_t *value) +{ + int ret; + bool *bool_value = (bool *)value; + gpio_pin_handle_t *pin = NULL; + + if (wrgpio >= GPIO_NUM) { + return -1; + } + + drv_pinmux_config(wrgpio, PIN_FUNC_GPIO); + pin = csi_gpio_pin_initialize(wrgpio, NULL); + + ret = csi_gpio_pin_config_direction(pin,GPIO_DIRECTION_INPUT); + if(ret < 0){ + return ret; + } + csi_gpio_pin_read(pin,bool_value); + return 0; +} + diff --git a/components/inc/mcu.h b/components/inc/mcu.h index cb00fde..cb5a4a9 100644 --- a/components/inc/mcu.h +++ b/components/inc/mcu.h @@ -96,9 +96,11 @@ #define HAL_ICER *((volatile uint32_t *)(0xe000e180)) //subWriteReg: write value to register zone: bit[high:low] -#define subWriteReg(addr,high,low,value) write_reg(addr,(read_reg(addr)&\ +#define subWriteReg(addr,high,low,value) {write_reg(addr,(read_reg(addr)&\ (~((((unsigned int)1<<((high)-(low)+1))-1)<<(low))))|\ - ((unsigned int)(value)<<(low))) +((unsigned int)(value)<<(low)));__asm volatile("nop");} + + #define TIME_BASE (0x003fffff) // 24bit count shift 2 bit as 1us/bit #define TIME_DELTA(x,y) ( (x>=y) ? x-y : TIME_BASE-y+x ) diff --git a/components/osal/include/comdef.h b/components/osal/include/comdef.h index a3cfe33..1e134ce 100644 --- a/components/osal/include/comdef.h +++ b/components/osal/include/comdef.h @@ -36,7 +36,9 @@ extern "C" #define NULL_OK #define INP #define OUTP +#ifndef UNUSED #define UNUSED +#endif #define ONLY #define READONLY #define SHARED diff --git a/csi_drivers/ck_irq.c b/csi_drivers/ck_irq.c index a68f6e3..f745cc3 100644 --- a/csi_drivers/ck_irq.c +++ b/csi_drivers/ck_irq.c @@ -23,11 +23,11 @@ extern void (*g_irqvector[])(void); */ __attribute__((section(".__sram.code"))) void drv_irq_enable(uint32_t irq_num) { -#ifdef CONFIG_SYSTEM_SECURE - csi_vic_enable_sirq(irq_num); -#else +//#ifdef CONFIG_SYSTEM_SECURE + //csi_vic_enable_sirq(irq_num); +//#else csi_vic_enable_irq(irq_num); -#endif +//#endif } /** @@ -37,11 +37,11 @@ __attribute__((section(".__sram.code"))) void drv_irq_enable(uint32_t irq_num) */ __attribute__((section(".__sram.code"))) void drv_irq_disable(uint32_t irq_num) { -#ifdef CONFIG_SYSTEM_SECURE - csi_vic_disable_sirq(irq_num); -#else +//#ifdef CONFIG_SYSTEM_SECURE + //csi_vic_disable_sirq(irq_num); +//#else csi_vic_disable_irq(irq_num); -#endif +//#endif } /** diff --git a/csi_drivers/dw_dmac.c b/csi_drivers/dw_dmac.c index a3bec64..e619618 100644 --- a/csi_drivers/dw_dmac.c +++ b/csi_drivers/dw_dmac.c @@ -48,7 +48,7 @@ static const dma_capabilities_t dma_capabilities = { #define writel(b, addr) \ *((volatile uint32_t *)(addr)) = b -static void dw_dma_set_channel(uint32_t addr, uint8_t ch, uint32_t source, uint32_t dest, uint32_t size) +__attribute__((section(".__sram.code"))) static void dw_dma_set_channel(uint32_t addr, uint8_t ch, uint32_t source, uint32_t dest, uint32_t size) { writel(size, addr + (ch % 4) * 0x58 + DMA_REG_CTRLbx); writel(source, addr + (ch % 4) * 0x58 + DMA_REG_SARx); @@ -112,7 +112,7 @@ static int32_t dw_dma_set_transferwidth(uint32_t addr, uint8_t ch, dma_datawidth return 0; } -static void dw_dma_set_burstlength(uint32_t addr, uint8_t ch, uint8_t burstlength) +__attribute__((section(".__sram.code"))) static void dw_dma_set_burstlength(uint32_t addr, uint8_t ch, uint8_t burstlength) { uint32_t value = readl(addr + (ch % 4) * 0x58 + DMA_REG_CTRLax); value &= ~(0x1f800); @@ -147,7 +147,7 @@ static int32_t dw_dma_assign_hdhs_interface(uint32_t addr, uint8_t ch, dwenum_dm return 0; } -static void dw_dmac_intr_ch_error(int32_t idx) +static __attribute__((section(".__sram.code"))) void dw_dmac_intr_ch_error(int32_t idx) { dw_dma_priv_t *dma_priv = &dma_instance[idx]; uint32_t addr = dma_priv->base; @@ -200,7 +200,7 @@ __attribute__((section(".__sram.code"))) void dw_dmac_irqhandler(int32_t idx) for (ch_num = 0; ch_num < CONFIG_DMA_CHANNEL_NUM; ch_num++) { if (status & (1ul << ch_num)) { - dw_dmac_intr_ch_complete(ch_num); + dw_dmac_intr_ch_error(ch_num); } } @@ -421,7 +421,7 @@ int32_t csi_dma_config_channel(int32_t ch, dma_config_t *config, dma_event_cb_t return ret; } - ret = dw_dma_assign_hdhs_interface(addr, dma_priv->ch_num, config->hs_if, config->hs_if); + ret = dw_dma_assign_hdhs_interface(addr, dma_priv->ch_num, 0, config->hs_if); if (ret < 0) { return ret; @@ -435,7 +435,7 @@ int32_t csi_dma_config_channel(int32_t ch, dma_config_t *config, dma_event_cb_t return ret; } - ret = dw_dma_assign_hdhs_interface(addr, dma_priv->ch_num, config->hs_if, config->hs_if); + ret = dw_dma_assign_hdhs_interface(addr, dma_priv->ch_num, config->hs_if, 0); if (ret < 0) { return ret; @@ -456,7 +456,7 @@ int32_t csi_dma_config_channel(int32_t ch, dma_config_t *config, dma_event_cb_t \param[in] pdstaddr dma transfer destination address \param[in] length dma transfer length (unit: bytes). */ -void csi_dma_start(int32_t ch, void *psrcaddr, +__attribute__((section(".__sram.code"))) void csi_dma_start(int32_t ch, void *psrcaddr, void *pdstaddr, uint32_t length) { if (ch >= CONFIG_DMA_CHANNEL_NUM || ch < 0 || psrcaddr == NULL || pdstaddr == NULL) { @@ -472,13 +472,13 @@ void csi_dma_start(int32_t ch, void *psrcaddr, return; } - uint8_t i; + uint8_t i = 0; - for (i = 2; i > 0; i--) { - if (!((length * dma_priv->src_tw / dma_priv->dst_tw) % (2 << i))) { - break; - } - } + //for (i = 2; i > 0; i--) { + // if (!((length * dma_priv->src_tw / dma_priv->dst_tw) % (2 << i))) { + // break; + // } + //} int32_t grouplen = i; @@ -503,7 +503,7 @@ void csi_dma_start(int32_t ch, void *psrcaddr, \brief Stop generate dma channel signal. \param[in] ch dma channel num */ -void csi_dma_stop(int32_t ch) +__attribute__((section(".__sram.code"))) void csi_dma_stop(int32_t ch) { if (ch >= CONFIG_DMA_CHANNEL_NUM || ch < 0) { return; diff --git a/csi_drivers/dw_usart.c b/csi_drivers/dw_usart.c index 421d655..ac8b032 100644 --- a/csi_drivers/dw_usart.c +++ b/csi_drivers/dw_usart.c @@ -9,7 +9,6 @@ * @version V1.0 * @date 02. June 2017 ******************************************************************************/ - #include #include #include @@ -18,6 +17,9 @@ #include #include #include +#if defined CONFIG_DW_UART_DMAC +#include +#endif #include #include #include @@ -98,6 +100,17 @@ typedef struct { uint32_t last_rx_num; int32_t idx; uint32_t fcr_reg; +#if defined CONFIG_DW_UART_DMAC + int32_t dma_tx_ch; + int32_t dma_rx_ch; + uint8_t dma_tx_mode; // 0-not sending 1-sending + uint8_t dma_rx_mode; // 0-not receiving 1-receiving + uint32_t rx_block_num; + uint32_t tx_block_num; + uint32_t rx_num; + uint32_t tx_num; + dma_config_t config; +#endif } dw_usart_priv_t; extern int32_t target_usart_init(int32_t idx, uint32_t *base, uint32_t *irq, void **handler); @@ -114,6 +127,120 @@ static const usart_capabilities_t usart_capabilities = { .event_rx_timeout = 0, /* Signal receive character timeout event */ }; +#if defined CONFIG_DW_UART_DMAC +__attribute__((section(".__sram.code"))) static void dw_usart_dma_event_cb(int32_t ch, dma_event_e event, void *arg) +{ + dw_usart_priv_t *usart_priv = NULL; + int8_t priv_num = 0; + + for (priv_num = 0; priv_num < CONFIG_USART_NUM; priv_num++) { + usart_priv = &usart_instance[priv_num]; + + if ((usart_priv->dma_tx_ch == ch && usart_priv->dma_tx_mode == 1) || (usart_priv->dma_rx_ch == ch && usart_priv->dma_rx_mode == 1)) { + break; + } + } + + dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base); + + if (event == DMA_EVENT_TRANSFER_ERROR) { /* DMA transfer ERROR */ + if (usart_priv->dma_tx_ch == ch && usart_priv->dma_tx_mode == 1) { + csi_dma_stop(usart_priv->dma_tx_ch); + csi_dma_release_channel(usart_priv->dma_tx_ch); + usart_priv->tx_busy = 0; + usart_priv->dma_tx_mode = 0; + usart_priv->dma_tx_ch = -1; + usart_priv->fcr_reg &= ~DW_FCR_TET_FIFO_HALF; + //addr->FCR = usart_priv->fcr_reg; + + if (usart_priv->cb_event) { + usart_priv->cb_event(priv_num, USART_EVENT_TX_UNDERFLOW); + } + } else { + csi_dma_stop(usart_priv->dma_rx_ch); + csi_dma_release_channel(usart_priv->dma_rx_ch); + usart_priv->rx_busy = 0; + usart_priv->dma_rx_mode = 0; + usart_priv->dma_rx_ch = -1; + + /* FIFO enable */ + usart_priv->fcr_reg &= ~(DW_FCR_RT_FIFO_LESSTWO); + // addr->FCR |= DW_FCR_FIFOE | DW_FCR_RT_FIFO_HALF; + usart_priv->fcr_reg |= DW_FCR_RT_FIFO_HALF; + /* enable received data available */ + addr->IER |= IER_RDA_INT_ENABLE | IIR_RECV_LINE_ENABLE; + + if (usart_priv->cb_event) { + usart_priv->cb_event(priv_num, USART_EVENT_RX_FRAMING_ERROR); + } + } + } else if (event == DMA_EVENT_TRANSFER_DONE) { /* DMA transfer complete */ + if (usart_priv->dma_tx_ch == ch && usart_priv->dma_tx_mode == 1) { + usart_priv->tx_num += usart_priv->tx_block_num; + + if (usart_priv->tx_num >= usart_priv->tx_total_num) { + csi_dma_stop(usart_priv->dma_tx_ch); + csi_dma_release_channel(usart_priv->dma_tx_ch); + usart_priv->tx_busy = 0; + usart_priv->dma_tx_mode = 0; + usart_priv->dma_tx_ch = -1; + usart_priv->fcr_reg &= ~(DW_FCR_TET_FIFO_HALF); + //addr->FCR = usart_priv->fcr_reg; + + if (usart_priv->cb_event) { + usart_priv->cb_event(priv_num, USART_EVENT_SEND_COMPLETE); + } + } else { + uint32_t max_block_size = DMA_MAX_TRANSPORT_SIZE(usart_priv->dma_tx_ch); + uint32_t next_tx_size = usart_priv->tx_total_num - usart_priv->tx_num; + usart_priv->tx_block_num = (next_tx_size > max_block_size) ? max_block_size : next_tx_size; + csi_dma_start(usart_priv->dma_tx_ch, usart_priv->tx_buf + usart_priv->tx_num, (uint8_t *) & (addr->THR), usart_priv->tx_block_num); + } + } else if (usart_priv->dma_rx_ch == ch && usart_priv->dma_rx_mode == 1) { + usart_priv->rx_num += usart_priv->rx_block_num; + + if (usart_priv->rx_num >= usart_priv->rx_total_num) { + csi_dma_stop(usart_priv->dma_rx_ch); + //csi_dma_release_channel(usart_priv->dma_rx_ch); + //usart_priv->rx_busy = 0; + //usart_priv->dma_rx_mode = 0; + //usart_priv->dma_rx_ch = -1; + + /* FIFO enable */ + //usart_priv->fcr_reg &= ~(DW_FCR_RT_FIFO_LESSTWO); + //usart_priv->fcr_reg |= DW_FCR_RT_FIFO_HALF; + //addr->FCR = usart_priv->fcr_reg; + /* enable received data available */ + //addr->IER |= IER_RDA_INT_ENABLE | IIR_RECV_LINE_ENABLE; + + //uint32_t max_block_size = DMA_MAX_TRANSPORT_SIZE(usart_priv->dma_rx_ch); + //usart_priv->rx_block_num = (usart_priv->rx_total_num > max_block_size) ? max_block_size : usart_priv->rx_total_num; + //usart_priv->rx_num = 0; + //csi_dma_start(usart_priv->dma_rx_ch, (uint8_t *) & (addr->THR), usart_priv->rx_buf, usart_priv->rx_block_num); + if (usart_priv->cb_event) { + usart_priv->cb_event(priv_num, USART_EVENT_RECEIVE_COMPLETE); + } + } else { + uint32_t max_block_size = DMA_MAX_TRANSPORT_SIZE(usart_priv->dma_rx_ch); + uint32_t next_rx_size = usart_priv->rx_total_num - usart_priv->rx_num; + usart_priv->rx_block_num = (next_rx_size > max_block_size) ? max_block_size : next_rx_size; + + uint8_t i; + + for (i = 2; i > 0; i--) { + if (!(usart_priv->rx_block_num % (2 << i))) { + break; + } + } + + csi_dma_start(usart_priv->dma_rx_ch, (uint8_t *) & (addr->THR), usart_priv->rx_buf + usart_priv->rx_num, usart_priv->rx_block_num); + } + + } + } +} +#endif + static int32_t usart_wait_timeout(usart_handle_t handle, dw_usart_reg_t *addr) { uint32_t timecount = 0; @@ -557,7 +684,11 @@ __attribute__((section(".__sram.code"))) void dw_usart_irqhandler(int32_t idx) { dw_usart_priv_t *usart_priv = &usart_instance[idx]; dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base); - +#if defined CONFIG_DW_UART_DMAC + if (usart_priv->dma_rx_mode) { + return; + } +#endif uint8_t intr_state = addr->IIR & 0xf; switch (intr_state) { @@ -625,41 +756,44 @@ __attribute__((section(".__sram.code"))) void csi_usart_prepare_sleep_action(vo uint32_t addr = 0x40004000; uint32_t set_fcr_value; while (!(*(volatile uint32_t *)(addr + 0x7c) & 0x4)); - - *(volatile uint32_t *)(addr + 0xc) |= 0x80; - registers_save((uint32_t *)usart_regs_saved, (uint32_t *)addr, 2); - *(volatile uint32_t *)(addr + 0xc) &= ~0x80; - registers_save(&usart_regs_saved[2], (uint32_t *)addr + 1, 1); - registers_save(&usart_regs_saved[3], (uint32_t *)addr + 3, 2); - - for(int i = 0; i < 4 ; i++) { - if(uart_tx_rx_pin[i] != 0xff) { - phy_gpio_fmux(uart_tx_rx_pin[i], Bit_DISABLE); - } - } - +// for(int i = 0; i < 4 ; i++) { +// if(uart_tx_rx_pin[i] != 0xff) { +// phy_gpio_fmux(uart_tx_rx_pin[i], Bit_DISABLE); +// } +// } +// while ((*(volatile uint32_t *)(addr + 0x7c) & 0x1)); set_fcr_value = (*(volatile uint32_t *)(addr + 0x98) & 0x01) | ((*(volatile uint32_t *)(addr + 0x94) & 0x01)<<3) | ((*(volatile uint32_t *)(addr + 0x9c) & 0x03)<<6) | ((*(volatile uint32_t *)(addr + 0xa0) & 0x03)<<4) | DW_FCR_RFIFOR | DW_FCR_XFIFOR; + + registers_save(&usart_regs_saved[3], (uint32_t *)addr + 3, 1); + + do{ - *(volatile uint32_t *)(addr + 0x8) = set_fcr_value; - }while (*(volatile uint32_t *)(addr + 0x7c) & 0x1); - - usart_regs_saved[4] = set_fcr_value; + *(volatile uint32_t *)(addr + 0xc) = 0x80; + }while(*(volatile uint32_t *)(addr + 0xc) != 0x80); + registers_save((uint32_t *)usart_regs_saved, (uint32_t *)addr, 2); + do{ + *(volatile uint32_t *)(addr + 0xc) = usart_regs_saved[3]; + }while(*(volatile uint32_t *)(addr + 0xc) != usart_regs_saved[3]); + registers_save(&usart_regs_saved[2], (uint32_t *)addr + 1, 1); + usart_regs_saved[4] = set_fcr_value; } __attribute__((section(".__sram.code"))) void csi_usart_wakeup_sleep_action(void) { uint32_t addr = 0x40004000; - //while (*(volatile uint32_t *)(addr + 0x7c) & 0x1); - *(volatile uint32_t *)(addr + 0xc) |= 0x80; + do{ + *(volatile uint32_t *)(addr + 0xc) = 0x80; + }while(*(volatile uint32_t *)(addr + 0xc) != 0x80); registers_save((uint32_t *)addr, usart_regs_saved, 2); - *(volatile uint32_t *)(addr + 0xc) &= ~0x80; + do{ + *(volatile uint32_t *)(addr + 0xc) = usart_regs_saved[3]; + }while(*(volatile uint32_t *)(addr + 0xc) != usart_regs_saved[3]); registers_save((uint32_t *)addr + 1, &usart_regs_saved[2], 1); - registers_save((uint32_t *)addr + 3, &usart_regs_saved[3], 2); registers_save((uint32_t *)addr + 2, &usart_regs_saved[4], 1); } @@ -703,6 +837,13 @@ usart_handle_t csi_usart_initialize(int32_t idx, usart_event_cb_t cb_event) usart_priv->cb_event = cb_event; usart_priv->idx = idx; +#if defined CONFIG_DW_UART_DMAC + usart_priv->dma_tx_ch = -1; + usart_priv->dma_rx_ch = -1; + usart_priv->dma_tx_mode = 0; + usart_priv->dma_rx_mode = 0; +#endif + #ifdef CONFIG_LPM csi_usart_power_control(usart_priv, DRV_POWER_FULL); #endif @@ -717,8 +858,8 @@ usart_handle_t csi_usart_initialize(int32_t idx, usart_event_cb_t cb_event) dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base); /* FIFO enable */ - addr->FCR = DW_FCR_FIFOE | DW_FCR_RT_FIFO_QUARTER; //DW_FCR_RT_FIFO_SINGLE; - usart_priv->fcr_reg = DW_FCR_FIFOE | DW_FCR_RT_FIFO_QUARTER; //DW_FCR_RT_FIFO_SINGLE; + addr->FCR = DW_FCR_FIFOE | DW_FCR_RT_FIFO_SINGLE; + usart_priv->fcr_reg = DW_FCR_FIFOE | DW_FCR_RT_FIFO_SINGLE; /* enable received data available */ addr->IER = IER_RDA_INT_ENABLE | IIR_RECV_LINE_ENABLE; @@ -813,6 +954,69 @@ int32_t csi_usart_config(usart_handle_t handle, return 0; } +#if defined CONFIG_DW_UART_DMAC +static int32_t dw_usart_send_dma(dw_usart_priv_t *usart_priv) +{ + dma_config_t config; + config.src_inc = DMA_ADDR_INC; + config.dst_inc = DMA_ADDR_CONSTANT; + config.src_tw = 1; + config.dst_tw = 1; + if (usart_priv->idx == 0) { + config.hs_if = DWENUM_DMA_UART0_TX; + } else if (usart_priv->idx == 1) { + config.hs_if = DWENUM_DMA_UART1_TX; + } else { + return ERR_USART(DRV_ERROR_PARAMETER); + } + config.type = DMA_MEM2PERH; + if (usart_priv->dma_tx_ch == -1) { + usart_priv->dma_tx_ch = csi_dma_alloc_channel(); + if (usart_priv->dma_tx_ch == -1) { + return ERR_USART(DRV_ERROR_PARAMETER); + } + } + int32_t ret = csi_dma_config_channel(usart_priv->dma_tx_ch, &config, dw_usart_dma_event_cb, NULL); + if (ret < 0) { + csi_dma_release_channel(usart_priv->dma_tx_ch); + return ret; + } + usart_priv->config = config; + uint32_t max_block_size = DMA_MAX_TRANSPORT_SIZE(usart_priv->dma_tx_ch); + usart_priv->tx_block_num = (usart_priv->tx_total_num > max_block_size) ? max_block_size : usart_priv->tx_total_num; + dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base); + addr->FCR = usart_priv->fcr_reg | (DW_FCR_TET_FIFO_HALF); + usart_priv->fcr_reg |= (DW_FCR_TET_FIFO_HALF); + csi_dma_start(usart_priv->dma_tx_ch, usart_priv->tx_buf, (uint8_t *) & (addr->THR), usart_priv->tx_block_num); + return 0; +} +int32_t csi_usart_send_dma(usart_handle_t handle, const void *data, uint32_t num) +{ + USART_NULL_PARAM_CHK(handle); + USART_NULL_PARAM_CHK(data); + + uint8_t *buff = (uint8_t *)data; + + if (num == 0) { + return ERR_USART(DRV_ERROR_PARAMETER); + } + + dw_usart_priv_t *usart_priv = handle; + + usart_priv->tx_buf = buff; + usart_priv->tx_total_num = num; + + usart_priv->dma_tx_mode = 1; + usart_priv->tx_busy = 1; + usart_priv->last_tx_num = 0; + usart_priv->tx_num = 0; + + int32_t ret = dw_usart_send_dma(usart_priv); + + return ret; +} + +#endif /** \brief Start sending data to UART transmitter,(received data is ignored). The function is non-blocking,UART_EVENT_TRANSFER_COMPLETE is signaled when transfer completes. @@ -858,6 +1062,111 @@ int32_t csi_usart_abort_send(usart_handle_t handle) return ERR_USART(DRV_ERROR_UNSUPPORTED); } +#if defined CONFIG_DW_UART_DMAC +static int32_t dw_usart_receive_dma(dw_usart_priv_t *usart_priv) +{ + dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base); + /* disable received data available */ + + dma_config_t config; + config.src_inc = DMA_ADDR_CONSTANT; + config.dst_inc = DMA_ADDR_INC; + config.src_tw = 1; + config.dst_tw = 1; + + if (usart_priv->idx == 0) { + config.hs_if = DWENUM_DMA_UART0_RX; + } else if (usart_priv->idx == 1) { + config.hs_if = DWENUM_DMA_UART1_RX; + } else { + return ERR_USART(DRV_ERROR_PARAMETER); + } + + //addr->IER &= ~(IER_RDA_INT_ENABLE | IIR_RECV_LINE_ENABLE); + config.type = DMA_PERH2MEM; + + if (usart_priv->dma_rx_ch == -1) { + usart_priv->dma_rx_ch = csi_dma_alloc_channel(); + + if (usart_priv->dma_rx_ch == -1) { + return ERR_USART(DRV_ERROR_PARAMETER); + } + } + + csi_dma_stop(usart_priv->dma_rx_ch); + + int ret = csi_dma_config_channel(usart_priv->dma_rx_ch, &config, dw_usart_dma_event_cb, NULL); + + if (ret < 0) { + csi_dma_release_channel(usart_priv->dma_rx_ch); + return ret; + } + + usart_priv->config = config; + + uint32_t max_block_size = DMA_MAX_TRANSPORT_SIZE(usart_priv->dma_rx_ch); + usart_priv->rx_block_num = (usart_priv->rx_total_num > max_block_size) ? max_block_size : usart_priv->rx_total_num; + + uint8_t i; + + for (i = 2; i > 0; i--) { + if (!(usart_priv->rx_block_num % (2 << i))) { + break; + } + } + + usart_priv->dma_rx_mode = 1; + + //usart_priv->fcr_reg &= ~(DW_FCR_RT_FIFO_LESSTWO); + //addr->FCR = 1 << DW_USART_FCR_RFIFOR_Pos | (1 << DW_USART_FCR_RT_Pos) | usart_priv->fcr_reg; + //usart_priv->fcr_reg |= (i << DW_USART_FCR_RT_Pos); + csi_dma_start(usart_priv->dma_rx_ch, (uint8_t *) & (addr->THR), usart_priv->rx_buf, usart_priv->rx_block_num); + return 0; +} + +int32_t csi_usart_receive_dma(usart_handle_t handle, void *data, uint32_t num) +{ + USART_NULL_PARAM_CHK(handle); + USART_NULL_PARAM_CHK(data); + + dw_usart_priv_t *usart_priv = handle; + + usart_priv->rx_buf = (uint8_t *)data; // Save receive buffer usart + usart_priv->rx_total_num = num; // Save number of data to be received + usart_priv->rx_cnt = 0; + usart_priv->rx_busy = 1; + usart_priv->last_rx_num = 0; + usart_priv->rx_num = 0; + + int32_t ret = dw_usart_receive_dma(usart_priv); + + return ret; + +} + +__attribute__((section(".__sram.code"))) int32_t csi_usart_restart_receive_dma(usart_handle_t handle) +{ + dw_usart_priv_t *usart_priv = handle; + dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base); + + /* if rx buffer pointer is working,but uart is idle, meanings rx buffer have unused data, need reset */ + uint32_t flags = csi_irq_save(); + if ((((volatile uint32_t )(AP_DMA_CH_CFG(usart_priv->dma_rx_ch)->DAR)) != usart_priv->rx_buf ) && + ((addr->USR & USR_UART_BUSY) == 0)) { + uint32_t max_block_size = DMA_MAX_TRANSPORT_SIZE(usart_priv->dma_rx_ch); + usart_priv->rx_block_num = (usart_priv->rx_total_num > max_block_size) ? max_block_size : usart_priv->rx_total_num; + usart_priv->rx_num = 0; + csi_dma_stop(usart_priv->dma_rx_ch); + csi_dma_start(usart_priv->dma_rx_ch, (uint8_t *) & (addr->THR), usart_priv->rx_buf, usart_priv->rx_block_num); + irq_unlock(flags); + return 0; + } + csi_irq_restore(flags); + return -1; +} + +#endif + /** \brief Start receiving data from UART receiver. \param[in] handle usart handle to operate. diff --git a/csi_drivers/dw_wdt.c b/csi_drivers/dw_wdt.c index 0fcf3fd..fcfc5b0 100644 --- a/csi_drivers/dw_wdt.c +++ b/csi_drivers/dw_wdt.c @@ -34,7 +34,8 @@ //#define SYSTEM_CLOCK_MS (30000 / 1000) //uint32_t timeout_ms[16]; -const uint32_t timeout_ms[8] = {2000, 4000, 8000, 16000, 32000, 64000, 128000, 256000}; +//const uint32_t timeout_ms[8] = {2000, 4000, 8000, 16000, 32000, 64000, 128000, 256000}; +uint32_t timeout_ms[8] = {2000, 4000, 8000, 16000, 32000, 64000, 128000, 256000}; typedef struct { #ifdef CONFIG_LPM uint8_t wdt_power_status; @@ -52,7 +53,7 @@ static dw_wdt_priv_t wdt_instance[CONFIG_WDT_NUM]; static inline void dw_wdt_enable(dw_wdt_reg_t *addr) { - addr->WDT_CR = 0x1F; + addr->WDT_CR = 0x1D; } static inline void dw_wdt_disable(dw_wdt_reg_t *addr) @@ -197,7 +198,7 @@ int32_t csi_wdt_power_control(wdt_handle_t handle, csi_power_stat_e state) \param[in] value the timeout value(ms) \ref:timeout_ms[] \return \ref execution_status */ -int32_t csi_wdt_set_timeout(wdt_handle_t handle, uint32_t value) +__attribute__((section(".__sram.code"))) int32_t csi_wdt_set_timeout(wdt_handle_t handle, uint32_t value) { WDT_NULL_PARAM_CHK(handle); uint32_t i = 0u; @@ -275,7 +276,7 @@ int32_t csi_wdt_stop(wdt_handle_t handle) \param[in] handle wdt handle to operate. \return \ref execution_status */ -int32_t csi_wdt_restart(wdt_handle_t handle) +__attribute__((section(".__sram.code"))) int32_t csi_wdt_restart(wdt_handle_t handle) { WDT_NULL_PARAM_CHK(handle); diff --git a/csi_drivers/phy_rtc.c b/csi_drivers/phy_rtc.c index ff353aa..febea69 100644 --- a/csi_drivers/phy_rtc.c +++ b/csi_drivers/phy_rtc.c @@ -72,7 +72,7 @@ static const rtc_capabilities_t rtc_capabilities = { extern void WaitRTCCount(uint32_t rtcDelyCnt); -static uint8 phy_rc32k_calibration(void) +static uint8 rc32k_calibration(void) { int delay = 15000;//4000;//ZQ 20181203 for HCLK=48M uint32_t temp = 0; @@ -148,7 +148,7 @@ static uint8 rc32k_calibration_check(uint8 hLimt, uint8 lLimt, uint8 rdCnt, uint uint32 temp; while (calCnt--) { - rc0 = phy_rc32k_calibration(); + rc0 = rc32k_calibration(); if (rc0 < hLimt && rc0 > lLimt) { temp = rc32k_tracking_check(rdCnt, ckCnt); diff --git a/csi_drivers/spif.c b/csi_drivers/spif.c index c908237..206a771 100644 --- a/csi_drivers/spif.c +++ b/csi_drivers/spif.c @@ -55,6 +55,10 @@ extern void spif_set_deep_sleep(void); extern void spif_release_deep_sleep(void); extern void spif_cmd(uint8_t op, uint8_t addrlen, uint8_t rdlen, uint8_t wrlen, uint8_t mbit, uint8_t dummy); extern void spif_rddata(uint8_t *data, uint8_t len); +extern void WaitRTCCount(uint32_t rtcDelyCnt); +extern uint8_t spif_flash_status_reg_0(void); +extern uint8_t spif_flash_status_reg_1(void); +extern void spif_wrdata(uint8_t* data, uint8_t len); #define SPIF_TIMEOUT 1000000 @@ -131,7 +135,7 @@ __attribute__((section(".__sram.code"))) static inline void spif_unlock(uint32_ #define spif_wait_nobusy(flg, tout_ns, return_val) {if(_spif_wait_nobusy_x(flg, tout_ns)){if(return_val){ return return_val;}}} -__attribute__((section(".__sram.code"))) static void hal_cache_tag_flush(void) +__attribute__((section(".__sram.code"))) void hal_cache_tag_flush(void) { _HAL_CS_ALLOC_(); HAL_ENTER_CRITICAL_SECTION(); @@ -139,10 +143,10 @@ __attribute__((section(".__sram.code"))) static void hal_cache_tag_flush(void) volatile int dly = 8; if (cb == 0) { - AP_CACHE->CTRL0 = 0x02; + AP_PCR->CACHE_BYPASS = 1; } - + AP_CACHE->CTRL0 = 0x02; while (dly--) { ; }; @@ -154,10 +158,10 @@ __attribute__((section(".__sram.code"))) static void hal_cache_tag_flush(void) while (dly--) { ; }; - + AP_CACHE->CTRL0 = 0; if (cb == 0) { AP_PCR->CACHE_BYPASS = 0; - AP_CACHE->CTRL0 = 0; + } HAL_EXIT_CRITICAL_SECTION(); @@ -178,6 +182,7 @@ __attribute__((section(".__sram.code"))) static int _spif_wait_nobusy_x(uint8_t volatile int tout = (int)(tout_ns); for (; tout ; tout --) { + WaitRTCCount(1);//increase polling interval status = _spif_read_status_reg_x(); if ((status & flg) == 0) { @@ -188,10 +193,77 @@ __attribute__((section(".__sram.code"))) static int _spif_wait_nobusy_x(uint8_t return PPlus_ERR_BUSY; } +__attribute__((section(".__sram.code"))) uint8_t hal_flash_lock_status(void) +{ + uint8_t status = _spif_read_status_reg_x(); + return status&(FCMD_DATAPRO_AREA_512|FCMD_SRP_REG); + +} + +__attribute__((section(".__sram.code"))) uint8_t hal_flash_write_disable(void) +{ + uint32_t result = csi_irq_save(); + uint8_t status; + status = _spif_read_status_reg_x(); + if(status & SFLG_WEL) + { + AP_SPIF->fcmd = XFRD_FCMD_WRDI; + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + } + csi_irq_restore(result); + return 0; +} + +__attribute__((section(".__sram.code"))) int hal_flash_lock(uint8_t area) +{ + uint32_t result = csi_irq_save(); + area &= FCMD_DATAPRO_AREA_512; + area |= FCMD_SRP_REG; + if(area != hal_flash_lock_status()) + { + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + AP_SPIF->fcmd = XFRD_FCMD_WREN; + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + AP_SPIF->fcmd_wrdata[0] = area | FCMD_SRP_REG; + AP_SPIF->fcmd = XFRD_FCMD_WRST; + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + } + csi_irq_restore(result); + return 0; +} + +__attribute__((section(".__sram.code"))) int hal_flash_unlock(void) +{ + uint32_t result = csi_irq_save(); + + if(FCMD_DATAPRO_AREA_NONE != hal_flash_lock_status()) + { + subWriteReg(&AP_SPIF->config, 14, 14, 0); //disable wp bit(14) + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + AP_SPIF->fcmd = XFRD_FCMD_WREN; + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + AP_SPIF->fcmd_wrdata[0] = FCMD_DATAPRO_AREA_NONE; + AP_SPIF->fcmd = XFRD_FCMD_WRST; + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + } + csi_irq_restore(result); + return 0; +} + + __attribute__((section(".__sram.code"))) static int hal_flash_write(uint32_t addr, uint8_t *data, uint32_t size) { uint8_t retval; - uint32_t cs = spif_lock(); + + uint32_t result = csi_irq_save(); + //hal_flash_unlock(); HAL_CACHE_ENTER_BYPASS_SECTION(); SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); @@ -200,13 +272,14 @@ __attribute__((section(".__sram.code"))) static int hal_flash_write(uint32_t ad SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); HAL_CACHE_EXIT_BYPASS_SECTION(); - spif_unlock(cs); + //hal_flash_lock(); + csi_irq_restore(result); return retval; } __attribute__((section(".__sram.code"))) static int hal_flash_read(uint32_t addr, uint8_t *data, uint32_t size) { - uint32_t cs = spif_lock(); + uint32_t result = csi_irq_save(); volatile uint8_t *u8_spif_addr = (volatile uint8_t *)((addr & 0x7ffff) | SPIF_ADDR_START); uint32_t cb = AP_PCR->CACHE_BYPASS; //#if(SPIF_FLASH_SZIE == FLASH_SIZE_1MB) @@ -246,7 +319,8 @@ __attribute__((section(".__sram.code"))) static int hal_flash_read(uint32_t add #endif - spif_unlock(cs); +// spif_unlock(cs); + csi_irq_restore(result); return PPlus_SUCCESS; } @@ -254,8 +328,9 @@ __attribute__((section(".__sram.code"))) static int hal_flash_read(uint32_t add __attribute__((section(".__sram.code"))) int hal_flash_erase_sector(unsigned int addr) { uint8_t retval; - uint32_t cs = spif_lock(); - + + uint32_t result = csi_irq_save(); + //hal_flash_unlock(); uint32_t cb = AP_PCR->CACHE_BYPASS; SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); @@ -268,15 +343,18 @@ __attribute__((section(".__sram.code"))) int hal_flash_erase_sector(unsigned in hal_cache_tag_flush(); } - spif_unlock(cs); + //hal_flash_lock(); + csi_irq_restore(result); return retval; } __attribute__((section(".__sram.code"))) int hal_flash_erase_block64(unsigned int addr) { - uint32_t cs = spif_lock(); uint8_t retval; + + uint32_t result = csi_irq_save(); + //hal_flash_unlock(); uint32_t cb = AP_PCR->CACHE_BYPASS; SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); @@ -287,15 +365,17 @@ __attribute__((section(".__sram.code"))) int hal_flash_erase_block64(unsigned i hal_cache_tag_flush(); } - spif_unlock(cs); - + //hal_flash_lock(); + csi_irq_restore(result); return retval; } __attribute__((section(".__sram.code"))) int hal_flash_erase_all(void) { - uint32_t cs = spif_lock(); uint8_t retval; + uint32_t result = csi_irq_save(); + + //hal_flash_unlock(); uint32_t cb = AP_PCR->CACHE_BYPASS; SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); @@ -306,7 +386,8 @@ __attribute__((section(".__sram.code"))) int hal_flash_erase_all(void) hal_cache_tag_flush(); } - spif_unlock(cs); + //hal_flash_lock(); + csi_irq_restore(result); return retval; } @@ -376,6 +457,101 @@ uint32_t phy_flash_block64_erase(unsigned int addr) return hal_flash_erase_block64(addr); } +__attribute__((section(".__sram.code"))) int hal_flash_rd_status_reg(uint8* buf,bool low_8bit) +{ + uint8_t retval = PPlus_SUCCESS; + uint32_t result = csi_irq_save(); + + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + + if(low_8bit == TRUE) + { + *buf = spif_flash_status_reg_0(); + } + else + { + *buf = spif_flash_status_reg_1(); + } + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + csi_irq_restore(result); + return retval; +} + + +__attribute__((section(".__sram.code"))) int hal_flash_wr_status_reg(uint8* buf,int len) +{ + uint8_t retval = PPlus_SUCCESS; + uint32_t result; + + if((len != 1) && (len != 2)) + { + return PPlus_ERR_INVALID_PARAM; + } + + result = csi_irq_save(); + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + + AP_SPIF->fcmd = XFRD_FCMD_WREN; + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + + spif_wrdata(buf, len); + spif_cmd(FCMD_WRST, 0,0,len,0,0); + + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + + csi_irq_restore(result); + return retval; +} + + + +__attribute__((section(".__sram.code"))) static int hal_flash_config_srp(void) +{ + uint8_t retval; + uint8_t status_reg[2]; + uint8_t status_reg_len = 1; + + FLASH_WP_HIGH_LEVEL; + retval = hal_flash_rd_status_reg(&status_reg[0],TRUE); + +#if (FLASH_STATUS_REGISTER_LEN == 1) + if((status_reg[0] & 0x80) != 0x80) //SRP=1 +#elif (FLASH_STATUS_REGISTER_LEN == 2) + retval = hal_flash_rd_status_reg(&status_reg[1],FALSE); + if(((status_reg[1] & 0x01) != 0x00) || ((status_reg[0] & 0x80) != 0x80)) //SRP1=0&& SRP0=1 +#endif + { +#if (FLASH_STATUS_REGISTER_LEN == 2) + status_reg_len = 2; + status_reg[1] &= ~(1<<0); +#endif + status_reg[0] |= (1<<7); + hal_flash_wr_status_reg(status_reg,status_reg_len); + } + + return retval; +} + +__attribute__((section(".__sram.code"))) int hal_flash_switch_hardware_protect_mode(void) +{ + uint8_t retval = hal_flash_config_srp(); + FLASH_WP_LOW_LEVEL; + return retval; +} + +__attribute__((section(".__sram.code"))) int hal_flash_switch_hardware_unprotect_mode(void) +{ + uint8_t retval = hal_flash_config_srp(); + FLASH_WP_HIGH_LEVEL; + return retval; +} + + /* cpi api */ diff --git a/flash/TG7120B_Flash.elf b/flash/TG7120B_Flash.elf index d6b5a6f5058ca7c42189bf9144dbd348f68ae0a4..c9ff7b2eaffb340f85bdb3bb1d0c7eec46999e4c 100644 GIT binary patch literal 81844 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 A9smFU literal 79664 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 PIvTzEDK6T-GT;9L0{epu diff --git a/include/dw_dmac.h b/include/dw_dmac.h index 6ff772d..64068c4 100644 --- a/include/dw_dmac.h +++ b/include/dw_dmac.h @@ -102,6 +102,7 @@ typedef enum { #define DMA_REG_Cfg 0x398 #define DMA_REG_ChEn 0x3a0 +#define DMA_MAX_TRANSPORT_SIZE(ch) ((ch == 0) ? 0x7ff : 0x1f) //typedef struct { // __IOM uint32_t SAR; /* offset: 0x00 (R/W) Channel Source Address Register */ // __IOM uint32_t DAR; /* offset: 0x04 (R/W) Channel Destination Address Register */ diff --git a/include/soc.h b/include/soc.h index 43af8e1..3402866 100644 --- a/include/soc.h +++ b/include/soc.h @@ -51,5 +51,6 @@ #define CONFIG_AES_NUM 1 #define CONFIG_PMU_NUM 1 #define CONFIG_ADC_NUM 1 - +#define CONFIG_OTP_BANK_SIZE 1024 +#define SHA_CONTEXT_SIZE 224 #endif /* _SOC_H_ */ diff --git a/include/spif.h b/include/spif.h index f9f4313..62add18 100644 --- a/include/spif.h +++ b/include/spif.h @@ -52,6 +52,11 @@ extern "C" { #define XFRD_FCMD_READ 0x801000B #define XFRD_FCMD_READ_DUAL 0x801003B #define XFRD_FCMD_READ_QUAD 0x801006B +#define XFRD_FCMD_WREN 0x6000001 +#define XFRD_FCMD_WRDI 0x4000001 //flash write disable +#define XFRD_FCMD_WRST 0x1008001 + + #define FCMD_RESET 0x99 //reset @@ -81,6 +86,50 @@ extern "C" { #define FCMD_READQIO 0xeB //quad I/O fast read #define FCMD_READQIOW 0xe7 //quad I/O fast read word +#define FCMD_CMD_EXCUTE 0x01 +#define FCMD_SRP_REG 0x80 +#define FCMD_DATAPRO_AREA_NONE 0x00 +#define FCMD_DATAPRO_AREA_504 0x04 +#define FCMD_DATAPRO_AREA_496 0x08 +#define FCMD_DATAPRO_AREA_480 0x0c +#define FCMD_DATAPRO_AREA_448 0x10 +#define FCMD_DATAPRO_AREA_384 0x14 +#define FCMD_DATAPRO_AREA_256 0x18 +#define FCMD_DATAPRO_AREA_512 0x1c + +#define FCMD_DATAPRO_NONE_BIT 0x00 +#define FCMD_DATAPRO_504_BIT 0x04 +#define FCMD_DATAPRO_496_BIT 0x08 +#define FCMD_DATAPRO_480_BIT 0x0c +#define FCMD_DATAPRO_448_BIT 0x10 +#define FCMD_DATAPRO_384_BIT 0x14 +#define FCMD_DATAPRO_256_BIT 0x18 +#define FCMD_DATAPRO_512_BIT 0x1c + + +#define FLASH_STATUS_REGISTER_LEN 1 + +#define XFRD_FCMD_WREN 0x6000001 +#define XFRD_FCMD_WRST 0x1008001 + +#define FLASH_WP_HIGH_LEVEL (AP_SPIF->config &= ~(1<<14)) +#define FLASH_WP_LOW_LEVEL (AP_SPIF->config |= (1<<14)) +#define FLASH_WP_LEVEL_GET (0x4000-(AP_SPIF->config & (1<<14))) + +extern uint8_t spif_flash_status_reg_1(void); +extern void spif_wrdata(uint8_t* data, uint8_t len); + +__attribute__((section(".__sram.code"))) void hal_cache_tag_flush(void); + + +__attribute__((section(".__sram.code"))) int hal_flash_rd_status_reg(uint8* buf,bool low_8bit); +__attribute__((section(".__sram.code"))) int hal_flash_wr_status_reg(uint8* buf,int len); + +__attribute__((section(".__sram.code"))) int hal_flash_switch_hardware_protect_mode(void); +__attribute__((section(".__sram.code"))) int hal_flash_switch_hardware_unprotect_mode(void); +__attribute__((section(".__sram.code"))) uint8_t hal_flash_write_disable(void); + + #ifdef __cplusplus } #endif diff --git a/misc/rom_sym_def.h b/misc/rom_sym_def.h index 7ed7555..2cc7539 100644 --- a/misc/rom_sym_def.h +++ b/misc/rom_sym_def.h @@ -4,6 +4,8 @@ #define __ROM_SYM_H__ #ifdef USE_ROMSYM_ALIAS +#define g_system_reset_cause _symrom_g_system_reset_cause +#define SystemResetCause _symrom_SystemResetCause #define WaitMs _symrom_WaitMs #define WaitRTCCount _symrom_WaitRTCCount #define WaitUs _symrom_WaitUs @@ -569,7 +571,7 @@ #define LL_SetPeriodicAdvEnable _symrom_LL_SetPeriodicAdvEnable #define LL_SetPeriodicAdvParameter _symrom_LL_SetPeriodicAdvParameter #define LL_SetPhyMode _symrom_LL_SetPhyMode -#define LL_SetRandomAddress _symrom_LL_SetRandomAddress +//#define LL_SetRandomAddress _symrom_LL_SetRandomAddress #define LL_SetResolvablePrivateAddressTimeout _symrom_LL_SetResolvablePrivateAddressTimeout #define LL_SetScanControl _symrom_LL_SetScanControl #define LL_SetScanParam _symrom_LL_SetScanParam @@ -909,6 +911,14 @@ #define rom_hal_uart_send_buff _symrom_hal_uart_send_buff #define rom_hal_uart_tx _symrom_hal_uart_tx #define move_to_slave_function0 _symrom_move_to_slave_function0 +#define ll_scheduler0 _symrom_ll_scheduler0 +#define g_llAdvMode _symrom_g_llAdvMode +#define LL_AdvSetTerminatedCback _symrom_LL_AdvSetTerminatedCback +#define g_timer4_irq_pending_time _symrom_g_timer4_irq_pending_time +#define llSetupNextSlaveEvent0 _symrom_llSetupNextSlaveEvent0 +#define llProcessSlaveControlPacket0 _symrom_llProcessSlaveControlPacket0 +#define llProcessMasterControlPacket0 _symrom_llProcessMasterControlPacket0 +#define LL_slave_conn_event0 _symrom_LL_slave_conn_event0 #endif #endif diff --git a/package.yaml b/package.yaml index 39b0216..fca480f 100755 --- a/package.yaml +++ b/package.yaml @@ -145,6 +145,7 @@ def_config: # 组件的可配置项 AOS_MAX_APP_PRI: 14 CONFIG_KERNEL_PRI_MAX: 14 CONFIG_SYSTICK_HZ: 1000 + CONFIG_CALIBRATE_WITH_FREQOFF: 1 # CONFIG_DEBUG: y # CONFIG_PARAM_NOT_CHECK: y # CONFIG_CLI: y diff --git a/phy_pmu.c b/phy_pmu.c index da0550e..fa1d802 100755 --- a/phy_pmu.c +++ b/phy_pmu.c @@ -25,7 +25,7 @@ #include #include - +#include "global_config.h" #define ERR_PMU(errno) (CSI_DRV_ERRNO_PMU_BASE | errno) #define PMU_NULL_PARAM_CHK(para) HANDLE_PARAM_CHK(para, ERR_PMU(DRV_ERROR_PARAMETER)) @@ -36,6 +36,7 @@ typedef struct { extern int32_t arch_do_cpu_save(void); extern int32_t arch_do_cpu_resume(void); +extern uint32_t rtc_get_counter(void); static uint8_t pmu_power_status; static phy_pmu_priv_t pmu_handle[CONFIG_PMU_NUM]; @@ -73,6 +74,9 @@ static void do_prepare_sleep_action(int32_t idx) static void do_wakeup_sleep_action(int32_t idx) { int i = 0; + + subWriteReg(&AP_SPIF->config, 14, 14, 1); //enable wp bit(14) + /* resume vic register */ VIC->ISER[0U] = vic_regs_saved[0]; VIC->ISPR[0U] = vic_regs_saved[1]; @@ -106,7 +110,10 @@ pmu_handle_t csi_pmu_initialize(int32_t idx, pmu_event_cb_t cb_event) pmu_priv->idx = idx; pmu_priv->cb = cb_event; - JUMP_FUNCTION(WAKEUP_PROCESS) = (uint32_t)arch_do_cpu_resume; + /* + WAKEUP_PROCESS jump func will be registed as arch_do_cpu_resume in enter_sleep_process + */ + //JUMP_FUNCTION(WAKEUP_PROCESS) = (uint32_t)arch_do_cpu_resume; return (pmu_handle_t)pmu_priv; } @@ -188,6 +195,18 @@ int32_t csi_pmu_enter_sleep(pmu_handle_t handle, pmu_mode_e mode) do_prepare_sleep_action(0); if (arch_do_cpu_save() == 0) { + subWriteReg(0x4000f03c, 2, 0, 0); //switch hclk to RC32M + uint32_t rtc_current; + extern uint32 *pGlobal_config; + rtc_current = rtc_get_counter(); + if(((AP_AON->RTCCC0 - rtc_current)>(pGlobal_config[MAX_SLEEP_TIME]>>4)) || + ((AP_AON->RTCCC0 - rtc_current)<(pGlobal_config[MIN_SLEEP_TIME]>>6))) + { + extern void just_enter_sleep(uint32 time); + just_enter_sleep(33000); + } + extern int32_t arch_do_cpu_resume(void); + JUMP_FUNCTION(WAKEUP_PROCESS) = (uint32_t)arch_do_cpu_resume; enter_sleep_off_mode(SYSTEM_SLEEP_MODE); } @@ -203,6 +222,7 @@ int32_t csi_pmu_enter_sleep(pmu_handle_t handle, pmu_mode_e mode) if (pmu_priv->cb) { pmu_priv->cb(pmu_priv->idx, PMU_EVENT_PREPARE_SLEEP, mode); } + set_sleep_flag(0); *((unsigned int *)0x4000f0c0) = 0x2; subWriteReg(0x4000f01c, 6, 6, 0x00); //disable software control enter_sleep_off_mode(SYSTEM_OFF_MODE); @@ -215,6 +235,7 @@ int32_t csi_pmu_enter_sleep(pmu_handle_t handle, pmu_mode_e mode) return 0; } + /** \brief Config the wakeup source. \param[in] handle pmu handle to operate diff --git a/pm.c b/pm.c index 21e8dd0..235c256 100644 --- a/pm.c +++ b/pm.c @@ -22,6 +22,7 @@ #include "pwrmgr.h" #include "pin.h" #include "pm.h" +#include "spif.h" #define DBGIO_LL_TRIG P14 #define DBGIO_LL_IRQ P15 @@ -40,7 +41,7 @@ extern uint32_t g_wakeup_rtc_tick;// = 0; extern uint32_t sleep_flag;// = 0; // when sleep, set this value to SLEEP_MAGIC. when wakeup, set this value to 0 extern uint32_t osal_sys_tick; -extern uint32_t g_counter_traking_avg ;// = 3906; +extern uint32_t g_counter_traking_avg ;// = 3906;7812(bug fix 2021/11/15) extern volatile uint32_t llWaitingIrq; //used for sleep timer sync @@ -65,6 +66,11 @@ extern uint32 read_LL_remainder_time(void); extern uint32_t read_current_fine_time(void); extern int clk_spif_ref_clk(sysclk_t spif_ref_sel); extern void hal_mpu_config(void); +extern void drv_reboot(int cmd); +extern void *osal_memcpy( void *dst, const void GENERIC *src, unsigned int len ); +extern void *osal_memset( void *dest, uint8 value, int len ); +extern __attribute__((section(".__sram.code"))) void config_reset_handler(int rstMod); +extern void jump_area_init(void); static uint32_t irq_flags; @@ -102,6 +108,10 @@ pm_wakeup_by_io_cb g_wakeup_cb = NULL; #define CONFIG_WDT 0 #endif +#ifndef CONFIG_LOW_POWER_WAKE_DEBUG +#define CONFIG_LOW_POWER_WAKE_DEBUG 0 +#endif + #if (CONFIG_WDT > 0) #define WDT_TIMEOUT 2000 static wdt_handle_t wdt_handle = NULL; @@ -200,7 +210,7 @@ void wdt_wakeup_action() while (delay-- > 0); - AP_WDT->CR = 0x1F; + AP_WDT->CR = 0x1D; csi_wdt_set_timeout(wdt_handle, WDT_TIMEOUT); #endif @@ -282,71 +292,6 @@ __attribute__((section(".__sram.code"))) static void usart_wakeup_action(void) registers_save((uint32_t *)addr + 3, &usart_regs_saved[3], 2); } #endif -#define CRY32_2_CYCLE_16MHZ_CYCLE_MAX (976 + 196) // tracking value range std +/- 20% -#define CRY32_2_CYCLE_16MHZ_CYCLE_MIN (976 - 196) -#define CRY32_2_CYCLE_DELTA_LMT (97) - -uint32_t g_xtal16M_waitCnt=0; -uint32_t g_xtal16M_tmp=0; -volatile uint8_t g_rc32kCalRes; - -extern uint8 rc32k_calibration(void); - -void rf_calibrate2(void) -{ - //========== do rf tp cal for tx and rx dcoffset cal - rf_phy_ana_cfg(); - rf_tpCal_gen_cap_arrary(); //generate the tpCal cap arrary - //rf_tpCal_cfg(/*rfChn*/2); - rf_rxDcoc_cfg(/*rfChn*/88,/*bwSet*/1,&g_rfPhyRxDcIQ); //set the rfChn as 2488 for BW=1MHz - g_rc32kCalRes = rc32k_calibration(); -} - -static void check_16MXtal_by_rcTracking(void) -{ - /* - for fiset wakeupini, not do rcCal, just skip the rcTacking - */ - if(g_rc32kCalRes==0xFF) - { - WaitRTCCount(30); - return; - } - - uint32_t temp,temp1,waitCnt; - // ======== enable tracking 32KHz RC timer with 16MHz crystal clock - temp = *(volatile uint32_t *)0x4000f040; - *(volatile uint32_t *)0x4000f040 = temp | BIT(18); - - waitCnt=0; - - temp = *(volatile uint32_t *)0x4000f05C; - *(volatile uint32_t *)0x4000f05C = (temp & 0xfffefe00) | 0x0028; - WaitRTCCount(2); - temp = (*(volatile uint32_t *)0x4000f064 & 0x1ffff); - - while(1) // - { - // 1. read RC 32KHz tracking counter, calculate 16MHz ticks number per RC32KHz cycle - waitCnt++; - WaitRTCCount(2); - temp1 = (*(volatile uint32_t *)0x4000f064 & 0x1ffff); - - if( temp1>CRY32_2_CYCLE_16MHZ_CYCLE_MIN && - temp1CRY32_2_CYCLE_16MHZ_CYCLE_MIN && - temp temp1 ? (temp -temp1):(temp1>temp)))waitCnt) ? g_xtal16M_waitCnt: waitCnt; -} uint8_t isSleepAllowInPM(void) { @@ -400,6 +345,22 @@ void set_sleep_flag(int flag) // *(volatile uint32_t *) 0x4000f024 |= 1 << 15; //enable comparator0 inerrupt //*(volatile uint32_t *) 0x4000f024 |= 0x148000; // combine above 3 statement to save MCU time +void rc32k_cap_cal(uint32_t temp) +{ + uint32_t rccap; + if((temp > CRY32_16_CYCLE_16MHZ_CYCLE_MAX) && ((*(volatile uint32_t *) 0x4000f018 & 0x7e) > 0)) + { + rccap = ((read_reg(0x4000f018)>>1) & 0x3f) - 1; + subWriteReg(0x4000f018,6,1,rccap); + WaitRTCCount(3); + } + else if((temp < CRY32_16_CYCLE_16MHZ_CYCLE_MIN) && ((*(volatile uint32_t *) 0x4000f018 & 0x7e) < 0x7e)) + { + rccap = ((read_reg(0x4000f018)>>1) & 0x3f) + 1; + subWriteReg(0x4000f018,6,1,rccap); + WaitRTCCount(3); + } +} void enterSleepProcess1(uint32_t time) { @@ -433,7 +394,8 @@ void enterSleepProcess1(uint32_t time) counter_tracking = (temp > CRY32_16_CYCLE_16MHZ_CYCLE_MAX) ? counter_tracking : temp; //20181204 filter the counter_tracking spur, due to the N+1 issue - + rc32k_cap_cal(temp); + if (g_counter_traking_cnt < 1000) { //before traking converage use hard limitation counter_tracking = (counter_tracking > CRY32_16_CYCLE_16MHZ_CYCLE_MAX || counter_tracking < CRY32_16_CYCLE_16MHZ_CYCLE_MIN) @@ -443,8 +405,8 @@ void enterSleepProcess1(uint32_t time) } else { //after tracking converage use soft limitation - counter_tracking = (counter_tracking > g_counter_traking_avg + (g_counter_traking_avg >> 8) - || counter_tracking < g_counter_traking_avg - (g_counter_traking_avg >> 8)) + counter_tracking = (counter_tracking > g_counter_traking_avg + (g_counter_traking_avg >> 3) + || counter_tracking < g_counter_traking_avg - (g_counter_traking_avg >> 3)) ? g_counter_traking_avg : counter_tracking; } @@ -502,7 +464,6 @@ void enterSleepProcess1(uint32_t time) // 5. set sleep flag(AON reg & retention SRAM variable) set_sleep_flag(1); - // 6. trigger system sleep csi_pmu_enter_sleep(pmu_handle, PMU_MODE_DORMANT); } @@ -512,7 +473,11 @@ void osal_pwrmgr_powerconserve_dummy(void) //do nothing return; } - +void sram_HardFault_Handler(void) +{ + subWriteReg(&(AP_PCRM->CLKSEL),2,0,SYS_CLK_RC_32M); + drv_reboot(1); +} /****************************************** // SOC interfaces ******************************************/ @@ -534,6 +499,9 @@ int sys_soc_suspend(uint32_t suspend_tick) RHINO_CPU_INTRPT_DISABLE(); irq_flags = psr; + extern void check_hclk_by_rc32k_rtc(void); + check_hclk_by_rc32k_rtc(); + if (!isSleepAllowInPM()) { RHINO_CPU_INTRPT_ENABLE(); __WFI(); @@ -702,6 +670,283 @@ int sys_soc_suspend(uint32_t suspend_tick) #define BASE_TIME_UNITS (0x3fffff) #endif +#define CRY32_2_CYCLE_16MHZ_CYCLE_MAX (976 + 98) // tracking value range std +/- 20% +#define CRY32_2_CYCLE_16MHZ_CYCLE_MIN (976 - 98) +#define CRY32_2_CYCLE_DELTA_LMT (19) +#define TRACKING_96M_16M_MULTI6_DELTA_LIMIT (10*6) //96M:16M*6 +- 1% +#define DLL_ENABLE_MAX (5) +#define TRACKING_16M_TICK_MAX (3300) +#define TRACKING_MAX_SLEEPTIME (1980000) //MAX sleep time is 60 seconds. + +//volatile uint8_t g_rc32kCalRes = 0xff; +uint32_t g_xtal16M_tmp=0; +uint32_t g_xtal96M_temp=0; +uint32_t DLL_enable_num=1; +uint32_t tracking_16M_num = 0; +extern void Reset_Handler(); +extern int SystemResetCause(void); +extern uint32_t g_system_reset_cause; +void _rom_data_init(void) +{ + //copy rom data section + osal_memcpy((void *)0x1fff0800,(const void GENERIC *)0x17c7c,(0x1fff0924-0x1fff0800)); + //clr rom bss section skip g_top_trapstack + osal_memset((void *)0x1fff0924,0,(0x1fff0988-0x1fff0924)); + osal_memset((void *)0x1fff0b8c,0,(0x1fff1a3c-0x1fff0b8c)); +} + +void sram_reset_handler(void) +{ + subWriteReg(&AP_SPIF->config, 14, 14, 1); //enable wp bit(14) + + AP_PCR->CACHE_BYPASS = 1;//disable cache + AP_SPIF->fcmd_wrdata[0] = 0x94; + clk_init(SYS_CLK_RC_32M); + config_reset_handler(1); + + + + g_spif_ref_clk = SYS_CLK_RC_32M; + hal_cache_init(); + hal_flash_write_disable(); + hal_mpu_config(); + + _rom_data_init(); + + + + /* + update reset cause, add 0x80 to mark the reset path from sram_reset_handler + */ + SystemResetCause(); + g_system_reset_cause |=0x80; + + //check just_sleep_reset flg + if((((*(volatile uint32_t*)0x4000f0c4) & 0x0f)>>2)) + g_system_reset_cause |=0x40; + + Reset_Handler(); +} +void just_enter_sleep(uint32 time) +{ + jump_area_init(); + JUMP_FUNCTION(WAKEUP_PROCESS) = (uint32_t)sram_reset_handler; + + /* set sleep flag , rom boot will check the flag and + set reset path from WAKEUP_PROCESS */ + phy_gpioretention_disable(); + set_sleep_flag(1); + + subWriteReg(&(AP_AON->PMCTL2_0),6,6,0x00); //disable software control + // config wakeup timer + uint32_t sleep_tick_now = *(volatile uint32_t *) 0x4000f028; + WaitRTCCount(1); + AP_AON->RTCCC0 = sleep_tick_now + time; + AP_AON->RTCCTL |= BIT(15)|BIT(18)|BIT(20); + + // clear sram retention + // hal_pwrmgr_RAM_retention_clr(); + + /** + config reset casue as RSTC_WARM_NDWC + reset path walkaround dwc + */ + AP_AON->SLEEP_R[0]=4; + + // trigger system sleep + enter_sleep_off_mode(SYSTEM_SLEEP_MODE); +} + + +#define RTC_32KRC_3_CYCLE_LIMIT_LOW (60) //3*30.5 normal pclk +#define RTC_32KRC_3_CYCLE_LIMIT_HIGH (120) //3*30.5 normal pclk + +void check_hclk_by_rc32k_rtc(void) +{ + WaitRTCCount(1); + uint32_t t0 = read_current_fine_time(); + WaitRTCCount(3); + uint32_t t1 = read_current_fine_time(); + if((TIME_DELTA(t1,t0)RTC_32KRC_3_CYCLE_LIMIT_HIGH)) + { + subWriteReg(0x4000f03c, 2, 0, 0); //switch hclk to RC32M + just_enter_sleep(33000); + + } + + +} + + +void check_16MXtal_by_rcTracking(void) +{ + /* + + for fiset wakeupini, not do rcCal, just skip the rcTacking + */ + + if(((*(volatile uint32_t*)0x4000f0c4) & 0x80) == 0) + { + WaitRTCCount(60); + return; + } + + uint32_t tracking_start = rtc_get_counter(); + + uint32_t temp,temp1; + uint32_t temp31,temp32,temp33; + uint32_t temp_min,temp_max; + + // ======== enable tracking 32KHz RC timer with 16MHz crystal clock + temp = *(volatile uint32_t *)0x4000f040; + *(volatile uint32_t *)0x4000f040 = temp | BIT(18); + temp = *(volatile uint32_t *)0x4000f05C; + *(volatile uint32_t *)0x4000f05C = (temp & 0xfffefe00) | 0x0028; + WaitRTCCount(3); + + temp31 = (*(volatile uint32_t *)0x4000f064 & 0x1ffff); + WaitRTCCount(3); + + temp32 = (*(volatile uint32_t *)0x4000f064 & 0x1ffff); + WaitRTCCount(3); + + temp33 = (*(volatile uint32_t *)0x4000f064 & 0x1ffff); + + while(1) + { + temp_min = (temp31 >=temp32) ? (temp32):(temp31); + temp_min = (temp_min >=temp33) ? (temp33):(temp_min); + temp_max = (temp31 >=temp32) ? (temp31):(temp32); + temp_max = (temp_max >=temp33) ? (temp_max):(temp33); + + if( temp31>CRY32_2_CYCLE_16MHZ_CYCLE_MIN && + temp31CRY32_2_CYCLE_16MHZ_CYCLE_MIN && + temp32 CRY32_2_CYCLE_16MHZ_CYCLE_MIN && + temp33 =tracking_start) ? (tracking_end-tracking_start) : (0xffffffff-tracking_start+tracking_end); + if(tracking_16M_tick >= TRACKING_16M_TICK_MAX) + { + uint32_t tracking_sleep_num = (*(volatile uint32_t*)0x4000f0c4 & 0xFF00) >>8; + subWriteReg(0x4000f0c4,15,8,tracking_sleep_num+1); + subWriteReg(0x4000f0c4,3,2,1); + if ((1 << tracking_sleep_num)*33000< TRACKING_MAX_SLEEPTIME) + { + just_enter_sleep((1 << tracking_sleep_num)*33000); + } + else + { + just_enter_sleep(TRACKING_MAX_SLEEPTIME); + } + } + + } + + temp1 = (*(volatile uint32_t *)0x4000f064 & 0x1ffff); + + subWriteReg(0x4000f05C,3,3,0); + + g_xtal16M_tmp = temp1; +} + +void check_96MXtal_by_rcTracking(void) +{ + uint32_t temp,temp1; + //for first wakeupinit + + if(((*(volatile uint32_t*)0x4000f0c4) & 0x80) == 0) + { + //enable DLL + temp = *(volatile uint32_t *)0x4000f044; + *(volatile uint32_t *)0x4000f044 = temp | BIT(7); + WaitRTCCount(3); + return; + } + + DLL_enable_num=0; + + // ======== enable tracking 32KHz RC timer with 16MHz crystal clock + temp = *(volatile uint32_t *)0x4000f040; + *(volatile uint32_t *)0x4000f040 = temp | BIT(18); + + while(1) + { + //enable DLL + temp = *(volatile uint32_t *)0x4000f044; + *(volatile uint32_t *)0x4000f044 = temp | BIT(7); + WaitRTCCount(3); + DLL_enable_num++; + + // //enable digclk 96M + + temp = *(volatile uint32_t *)0x4000f044; + *(volatile uint32_t *)0x4000f044 = temp | BIT(16); + for(uint8 index=0;index<5;index++) + { + temp = *(volatile uint32_t *)0x4000f05C; + *(volatile uint32_t *)0x4000f05C = (temp & 0xfffefe00) | 0x0028 | BIT(16); + WaitRTCCount(3); + temp1 = (*(volatile uint32_t *)0x4000f064 & 0x1ffff); + subWriteReg(0x4000f05C,3,3,0); + if( (g_xtal16M_tmp*6 >=temp1 ? (g_xtal16M_tmp*6 -temp1):(temp1-g_xtal16M_tmp*6))= DLL_ENABLE_MAX) + { + subWriteReg(0x4000f0c4,5,4,1); + just_enter_sleep(60); + } + + //disable DLL + + subWriteReg(0x4000f044,7,7,0); + WaitRTCCount(3); + + //update g_xtal16M_tmp + temp = *(volatile uint32_t *)0x4000f05C; + *(volatile uint32_t *)0x4000f05C = (temp & 0xfffefe00) | 0x0028 ; + WaitRTCCount(3); + g_xtal16M_tmp = (*(volatile uint32_t *)0x4000f064 & 0x1ffff); + + subWriteReg(0x4000f05C,3,3,0); + } + +} + +uint32_t tracking_cnt=0; void wakeup_init1() { uint8_t pktFmt = 1; // packet format 1: BLE 1M uint32_t temp; @@ -713,7 +958,27 @@ void wakeup_init1() { //each rtc count is about 30.5us //after 15count , xtal will be feedout to dll and doubler //WaitRTCCount(pGlobal_config[WAKEUP_DELAY]); - check_16MXtal_by_rcTracking(); + if(g_system_clk == SYS_CLK_XTAL_16M) + { + //WaitRTCCount(pGlobal_config[WAKEUP_DELAY]); + WaitRTCCount(10); + check_16MXtal_by_rcTracking(); + } + else + { + uint32_t tracking_c1,tracking_c2; + tracking_c1 = rtc_get_counter(); + WaitRTCCount(30); + subWriteReg(0x4000f0c4,1,0,0); + check_16MXtal_by_rcTracking(); + WaitRTCCount(6); + subWriteReg(0x4000f0c4,1,0,1); + check_96MXtal_by_rcTracking(); + subWriteReg(0x4000f0c4,1,0,2); + tracking_c2 = rtc_get_counter(); + tracking_cnt = (tracking_c2>=tracking_c1) ? (tracking_c2-tracking_c1) : (0xffffffff-tracking_c1+tracking_c2); + pGlobal_config[WAKEUP_ADVANCE] =1500+30*tracking_cnt; + } // ============ config BB Top *(volatile uint32_t *) 0x40030000 = 0x3d068001; // set tx pkt =2 @@ -721,7 +986,7 @@ void wakeup_init1() { *(volatile uint32_t *) 0x400300a4 = 0x140; //[6] for tpm_en clk_init(g_system_clk); - + subWriteReg(0x4000f0c4,1,0,3); hal_wakeup_irq_config(); // ========== init timers @@ -755,6 +1020,8 @@ static void hw_spif_cache_config(void) { hal_cache_init(); } +extern void efuse_init(void); + int sys_soc_resume(int pm_state) { uint32_t current_RTC_tick; uint32_t wakeup_time, wakeup_time0, next_time; @@ -764,6 +1031,15 @@ int sys_soc_resume(int pm_state) { if (pm_state == SYS_POWER_STATE_RUN) { return 0; } + + AP_PCR->CACHE_BYPASS = 1;//disable cache + AP_SPIF->fcmd_wrdata[0] = 0x94; + + config_reset_handler(1); + + efuse_init(); + + wdt_wakeup_action(); DBG_GPIO_WRITE(DBGIO_APP_WAKEUP, 1); // restore HW registers @@ -789,14 +1065,14 @@ int sys_soc_resume(int pm_state) { //config the tx2rx timing according to the g_rfPhyPktFmt ll_hw_tx2rx_timing_config(g_rfPhyPktFmt); - if (pGlobal_config[LL_SWITCH] & LL_RC32K_SEL) { - subWriteReg(0x4000f01c, 16, 7, 0x3fb); //software control 32k_clk - subWriteReg(0x4000f01c, 6, 6 , 0x01); //enable software control + // if (pGlobal_config[LL_SWITCH] & LL_RC32K_SEL) { + // subWriteReg(0x4000f01c, 16, 7, 0x3fb); //software control 32k_clk + // subWriteReg(0x4000f01c, 6, 6 , 0x01); //enable software control - } else { - subWriteReg(0x4000f01c, 9, 8, 0x03); //software control 32k_clk - subWriteReg(0x4000f01c, 6, 6, 0x00); //disable software control - } + // } else { + // subWriteReg(0x4000f01c, 9, 8, 0x03); //software control 32k_clk + // subWriteReg(0x4000f01c, 6, 6, 0x00); //disable software control + // } //20181201 by ZQ //restart the TIM2 to align the RTC @@ -924,7 +1200,7 @@ int sys_soc_resume(int pm_state) { ll_debug_output(DEBUG_WAKEUP); - set_sleep_flag(0); +// set_sleep_flag(0); DBG_GPIO_WRITE(DBGIO_APP_WAKEUP, 1); @@ -932,12 +1208,27 @@ int sys_soc_resume(int pm_state) { hal_mpu_config(); //clk_spif_ref_clk(g_spif_ref_clk); - + /* clear tick irq state by reading reg */ + int count; + unsigned int v = *((volatile unsigned int *) (0xE000E010)); + while((v & 0x10000) > 0) + { + v = *((volatile unsigned int *) (0xE000E010)); + count++; + } + #if (CONFIG_LOW_POWER_WAKE_DEBUG == 1) + gpio_write(P25,1); + gpio_write(P25,0); + #endif CPSR_ALLOC(); psr = irq_flags; RHINO_CPU_INTRPT_ENABLE(); - wdt_wakeup_action(); +// wdt_wakeup_action(); + #if(CONFIG_LOW_POWER_WAKE_DEBUG == 1) + gpio_write(P33,1); + gpio_write(P33,0); + #endif //usart_wakeup_action(); pm_after_sleep_action(); diff --git a/port_s.S b/port_s.S index a3b38f6..38152f3 100644 --- a/port_s.S +++ b/port_s.S @@ -218,7 +218,7 @@ tspend_handler: jbsr krhino_stack_ovf_check #endif -#if (RHINO_CONFIG_TASK_SCHED_STATS > 0) +#if (RHINO_CONFIG_SYS_STATS > 0) jbsr krhino_task_sched_stats_get #endif diff --git a/reboot.c b/reboot.c index b64b501..f25fcb6 100644 --- a/reboot.c +++ b/reboot.c @@ -14,27 +14,48 @@ #include #include #include +#include "jump_function.h" + +#define RST_FROM_ROM_BOOT 0 +#define RST_FROM_APP_RST_HANDLER 1 + extern size_t cpu_intrpt_save(void); +extern void sram_reset_handler(void); +extern void set_sleep_flag(int flag); + +__attribute__((section(".__sram.code"))) void config_reset_handler(int rstMod) +{ + if(rstMod==RST_FROM_ROM_BOOT) + { + set_sleep_flag(0); + } + else + { + JUMP_FUNCTION(WAKEUP_PROCESS) = (uint32_t)sram_reset_handler; + extern void trap_c(uint32_t *regs); + extern void sram_HardFault_Handler(void); + JUMP_FUNCTION(CK802_TRAP_C) = (uint32_t)&sram_HardFault_Handler; //register trap irq handler + set_sleep_flag(1); + } +} __attribute__((section(".__sram.code"))) void drv_reboot(int cmd) { csi_irq_save(); - - volatile int dly = 100; - - //cache rst + AP_PCR->CACHE_BYPASS = 1; +// hal_flash_write_disable(); +// AP_SPIF->config = 0; AP_PCR->CACHE_RST = 0; - while (dly--) {}; - - AP_PCR->CACHE_RST = 0x03; + // config reset path , from rom or app + config_reset_handler(cmd); + /** + config reset casue as RSTC_WARM_NDWC + reset path walkaround dwc + */ + AP_AON->SLEEP_R[0]=4; - //cache flush tag - AP_CACHE->CTRL0 = 0x03; - - //cache enable - AP_PCR->CACHE_BYPASS = 1; *(volatile uint32_t *) 0x40000004 = 0x00; diff --git a/startup.S b/startup.S index 9e11059..c8077d3 100644 --- a/startup.S +++ b/startup.S @@ -32,9 +32,6 @@ .globl __Vectors .type __Vectors, @object __Vectors: - .long Reset_Handler - .size __Vectors, . - __Vectors - br Reset_Handler .align 2 .long 0x594B5343 /* CSKY ASCII */ diff --git a/system.c b/system.c index 1722b79..a13011a 100644 --- a/system.c +++ b/system.c @@ -35,6 +35,11 @@ #include "sys_freq.h" #include #include "pm.h" +#include "spif.h" + +#ifndef CONFIG_SYSTICK_HZ +#define CONFIG_SYSTICK_HZ 100 +#endif extern volatile sysclk_t g_system_clk; int g_spif_ref_clk = SYS_CLK_DLL_64M; @@ -71,7 +76,7 @@ __attribute__((section(".__sram.code"))) void hal_cache_init(void) hal_clk_gate_enable(MOD_PCLK_CACHE); //cache rst - AP_PCR->CACHE_RST = 0x00; + AP_PCR->CACHE_RST = 0x02; while (dly--) {}; @@ -79,13 +84,16 @@ __attribute__((section(".__sram.code"))) void hal_cache_init(void) AP_PCR->CACHE_RST = 0x03; //cache flush tag - AP_CACHE->CTRL0 = 0x01; + //AP_CACHE->CTRL0 = 0x01; + hal_cache_tag_flush(); //cache enable AP_PCR->CACHE_BYPASS = 0; spif_config(g_spif_ref_clk, 0x1, 0x801003b, 0, 0); + subWriteReg(&AP_SPIF->config, 14, 14, 1); //enable wp bit(14) + AP_SPIF->low_wr_protection = 0; AP_SPIF->up_wr_protection = 0x10; @@ -194,7 +202,9 @@ static void hal_low_power_io_init(void) drv_pm_ram_retention(RET_SRAM0 | RET_SRAM1 | RET_SRAM2); //hal_pwrmgr_RAM_retention(RET_SRAM0); hal_pwrmgr_RAM_retention_set(); +#if (defined(CONFIG_SYS_CLK_XTAL_16M) && CONFIG_SYS_CLK_XTAL_16M > 0) hal_pwrmgr_LowCurrentLdo_enable(); +#endif //========= low power module clk gate #if(PHY_MCU_TYPE==MCU_BUMBEE_CK802) *(volatile uint32_t *)0x40000008 = 0x001961f1; // @@ -210,7 +220,7 @@ static void hal_low_power_io_init(void) static void hal_init(void) { hal_low_power_io_init(); - + hal_rtc_clock_config(g_clk32K_config); //hal_pwrmgr_init(); } @@ -229,9 +239,12 @@ __attribute__((section(".__data_copy_first__"))) void check_before_startup() { //check_data = -1; } - void SystemInit(void) { + // /* USE CONFIG_WDT=1 to enable wdt */ + extern void wdt_init(void); + wdt_init(); + subWriteReg(&AP_SPIF->config, 14, 14, 1); //enable wp bit(14) /* Clear active and pending IRQ */ VIC->IABR[0] = 0x0; VIC->ICPR[0] = 0xFFFFFFFF; @@ -249,9 +262,9 @@ void SystemInit(void) g_spif_ref_clk = SYS_CLK_DLL_64M; - hal_rtc_clock_config(g_clk32K_config); - - JUMP_FUNCTION(CK802_TRAP_C) = (uint32_t)&trap_c; //register trap irq handler + + extern void sram_HardFault_Handler(void); + JUMP_FUNCTION(CK802_TRAP_C) = (uint32_t)&sram_HardFault_Handler; //register trap irq handler #ifdef CONFIG_KERNEL_NONE _system_init_for_baremetal(); diff --git a/trap_c.c b/trap_c.c index 0a764a7..2d1e126 100644 --- a/trap_c.c +++ b/trap_c.c @@ -27,6 +27,16 @@ #include void (*trap_c_callback)(void); +extern char * strerror(int errnum); +extern void drv_reboot(int cmd); + + +static void except_process_function(int errno, const char *file, int line, const char *func_name, void *caller) +{ + printf("Except! errno is %s, caller: %p\n", strerror(errno), caller); + drv_reboot(1); +} + void trap_c(uint32_t *regs) { @@ -47,9 +57,11 @@ void trap_c(uint32_t *regs) printf("epsr: %8x\n", regs[16]); printf("epc : %8x\n", regs[17]); - if (trap_c_callback) { - trap_c_callback(); - } + except_process_function(1, __FILE__, __LINE__, __func__, NULL); + +// if (trap_c_callback) { +// trap_c_callback(); +// } while (1); } -- Gitee From cac409e6097dda58314760451ac27156cb877547 Mon Sep 17 00:00:00 2001 From: "qing.han" Date: Tue, 29 Mar 2022 16:26:53 +0800 Subject: [PATCH 2/2] 1.change adc driver for polling mode 2.cost dowm sram in patch xip mode 3.bugfixed secondary adv/scan timing --- components/driver/src/phy_adc.c | 6 +- components/inc/types.h | 2 +- csi_drivers/spif.c | 127 +++++++++++++++++++------------- flash/TG7120B_Flash.elf | Bin 81844 -> 79664 bytes include/spif.h | 39 ++++++++++ misc/rom_sym_def.h | 3 + pm.c | 109 ++++++++++++++------------- reboot.c | 3 +- system.c | 3 +- 9 files changed, 184 insertions(+), 108 deletions(-) diff --git a/components/driver/src/phy_adc.c b/components/driver/src/phy_adc.c index b8d641c..a15dccb 100644 --- a/components/driver/src/phy_adc.c +++ b/components/driver/src/phy_adc.c @@ -222,7 +222,7 @@ int phy_adc_start_int_dis(void) //hal_pwrmgr_lock(MOD_ADCC); //JUMP_FUNCTION(V29_IRQ_HANDLER) = (uint32_t)&hal_ADC_IRQHandler; - MASK_ADC_INT; + AP_ADCC->intr_mask = 0x1ff; drv_irq_disable(ADCC_IRQn); drv_irq_unregister(ADCC_IRQn); @@ -885,6 +885,10 @@ static int read_multiple_channel_n(adc_handle_t handle, uint32_t *data, uint32_t break; ch_cur=(ch%2)?(ch-1):(ch+1); + + while(!(read_reg(0x4005003c)&BIT(ch_cur))); + + subWriteReg(0x40050038,ch_cur,ch_cur,1); ++i; i&=0x07; diff --git a/components/inc/types.h b/components/inc/types.h index d1c404b..1476922 100644 --- a/components/inc/types.h +++ b/components/inc/types.h @@ -169,7 +169,7 @@ typedef struct _comm_evt_t { typedef void (*comm_cb_t)(comm_evt_t *pev); - +#define __ATTR_FUNC_XIP__(fn) __attribute__(( section("__xip_function__."#fn))) fn #endif diff --git a/csi_drivers/spif.c b/csi_drivers/spif.c index 206a771..f737ee9 100644 --- a/csi_drivers/spif.c +++ b/csi_drivers/spif.c @@ -59,6 +59,7 @@ extern void WaitRTCCount(uint32_t rtcDelyCnt); extern uint8_t spif_flash_status_reg_0(void); extern uint8_t spif_flash_status_reg_1(void); extern void spif_wrdata(uint8_t* data, uint8_t len); +extern void ll_patch_restore(uint8_t flg); #define SPIF_TIMEOUT 1000000 @@ -102,6 +103,7 @@ __attribute__((section(".__sram.code"))) static inline uint32_t spif_lock() VIC->ICER[0] = 0xFFFFFFFF; //enable ll irq and tim1 irq VIC->ISER[0] = 0x100010; + ll_patch_restore(0); HAL_EXIT_CRITICAL_SECTION(); return vic_iser; } @@ -111,6 +113,7 @@ __attribute__((section(".__sram.code"))) static inline void spif_unlock(uint32_ _HAL_CS_ALLOC_(); HAL_ENTER_CRITICAL_SECTION(); VIC->ISER[0] = vic_iser; + ll_patch_restore(1); HAL_EXIT_CRITICAL_SECTION(); } @@ -193,16 +196,17 @@ __attribute__((section(".__sram.code"))) static int _spif_wait_nobusy_x(uint8_t return PPlus_ERR_BUSY; } -__attribute__((section(".__sram.code"))) uint8_t hal_flash_lock_status(void) +__attribute__((section(".__sram.code"))) uint16_t hal_flash_lock_status() { - uint8_t status = _spif_read_status_reg_x(); - return status&(FCMD_DATAPRO_AREA_512|FCMD_SRP_REG); - + uint16_t status = _spif_read_status_reg_x(); + if(s_spif_ctx.mid == FLASH_TH_ID) + return status&(FCMD_DATAPRO_AREA_512_TH | FCMD_SRP_REG_TH); + return status&(FCMD_DATAPRO_AREA_512 | FCMD_SRP_REG); } __attribute__((section(".__sram.code"))) uint8_t hal_flash_write_disable(void) { - uint32_t result = csi_irq_save(); + uint32_t cs = spif_lock(); uint8_t status; status = _spif_read_status_reg_x(); if(status & SFLG_WEL) @@ -211,34 +215,51 @@ __attribute__((section(".__sram.code"))) uint8_t hal_flash_write_disable(void) SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); } - csi_irq_restore(result); + spif_unlock(cs); return 0; } -__attribute__((section(".__sram.code"))) int hal_flash_lock(uint8_t area) +__attribute__((section(".__sram.code"))) int hal_flash_lock(uint16_t area) { - uint32_t result = csi_irq_save(); - area &= FCMD_DATAPRO_AREA_512; - area |= FCMD_SRP_REG; + uint32_t cs = spif_lock(); + if(s_spif_ctx.mid == FLASH_TH_ID) + { + area |= FCMD_DATAPRO_AREA_512_TH; + area |= FCMD_SRP_REG_TH; + } + else + { + area &= FCMD_DATAPRO_AREA_512; + area |= FCMD_SRP_REG; + } if(area != hal_flash_lock_status()) { - SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); - spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); - AP_SPIF->fcmd = XFRD_FCMD_WREN; - SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); - spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); - AP_SPIF->fcmd_wrdata[0] = area | FCMD_SRP_REG; - AP_SPIF->fcmd = XFRD_FCMD_WRST; - SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); - spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + if(s_spif_ctx.mid == FLASH_TH_ID) + { + area |= FCMD_SRP_REG_TH; + hal_flash_wr_status_reg((uint8 *)&area,2); + + } + else + { + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + AP_SPIF->fcmd = XFRD_FCMD_WREN; + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + AP_SPIF->fcmd_wrdata[0] = area | FCMD_SRP_REG; + AP_SPIF->fcmd = XFRD_FCMD_WRST; + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + } } - csi_irq_restore(result); + spif_unlock(cs); return 0; } - -__attribute__((section(".__sram.code"))) int hal_flash_unlock(void) -{ - uint32_t result = csi_irq_save(); +__attribute__((section(".__sram.code"))) int hal_flash_unlock() +{ + + uint32_t cs = spif_lock(); if(FCMD_DATAPRO_AREA_NONE != hal_flash_lock_status()) { @@ -253,7 +274,7 @@ __attribute__((section(".__sram.code"))) int hal_flash_unlock(void) SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); } - csi_irq_restore(result); + spif_unlock(cs); return 0; } @@ -261,9 +282,7 @@ __attribute__((section(".__sram.code"))) int hal_flash_unlock(void) __attribute__((section(".__sram.code"))) static int hal_flash_write(uint32_t addr, uint8_t *data, uint32_t size) { uint8_t retval; - - uint32_t result = csi_irq_save(); - //hal_flash_unlock(); + uint32_t cs = spif_lock(); HAL_CACHE_ENTER_BYPASS_SECTION(); SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); @@ -272,14 +291,13 @@ __attribute__((section(".__sram.code"))) static int hal_flash_write(uint32_t ad SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); HAL_CACHE_EXIT_BYPASS_SECTION(); - //hal_flash_lock(); - csi_irq_restore(result); + spif_unlock(cs); return retval; } __attribute__((section(".__sram.code"))) static int hal_flash_read(uint32_t addr, uint8_t *data, uint32_t size) { - uint32_t result = csi_irq_save(); + uint32_t cs = spif_lock(); volatile uint8_t *u8_spif_addr = (volatile uint8_t *)((addr & 0x7ffff) | SPIF_ADDR_START); uint32_t cb = AP_PCR->CACHE_BYPASS; //#if(SPIF_FLASH_SZIE == FLASH_SIZE_1MB) @@ -319,8 +337,7 @@ __attribute__((section(".__sram.code"))) static int hal_flash_read(uint32_t add #endif -// spif_unlock(cs); - csi_irq_restore(result); + spif_unlock(cs); return PPlus_SUCCESS; } @@ -328,9 +345,8 @@ __attribute__((section(".__sram.code"))) static int hal_flash_read(uint32_t add __attribute__((section(".__sram.code"))) int hal_flash_erase_sector(unsigned int addr) { uint8_t retval; - - uint32_t result = csi_irq_save(); - //hal_flash_unlock(); + uint32_t cs = spif_lock(); + uint32_t cb = AP_PCR->CACHE_BYPASS; SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); @@ -343,8 +359,7 @@ __attribute__((section(".__sram.code"))) int hal_flash_erase_sector(unsigned in hal_cache_tag_flush(); } - //hal_flash_lock(); - csi_irq_restore(result); + spif_unlock(cs); return retval; } @@ -352,9 +367,8 @@ __attribute__((section(".__sram.code"))) int hal_flash_erase_sector(unsigned in __attribute__((section(".__sram.code"))) int hal_flash_erase_block64(unsigned int addr) { uint8_t retval; - - uint32_t result = csi_irq_save(); - //hal_flash_unlock(); + uint32_t cs = spif_lock(); + uint32_t cb = AP_PCR->CACHE_BYPASS; SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); @@ -365,17 +379,16 @@ __attribute__((section(".__sram.code"))) int hal_flash_erase_block64(unsigned i hal_cache_tag_flush(); } - //hal_flash_lock(); - csi_irq_restore(result); + spif_unlock(cs); + return retval; } __attribute__((section(".__sram.code"))) int hal_flash_erase_all(void) { uint8_t retval; - uint32_t result = csi_irq_save(); - - //hal_flash_unlock(); + uint32_t cs = spif_lock(); + uint32_t cb = AP_PCR->CACHE_BYPASS; SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); @@ -386,12 +399,19 @@ __attribute__((section(".__sram.code"))) int hal_flash_erase_all(void) hal_cache_tag_flush(); } - //hal_flash_lock(); - csi_irq_restore(result); + spif_unlock(cs); return retval; } +__attribute__((section(".__sram.code")))uint16_t hal_flash_area_choose() +{ + uint16_t area = FCMD_DATAPRO_AREA_384; + if(s_spif_ctx.mid == FLASH_TH_ID) + area = FCMD_DATAPRO_AREA_384_TH | FCMD_DATAPRO_AREA_384_TH_CMP; + return area; +} + /* basic spif driver */ @@ -460,7 +480,7 @@ uint32_t phy_flash_block64_erase(unsigned int addr) __attribute__((section(".__sram.code"))) int hal_flash_rd_status_reg(uint8* buf,bool low_8bit) { uint8_t retval = PPlus_SUCCESS; - uint32_t result = csi_irq_save(); + uint32_t cs = spif_lock(); SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); @@ -475,7 +495,7 @@ __attribute__((section(".__sram.code"))) int hal_flash_rd_status_reg(uint8* buf, } SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); - csi_irq_restore(result); + spif_unlock(cs); return retval; } @@ -483,14 +503,14 @@ __attribute__((section(".__sram.code"))) int hal_flash_rd_status_reg(uint8* buf, __attribute__((section(".__sram.code"))) int hal_flash_wr_status_reg(uint8* buf,int len) { uint8_t retval = PPlus_SUCCESS; - uint32_t result; + //uint32_t result; if((len != 1) && (len != 2)) { return PPlus_ERR_INVALID_PARAM; } - result = csi_irq_save(); + uint32_t cs = spif_lock(); SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); @@ -504,7 +524,7 @@ __attribute__((section(".__sram.code"))) int hal_flash_wr_status_reg(uint8* buf, spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); - csi_irq_restore(result); + spif_unlock(cs); return retval; } @@ -914,3 +934,4 @@ int32_t csi_spiflash_power_control(spiflash_handle_t handle, /*csi_power_stat_e* return state; } + diff --git a/flash/TG7120B_Flash.elf b/flash/TG7120B_Flash.elf index c9ff7b2eaffb340f85bdb3bb1d0c7eec46999e4c..d6b5a6f5058ca7c42189bf9144dbd348f68ae0a4 100644 GIT binary patch literal 79664 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 PIvTzEDK6T-GT;9L0{epu literal 81844 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 A9smFU diff --git a/include/spif.h b/include/spif.h index 62add18..5cff3a6 100644 --- a/include/spif.h +++ b/include/spif.h @@ -25,6 +25,7 @@ //#include "drv_spiflash.h" //#include "soc.h" #include "types.h" +#include "rom_sym_def.h" #ifdef __cplusplus extern "C" { @@ -35,6 +36,27 @@ extern "C" { #define __IOM volatile /*! Defines 'read / write' structure member permissions */ #endif +typedef struct{ + uint8_t state; + uint32_t size; + + bool w_protect; + + uint8_t clk_div; + + uint32_t qspi_en; + uint32_t rd_instr; + uint32_t wr_instr; + uint32_t remap; + + /*device id*/ + uint8_t mid; + uint8_t mtype; //mempry type + uint8_t mcapc; //memory capcity +}spif_ctx_t; + +extern spif_ctx_t s_spif_ctx; + #define CONFIG_SPIFLASH_NUM 1 #define DEBUG_EN 1 //#define SPIF_ADDR_START 0x11005000 @@ -59,6 +81,7 @@ extern "C" { + #define FCMD_RESET 0x99 //reset #define FCMD_ENRST 0x66 //enable reset #define FCMD_WREN 0x06 //write enable @@ -88,14 +111,21 @@ extern "C" { #define FCMD_CMD_EXCUTE 0x01 #define FCMD_SRP_REG 0x80 +#define FCMD_SRP_REG_TH 0x0080 + #define FCMD_DATAPRO_AREA_NONE 0x00 #define FCMD_DATAPRO_AREA_504 0x04 #define FCMD_DATAPRO_AREA_496 0x08 #define FCMD_DATAPRO_AREA_480 0x0c #define FCMD_DATAPRO_AREA_448 0x10 #define FCMD_DATAPRO_AREA_384 0x14 +#define FCMD_DATAPRO_AREA_384_TH 0x0008 +#define FCMD_DATAPRO_AREA_384_TH_CMP 0x4000 #define FCMD_DATAPRO_AREA_256 0x18 #define FCMD_DATAPRO_AREA_512 0x1c +#define FCMD_DATAPRO_AREA_512_TH 0x0000 + + #define FCMD_DATAPRO_NONE_BIT 0x00 #define FCMD_DATAPRO_504_BIT 0x04 @@ -107,6 +137,8 @@ extern "C" { #define FCMD_DATAPRO_512_BIT 0x1c + + #define FLASH_STATUS_REGISTER_LEN 1 #define XFRD_FCMD_WREN 0x6000001 @@ -116,7 +148,14 @@ extern "C" { #define FLASH_WP_LOW_LEVEL (AP_SPIF->config |= (1<<14)) #define FLASH_WP_LEVEL_GET (0x4000-(AP_SPIF->config & (1<<14))) +#define FLASH_GD_ID 0xc8 +#define FLASH_XTX_ID 0x0b +#define FLASH_TH_ID 0xcd + + + extern uint8_t spif_flash_status_reg_1(void); +extern int spif_read_id(uint32_t* pid); extern void spif_wrdata(uint8_t* data, uint8_t len); __attribute__((section(".__sram.code"))) void hal_cache_tag_flush(void); diff --git a/misc/rom_sym_def.h b/misc/rom_sym_def.h index 2cc7539..0e106ac 100644 --- a/misc/rom_sym_def.h +++ b/misc/rom_sym_def.h @@ -42,6 +42,7 @@ #define conn_param _symrom_conn_param #define connUpdateTimer _symrom_connUpdateTimer #define counter_tracking _symrom_counter_tracking +#define g_llScanMode _symrom_g_llScanMode #define crc16_rom _symrom_crc16 #define ctrlToHostEnable _symrom_ctrlToHostEnable #define dataPkt _symrom_dataPkt @@ -875,6 +876,7 @@ #define spif_set_deep_sleep _symrom_spif_set_deep_sleep #define spif_wrdata _symrom_spif_wrdata #define spif_write _symrom_spif_write +#define spif_read_id _symrom_spif_read_id #define spif_write_protect _symrom_spif_write_protect #define sram_ret_patch _symrom_sram_ret_patch #define supportedCmdsTable _symrom_supportedCmdsTable @@ -919,6 +921,7 @@ #define llProcessSlaveControlPacket0 _symrom_llProcessSlaveControlPacket0 #define llProcessMasterControlPacket0 _symrom_llProcessMasterControlPacket0 #define LL_slave_conn_event0 _symrom_LL_slave_conn_event0 +#define LL_SetScanParam0 _symrom_LL_SetScanParam0 #endif #endif diff --git a/pm.c b/pm.c index 235c256..2483d07 100644 --- a/pm.c +++ b/pm.c @@ -34,6 +34,7 @@ #define MIN_TIME_TO_SLEEP 50 //ms #define MIN_TIME_TO_SUSPEND 10000 //ms + extern int g_spif_ref_clk; //pwrmgr_attribute_t pwrmgr_attribute; extern uint32_t ll_remain_time; @@ -371,7 +372,7 @@ void enterSleepProcess1(uint32_t time) if (pGlobal_config[LL_SWITCH] & RC32_TRACKINK_ALLOW) { // 1. read RC 32KHz tracking counter, calculate 16MHz ticks number per RC32KHz cycle - temp = *(volatile uint32_t *)0x4000f064 & 0x1ffff; + temp = AP_PCRM->cal_ro1 & 0x1ffff; //====== assume the error cnt is (n+1/2) cycle,for this case, it should be 9 or 10 // error_delt = (temp>STD_CRY32_8_CYCLE_16MHZ_CYCLE) @@ -722,13 +723,16 @@ void sram_reset_handler(void) g_system_reset_cause |=0x80; //check just_sleep_reset flg - if((((*(volatile uint32_t*)0x4000f0c4) & 0x0f)>>2)) + if(((AP_AON->SLEEP_R[1] & 0x0f)>>2)) g_system_reset_cause |=0x40; Reset_Handler(); } void just_enter_sleep(uint32 time) { + if (time < MIN_TIME_TO_SLEEP) + time = MIN_TIME_TO_SLEEP; + jump_area_init(); JUMP_FUNCTION(WAKEUP_PROCESS) = (uint32_t)sram_reset_handler; @@ -739,7 +743,7 @@ void just_enter_sleep(uint32 time) subWriteReg(&(AP_AON->PMCTL2_0),6,6,0x00); //disable software control // config wakeup timer - uint32_t sleep_tick_now = *(volatile uint32_t *) 0x4000f028; + uint32_t sleep_tick_now = AP_AON->RTCCNT; WaitRTCCount(1); AP_AON->RTCCC0 = sleep_tick_now + time; AP_AON->RTCCTL |= BIT(15)|BIT(18)|BIT(20); @@ -751,6 +755,9 @@ void just_enter_sleep(uint32 time) config reset casue as RSTC_WARM_NDWC reset path walkaround dwc */ + if (((AP_AON->SLEEP_R[1] & 0xFF00) >>8) > 100) + AP_AON->SLEEP_R[1]=0; + AP_AON->SLEEP_R[0]=4; // trigger system sleep @@ -769,7 +776,7 @@ void check_hclk_by_rc32k_rtc(void) uint32_t t1 = read_current_fine_time(); if((TIME_DELTA(t1,t0)RTC_32KRC_3_CYCLE_LIMIT_HIGH)) { - subWriteReg(0x4000f03c, 2, 0, 0); //switch hclk to RC32M + subWriteReg(&(AP_PCRM->CLKSEL), 2, 0, 0); //switch hclk to RC32M just_enter_sleep(33000); } @@ -785,7 +792,7 @@ void check_16MXtal_by_rcTracking(void) for fiset wakeupini, not do rcCal, just skip the rcTacking */ - if(((*(volatile uint32_t*)0x4000f0c4) & 0x80) == 0) + if((AP_AON->SLEEP_R[1] & 0x80) == 0) { WaitRTCCount(60); return; @@ -798,19 +805,19 @@ void check_16MXtal_by_rcTracking(void) uint32_t temp_min,temp_max; // ======== enable tracking 32KHz RC timer with 16MHz crystal clock - temp = *(volatile uint32_t *)0x4000f040; - *(volatile uint32_t *)0x4000f040 = temp | BIT(18); - temp = *(volatile uint32_t *)0x4000f05C; - *(volatile uint32_t *)0x4000f05C = (temp & 0xfffefe00) | 0x0028; + temp = AP_PCRM->CLKHF_CTL0; + AP_PCRM->CLKHF_CTL0 = temp | BIT(18); + temp = AP_PCRM->cal_rw; + AP_PCRM->cal_rw = (temp & 0xfffefe00) | 0x0028; WaitRTCCount(3); - temp31 = (*(volatile uint32_t *)0x4000f064 & 0x1ffff); + temp31 = (AP_PCRM->cal_ro1 & 0x1ffff); WaitRTCCount(3); - temp32 = (*(volatile uint32_t *)0x4000f064 & 0x1ffff); + temp32 = (AP_PCRM->cal_ro1 & 0x1ffff); WaitRTCCount(3); - temp33 = (*(volatile uint32_t *)0x4000f064 & 0x1ffff); + temp33 = (AP_PCRM->cal_ro1 & 0x1ffff); while(1) { @@ -828,27 +835,27 @@ void check_16MXtal_by_rcTracking(void) (temp_max-temp_min)SLEEP_R[1]),3,2,0); //reset tracking sleep num - subWriteReg(0x4000f0c4,15,8,0); + subWriteReg(&(AP_AON->SLEEP_R[1]),15,8,0); break; } temp31= temp32; temp32 = temp33; WaitRTCCount(3); - temp33 = (*(volatile uint32_t *)0x4000f064 & 0x1ffff); + temp33 = (AP_PCRM->cal_ro1 & 0x1ffff); //check tracking cost uint32_t tracking_end = rtc_get_counter(); uint32_t tracking_16M_tick = (tracking_end>=tracking_start) ? (tracking_end-tracking_start) : (0xffffffff-tracking_start+tracking_end); if(tracking_16M_tick >= TRACKING_16M_TICK_MAX) { - uint32_t tracking_sleep_num = (*(volatile uint32_t*)0x4000f0c4 & 0xFF00) >>8; - subWriteReg(0x4000f0c4,15,8,tracking_sleep_num+1); - subWriteReg(0x4000f0c4,3,2,1); - if ((1 << tracking_sleep_num)*33000< TRACKING_MAX_SLEEPTIME) + uint32_t tracking_sleep_num = (AP_AON->SLEEP_R[1] & 0xFF00) >>8; + subWriteReg(&(AP_AON->SLEEP_R[1]),15,8,tracking_sleep_num+1); + subWriteReg(&(AP_AON->SLEEP_R[1]),3,2,1); + if ((uint32_t)((uint32_t)1 << tracking_sleep_num)*33000 < TRACKING_MAX_SLEEPTIME) { just_enter_sleep((1 << tracking_sleep_num)*33000); } @@ -860,9 +867,9 @@ void check_16MXtal_by_rcTracking(void) } - temp1 = (*(volatile uint32_t *)0x4000f064 & 0x1ffff); + temp1 = (AP_PCRM->cal_ro1 & 0x1ffff); - subWriteReg(0x4000f05C,3,3,0); + subWriteReg(&(AP_PCRM->cal_rw),3,3,0); g_xtal16M_tmp = temp1; } @@ -872,11 +879,11 @@ void check_96MXtal_by_rcTracking(void) uint32_t temp,temp1; //for first wakeupinit - if(((*(volatile uint32_t*)0x4000f0c4) & 0x80) == 0) + if((AP_AON->SLEEP_R[1] & 0x80) == 0) { //enable DLL - temp = *(volatile uint32_t *)0x4000f044; - *(volatile uint32_t *)0x4000f044 = temp | BIT(7); + temp = AP_PCRM->CLKHF_CTL1; + AP_PCRM->CLKHF_CTL1 = temp | BIT(7); WaitRTCCount(3); return; } @@ -884,64 +891,64 @@ void check_96MXtal_by_rcTracking(void) DLL_enable_num=0; // ======== enable tracking 32KHz RC timer with 16MHz crystal clock - temp = *(volatile uint32_t *)0x4000f040; - *(volatile uint32_t *)0x4000f040 = temp | BIT(18); + temp = AP_PCRM->CLKHF_CTL0; + AP_PCRM->CLKHF_CTL0 = temp | BIT(18); while(1) { //enable DLL - temp = *(volatile uint32_t *)0x4000f044; - *(volatile uint32_t *)0x4000f044 = temp | BIT(7); + temp = AP_PCRM->CLKHF_CTL1; + AP_PCRM->CLKHF_CTL1 = temp | BIT(7); WaitRTCCount(3); DLL_enable_num++; // //enable digclk 96M - temp = *(volatile uint32_t *)0x4000f044; - *(volatile uint32_t *)0x4000f044 = temp | BIT(16); + temp = AP_PCRM->CLKHF_CTL1; + AP_PCRM->CLKHF_CTL1 = temp | BIT(16); for(uint8 index=0;index<5;index++) { - temp = *(volatile uint32_t *)0x4000f05C; - *(volatile uint32_t *)0x4000f05C = (temp & 0xfffefe00) | 0x0028 | BIT(16); + temp = AP_PCRM->cal_rw; + AP_PCRM->cal_rw = (temp & 0xfffefe00) | 0x0028 | BIT(16); WaitRTCCount(3); - temp1 = (*(volatile uint32_t *)0x4000f064 & 0x1ffff); - subWriteReg(0x4000f05C,3,3,0); + temp1 = (AP_PCRM->cal_ro1 & 0x1ffff); + subWriteReg(&(AP_PCRM->cal_rw),3,3,0); if( (g_xtal16M_tmp*6 >=temp1 ? (g_xtal16M_tmp*6 -temp1):(temp1-g_xtal16M_tmp*6))cal_rw),16,16,0); + subWriteReg(&(AP_PCRM->CLKHF_CTL1),16,16,0); g_xtal96M_temp = temp1; - subWriteReg(0x4000f0c4,5,4,0); + subWriteReg(&(AP_AON->SLEEP_R[1]),5,4,0); return; } } //disable 96M - subWriteReg(0x4000f05C,16,16,0); - subWriteReg(0x4000f044,16,16,0); + subWriteReg(&(AP_PCRM->cal_rw),16,16,0); + subWriteReg(&(AP_PCRM->CLKHF_CTL1),16,16,0); //should not be here if(DLL_enable_num>= DLL_ENABLE_MAX) { - subWriteReg(0x4000f0c4,5,4,1); + subWriteReg(&(AP_AON->SLEEP_R[1]),5,4,1); just_enter_sleep(60); } //disable DLL - subWriteReg(0x4000f044,7,7,0); + subWriteReg(&(AP_PCRM->CLKHF_CTL1),7,7,0); WaitRTCCount(3); //update g_xtal16M_tmp - temp = *(volatile uint32_t *)0x4000f05C; - *(volatile uint32_t *)0x4000f05C = (temp & 0xfffefe00) | 0x0028 ; + temp = AP_PCRM->cal_rw; + AP_PCRM->cal_rw = (temp & 0xfffefe00) | 0x0028 ; WaitRTCCount(3); - g_xtal16M_tmp = (*(volatile uint32_t *)0x4000f064 & 0x1ffff); + g_xtal16M_tmp = (AP_PCRM->cal_ro1 & 0x1ffff); - subWriteReg(0x4000f05C,3,3,0); + subWriteReg(&(AP_PCRM->cal_rw),3,3,0); } } @@ -969,12 +976,12 @@ void wakeup_init1() { uint32_t tracking_c1,tracking_c2; tracking_c1 = rtc_get_counter(); WaitRTCCount(30); - subWriteReg(0x4000f0c4,1,0,0); + subWriteReg(&(AP_AON->SLEEP_R[1]),1,0,0); check_16MXtal_by_rcTracking(); WaitRTCCount(6); - subWriteReg(0x4000f0c4,1,0,1); + subWriteReg(&(AP_AON->SLEEP_R[1]),1,0,1); check_96MXtal_by_rcTracking(); - subWriteReg(0x4000f0c4,1,0,2); + subWriteReg(&(AP_AON->SLEEP_R[1]),1,0,2); tracking_c2 = rtc_get_counter(); tracking_cnt = (tracking_c2>=tracking_c1) ? (tracking_c2-tracking_c1) : (0xffffffff-tracking_c1+tracking_c2); pGlobal_config[WAKEUP_ADVANCE] =1500+30*tracking_cnt; @@ -986,7 +993,7 @@ void wakeup_init1() { *(volatile uint32_t *) 0x400300a4 = 0x140; //[6] for tpm_en clk_init(g_system_clk); - subWriteReg(0x4000f0c4,1,0,3); + subWriteReg(&(AP_AON->SLEEP_R[1]),1,0,3); hal_wakeup_irq_config(); // ========== init timers @@ -1010,8 +1017,8 @@ void wakeup_init1() { ll_hw_ign_rfifo(LL_HW_IGN_SSN | LL_HW_IGN_CRC | LL_HW_IGN_EMP); // ======== enable tracking 32KHz RC timer with 16MHz crystal clock - temp = *(volatile uint32_t *)0x4000f05C; - *(volatile uint32_t *)0x4000f05C = (temp & 0xfffefe00) | 0x0108; //[16] 16M [8:4] cnt [3] track_en_rc32k + temp = AP_PCRM->cal_rw; + AP_PCRM->cal_rw = (temp & 0xfffefe00) | 0x0108; //[16] 16M [8:4] cnt [3] track_en_rc32k } static void hw_spif_cache_config(void) { diff --git a/reboot.c b/reboot.c index f25fcb6..3c2a4bb 100644 --- a/reboot.c +++ b/reboot.c @@ -55,7 +55,8 @@ __attribute__((section(".__sram.code"))) void drv_reboot(int cmd) reset path walkaround dwc */ AP_AON->SLEEP_R[0]=4; - + + AP_AON->SLEEP_R[1]=0; *(volatile uint32_t *) 0x40000004 = 0x00; diff --git a/system.c b/system.c index a13011a..d99e7fa 100644 --- a/system.c +++ b/system.c @@ -299,7 +299,8 @@ void SystemInit(void) //replace TS_PEND IRQ with IRQ0 drv_irq_enable(0); - csi_vic_set_prio(0, 3); + csi_vic_set_prio(0, 3); + spif_read_id(NULL); hal_cache_init(); hal_mpu_config(); -- Gitee