initial commit

This commit is contained in:
2024-12-15 00:34:01 +06:00
commit 31efbc726f
1576 changed files with 657692 additions and 0 deletions

View File

@@ -0,0 +1,61 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_PERIPHERALNAMES_H
#define MBED_PERIPHERALNAMES_H
#include "cmsis.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
UART_0 = (int)UART0_DEV,
UART_1 = (int)UART1_DEV,
UART_2 = (int)UART2_DEV,
} UARTName;
typedef enum {
ADC0_0 = 0,
ADC0_1,
ADC0_2,
ADC0_3
} ADCName;
typedef enum {
SPI_0 = (int)SPI0_DEV,
SPI_1 = (int)SPI1_DEV,
} SPIName;
typedef enum {
I2C_0 = (int)I2C0_DEV,
I2C_1 = (int)I2C1_DEV,
} I2CName;
typedef enum {
PWM_0 = 1,
PWM_1,
PWM_2,
PWM_3,
PWM_4,
PWM_5
} PWMName;
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,92 @@
#ifndef _PINNAMES_H_
#define _PINNAMES_H_
#include "cmsis.h"
#ifdef __cplusplus
extern "C" {
#endif
#define PIN_DATA(PUPD, FUNC) (((PUPD) << 6) | (FUNC))
#define PIN_PIN_PUPD(X) ((X) & 0x03) /* PullNone/PullUp/PullDown */
#define PIN_FUNC(X) ((X) & 0x0F) /* PINMUX_FUNCTION_XXXX */
typedef enum {
PORT_A = 0,
PORT_B = 1,
} GPIO_PORT;
typedef enum {
PIN_INPUT=0,
PIN_OUTPUT
} PinDirection;
/* (((port)<<5)|(pin)) */
typedef enum {
PA_0 = (PORT_A<<5|0),
PA_1 = (PORT_A<<5|1),
PA_2 = (PORT_A<<5|2),
PA_3 = (PORT_A<<5|3),
PA_4 = (PORT_A<<5|4),
PA_5 = (PORT_A<<5|5),
PA_6 = (PORT_A<<5|6),
PA_7 = (PORT_A<<5|7),
PA_8 = (PORT_A<<5|8),
PA_9 = (PORT_A<<5|9),
PA_10 = (PORT_A<<5|10),
PA_11 = (PORT_A<<5|11),
PA_12 = (PORT_A<<5|12),
PA_13 = (PORT_A<<5|13),
PA_14 = (PORT_A<<5|14),
PA_15 = (PORT_A<<5|15),
PA_16 = (PORT_A<<5|16),
PA_17 = (PORT_A<<5|17),
PA_18 = (PORT_A<<5|18),
PA_19 = (PORT_A<<5|19),
PA_20 = (PORT_A<<5|20),
PA_21 = (PORT_A<<5|21),
PA_22 = (PORT_A<<5|22),
PA_23 = (PORT_A<<5|23),
PA_24 = (PORT_A<<5|24),
PA_25 = (PORT_A<<5|25),
PA_26 = (PORT_A<<5|26),
PA_27 = (PORT_A<<5|27),
PA_28 = (PORT_A<<5|28),
PA_29 = (PORT_A<<5|29),
PA_30 = (PORT_A<<5|30),
PA_31 = (PORT_A<<5|31),
PB_0 = (PORT_B<<5|0),
PB_1 = (PORT_B<<5|1),
PB_2 = (PORT_B<<5|2),
PB_3 = (PORT_B<<5|3),
PB_4 = (PORT_B<<5|4),
PB_5 = (PORT_B<<5|5),
PB_6 = (PORT_B<<5|6),
PB_7 = (PORT_B<<5|7),
PB_8 = (PORT_B<<5|8),
VBAT_MEAS = (0x7<<5|2),
AD_1 = PA_19, //CH1
AD_2 = VBAT_MEAS, //CH2
AD_3 = PA_20, //CH3
// Not connected
NC = (uint32_t)0xFFFFFFFF
} PinName;
typedef enum {
PullNone = 0, //IN HIGHZ
PullUp = 1,
PullDown = 2,
PullDefault = PullNone
} PinMode;
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,31 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_PORTNAMES_H
#define MBED_PORTNAMES_H
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
PortA = 0,
PortB = 1,
} PortName;
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,197 @@
/** mbed Microcontroller Library
******************************************************************************
* @file analogin_api.c
* @author
* @version V1.0.0
* @date 2016-08-01
* @brief This file provides mbed API for ADC.
******************************************************************************
* @attention
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
******************************************************************************
*/
#include "objects.h"
#include "PinNames.h"
#include "analogin_api.h"
#include "pinmap.h"
static ADC_InitTypeDef AdcInitStruct;
extern u32 ConfigDebugErr;
extern u32 ConfigDebuginfo;
typedef enum {
ADC_CH0 = 0,
ADC_CH1 = 1,
ADC_CH2 = 2,
ADC_CH3 = 3,
} ADC_CH;
static const PinMap PinMap_ADC[] = {
{PA_19, ADC_CH1, 0},
{VBAT_MEAS, ADC_CH2, 0},
{PA_20, ADC_CH3, 0},
{NC, NC, 0}
};
/**
* @brief Read 8 bytes data from ADC.
* @param pBuf: 8 bytes buffer for data read.
* @note poll mode will be used in this function.
* @retval None
*/
void ADC_ReceiveBuf_ACUT(u32 *pBuf)
{
u32 isr = ADC_GetISR();
ADC_TypeDef *adc = ADC;
u32 AdcTempDat;
/* Clear ADC Status */
ADC_INTClear();
ADC_INTConfig(BIT_ADC_FIFO_FULL_EN|BIT_ADC_FIFO_RD_REQ_EN, ENABLE);
ADC_Cmd(ENABLE);
/* B CUT ADD patch for reset fail */
AdcTempDat = adc->ANAPAR_AD1;
AdcTempDat |= BIT(0);
adc->ANAPAR_AD1 = AdcTempDat;
while (1) {
isr = ADC_GetISR();
if (isr & (BIT_ADC_FIFO_FULL | BIT_ADC_FIFO_RD_REQ)) {
*pBuf = (u32)ADC_Read_RAM();
*(pBuf+1)= (u32)ADC_Read_RAM();
ADC_INTClear();
ADC_INTConfig(BIT_ADC_FIFO_FULL_EN|BIT_ADC_FIFO_RD_REQ_EN, DISABLE);
break;
}
}
/* B CUT ADD patch for reset fail */
AdcTempDat = adc->ANAPAR_AD1;
AdcTempDat &= ~BIT(0);
adc->ANAPAR_AD1 = AdcTempDat;
ADC_Cmd(DISABLE);
/* Clear ADC Status */
ADC_INTClear();
}
/**
* @brief Initializes the ADC device, include clock/function/ADC registers.
* @param obj: adc object define in application software.
* @param pin: adc PinName according to pinmux spec.
* @retval none
*/
void analogin_init(analogin_t *obj, PinName pin)
{
uint32_t adc_idx;
ConfigDebugErr &= (~(_DBG_ADC_|_DBG_GDMA_));
ConfigDebugInfo&= (~(_DBG_ADC_|_DBG_GDMA_));
adc_idx = pinmap_peripheral(pin, PinMap_ADC);
DBG_8195A("analogin_init [%x:%x ]\n", pin, adc_idx);
assert_param(adc_idx != NC);
/* Set ADC Device Number */
obj->adc_idx = adc_idx;
/* Load ADC default value */
ADC_InitStruct(&AdcInitStruct);
ADC_AnaparAd[1] = 0x81004;
/* Init ADC now */
/* ADC Interrupt disable, poll mode will be used */
InterruptDis(ADC_IRQ);
/* To release ADC delta sigma clock gating */
PLL2_Set(BIT_SYS_SYSPLL_CK_ADC_EN, ENABLE);
/* Turn on ADC active clock */
RCC_PeriphClockCmd(APBPeriph_ADC, APBPeriph_ADC_CLOCK, ENABLE);
ADC_Init(&AdcInitStruct);
}
/**
* @brief Reads data from the specified adc channel fifo.
* @param obj: adc object define in application software.
* @retval adc channel data(float)
*/
float analogin_read(analogin_t *obj)
{
float value;
uint32_t AnaloginTmp[2] = {0,0};
uint32_t AnaloginDatMsk = 0xFFFF;
uint8_t AnaloginIdx = obj->adc_idx;
uint32_t AnalogDat = 0;
uint32_t AnalogDatFull = 0;
ADC_ReceiveBuf_ACUT(&AnaloginTmp[0]);
AnaloginDatMsk = (u32)(AnaloginDatMsk<<((u32)(16*(AnaloginIdx&0x01))));
AnalogDat = AnaloginTmp[(AnaloginIdx/2)];
AnalogDat = (AnalogDat & AnaloginDatMsk);
AnalogDat = (AnalogDat>>((u32)(16*(AnaloginIdx&0x01))));
AnalogDatFull = 0xCE80;
value = (float)(AnalogDat) / (float)(AnalogDatFull);
return (float)value;
}
/**
* @brief Reads data from the specified adc channel fifo.
* @param obj: adc object define in application software.
* @retval 16bit adc channel data(int)
*/
uint16_t analogin_read_u16(analogin_t *obj)
{
uint32_t AnaloginTmp[2] = {0,0};
uint32_t AnaloginDatMsk = 0xFFFF;
uint8_t AnaloginIdx = obj->adc_idx;
uint32_t AnalogDat = 0;
ADC_ReceiveBuf_ACUT(&AnaloginTmp[0]);
//DBG_8195A("[0]:%08x, %08x\n", AnaloginTmp[0], AnaloginTmp[1] );
AnaloginDatMsk = (u32)(AnaloginDatMsk<<((u32)(16*(AnaloginIdx&0x01))));
AnalogDat = AnaloginTmp[(AnaloginIdx/2)];
AnalogDat = (AnalogDat & AnaloginDatMsk);
AnalogDat = (AnalogDat>>((u32)(16*(AnaloginIdx&0x01))));
return (uint16_t)AnalogDat;
}
/**
* @brief Deinitializes the ADC device, include clock/function/ADC registers.
* @param obj: adc object define in application software.
* @retval none
*/
void analogin_deinit(analogin_t *obj)
{
/* Clear ADC Status */
ADC_INTClear();
/* Disable ADC */
ADC_Cmd(DISABLE);
/* To release ADC delta sigma clock gating */
PLL2_Set(BIT_SYS_SYSPLL_CK_ADC_EN, DISABLE);
/* Turn on ADC active clock */
RCC_PeriphClockCmd(APBPeriph_ADC, APBPeriph_ADC_CLOCK, DISABLE);
}
/******************* (C) COPYRIGHT 2016 Realtek Semiconductor *****END OF FILE****/

View File

@@ -0,0 +1,48 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_DEVICE_H
#define MBED_DEVICE_H
#define DEVICE_PORTIN 1
#define DEVICE_PORTOUT 1
#define DEVICE_PORTINOUT 1
#define DEVICE_INTERRUPTIN 1
#define DEVICE_ANALOGIN 1
#define DEVICE_ANALOGOUT 0
#define DEVICE_SERIAL 1
#define DEVICE_I2C 1
#define DEVICE_I2CSLAVE 1
#define DEVICE_SPI 1
#define DEVICE_SPISLAVE 1
#define DEVICE_CAN 0
#define DEVICE_RTC 1
#define DEVICE_ETHERNET 0
#define DEVICE_PWMOUT 1
#define DEVICE_SLEEP 1
#include "objects.h"
#endif

View File

@@ -0,0 +1,111 @@
/** mbed Microcontroller Library
******************************************************************************
* @file sys_api.c
* @author
* @version V1.0.0
* @date 2016-08-01
* @brief This file provides mbed GDMA API for memcopy
******************************************************************************
* @attention
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
******************************************************************************
*/
#include "dma_api.h"
#include "cmsis.h"
static void dma_memcpy_int(void *pData)
{
gdma_t *dma_obj = (gdma_t *)pData;
/* Clean Auto Reload Bit */
GDMA_ChCleanAutoReload(dma_obj->index, dma_obj->ch_num, CLEAN_RELOAD_DST);
/* Clear Pending ISR */
GDMA_ClearINT(dma_obj->index, dma_obj->ch_num);
GDMA_Cmd(dma_obj->index, dma_obj->ch_num, DISABLE);
if (dma_obj->user_cb != NULL) {
dma_obj->user_cb((VOID*)dma_obj->user_cb_data);
}
}
/**
* @brief Initial the GDMA
* @param dma_obj: the GDMA object
* @param handler: the callback function for a DMA transfer complete.
* @param id: the argument of the callback function.
* @return None
*
*/
void dma_memcpy_init(gdma_t *dma_obj, dma_irq_handler handler, uint32_t id)
{
u8 ch_num;
dma_obj->index = 1;
ch_num = GDMA_ChnlAlloc(dma_obj->index, (IRQ_FUN) dma_memcpy_int, (u32)dma_obj, 10);
if (0xFF == ch_num) {
DBG_8195A("%s: Cannot allocate a GDMA Channel\n", __FUNCTION__);
return;
}
dma_obj->user_cb = (IRQ_FUN)handler;
dma_obj->user_cb_data = id;
dma_obj->ch_num = ch_num;
}
/**
* @brief De-Initial the GDMA
* @param dma_obj: the GDMA object
* @return None
*
*/
void dma_memcpy_deinit(gdma_t *dma_obj)
{
GDMA_ChnlFree(dma_obj->index, dma_obj->ch_num);
}
/**
* @brief To do a memory copy by DMA
* @param None
* @return None
*
*/
void dma_memcpy(gdma_t *dma_obj, void *dst, void* src, uint32_t len)
{
GDMA_InitTypeDef GDMA_InitStruct;
_memset((void *)&GDMA_InitStruct, 0, sizeof(GDMA_InitTypeDef));
GDMA_InitStruct.GDMA_ChNum = dma_obj->ch_num;
GDMA_InitStruct.GDMA_Index = dma_obj->index;
GDMA_InitStruct.GDMA_IsrType = (TransferType|ErrType);
DBG_PRINTF(MODULE_GDMA, LEVEL_INFO, "%s: ==> Src=0x%x Dst=0x%x Len=%d\r\n", __FUNCTION__, src, dst, len);
if ((((u32)src & 0x03)==0) && (((u32)dst & 0x03)==0) && ((len & 0x03)== 0)) {
/* 4-bytes aligned, move 4 bytes each transfer */
GDMA_InitStruct.GDMA_SrcMsize = MsizeEight;
GDMA_InitStruct.GDMA_SrcDataWidth = TrWidthFourBytes;
GDMA_InitStruct.GDMA_DstMsize = MsizeEight;
GDMA_InitStruct.GDMA_DstDataWidth = TrWidthFourBytes;
GDMA_InitStruct.GDMA_BlockSize = len >> 2;
} else {
GDMA_InitStruct.GDMA_SrcMsize = MsizeEight;
GDMA_InitStruct.GDMA_SrcDataWidth = TrWidthOneByte;
GDMA_InitStruct.GDMA_DstMsize = MsizeEight;
GDMA_InitStruct.GDMA_DstDataWidth = TrWidthOneByte;
GDMA_InitStruct.GDMA_BlockSize = len;
}
GDMA_InitStruct.GDMA_SrcAddr = (u32)src;
GDMA_InitStruct.GDMA_DstAddr = (u32)dst;
GDMA_Init(dma_obj->index, dma_obj->ch_num, &GDMA_InitStruct);
GDMA_Cmd(dma_obj->index, dma_obj->ch_num, ENABLE);
}
/******************* (C) COPYRIGHT 2016 Realtek Semiconductor *****END OF FILE****/

View File

@@ -0,0 +1,515 @@
/** mbed Microcontroller Library
******************************************************************************
* @file efuse_api.c
* @author
* @version V1.0.0
* @date 2016-08-01
* @brief This file provides mbed API for EFUSE.
******************************************************************************
* @attention
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
******************************************************************************
*/
#include "ameba_soc.h"
#include "rtl8711b_efuse.h"
#include "rom_aes.h"
//#ifdef CONFIG_EFUSE_EN
typedef union
{ unsigned int l;
unsigned char b[4];
} aes_inf;
typedef struct
{
aes_context ctx;
aes_inf inf;
} aes_encrypt_ctx;
#define RDP_KEY_CHECK_TIMES (3)
/*plaintext image*/
static u8 rdp_bin_test_plaintext[16]= {0x08,0x18,0x70,0x47,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
/*encrypt image buffer*/
static u8 rdp_bin_test_enc[16] = {0};
/*checksum*/
static u32 rdp_bin_checksum = 0;
/*RDP key*/
static u8 * RDP_key = NULL;
static u32 EFUSE_OTP_Check(u16 Addr, u8 Data)
{
u8 L25OutVoltage = L25EOUTVOLTAGE;
u32 CtrlSetting = HAL_READ32(SYSTEM_CTRL_BASE, REG_SYS_EFUSE_CTRL);
u32 bResult = _SUCCESS;
u8 temp = 0xFF;
EFUSE_WRITE_Check_ACUT(ENABLE);
if ((Addr >= (OTP_SECTION)) && (Addr < (OTP_SECTION + OTP_SECTION_LEN))){
EFUSE_OneByteRead_ACUT(CtrlSetting, Addr, &temp, L25OutVoltage);
if (temp == 0xff) {
bResult = EFUSE_OneByteWriteROM(CtrlSetting, Addr, Data, L25OutVoltage);
if (bResult == _SUCCESS){
EFUSE_OneByteRead_ACUT(CtrlSetting, Addr, &temp, L25OutVoltage);
if (temp != Data){
EFUSE_OneByteWriteROM(CtrlSetting, Addr, Data, L25OutVoltage);
EFUSE_OneByteRead_ACUT(CtrlSetting, Addr, &temp, L25OutVoltage);
if (temp != Data){
bResult = _FAIL;
}
}
}
} else {
if (temp != Data){
EFUSE_OneByteWriteROM(CtrlSetting, Addr, Data, L25OutVoltage);
EFUSE_OneByteRead_ACUT(CtrlSetting, Addr, &temp, L25OutVoltage);
if (temp != Data){
bResult = _FAIL;
}
}
}
}
EFUSE_WRITE_Check_ACUT(DISABLE);
return bResult;
}
/**
* @brief Get remaining efuse length
* @retval remaining efuse length
*/
int efuse_get_remaining_length(void)
{
return EFUSE_RemainLength();
}
/**
* @brief Read efuse contant of specified user
* @param data: Specified the address to save the readback data.
* @retval none
*/
void efuse_mtp_read(uint8_t * data)
{
EFUSE_USER1_Read(data);
return;
}
/**
* @brief Write user's contant to efuse
* @param data: Specified the data to be programmed.
* @param len: Specifies the data length of programmed data.
* @retval status value:
* - 0~32: Success
* - -1: Failure
*/
int efuse_mtp_write(uint8_t *data, uint8_t len)
{
u8 len_low, section_num, word_enable = 0;
u8 ret = 0;
if( (len & 0x01) == 1)
len += 1;
if(len > 32){
return -1;
}
if(len == 0){
return 0;
}
/* 8bytes one section */
len_low = len & 0x07;
section_num = (len >> 3) & 0x07;
if(len_low == 0)
word_enable = 0; /* 0 word write enable */
else if(len_low == 2)
word_enable = 1; /* 1 word write enable */
else if(len_low == 4)
word_enable = 3; /* 2 word write enable */
else if(len_low == 6)
word_enable = 7; /* 3 word write enable */
switch (section_num){
case 0:
ret = EFUSE_USER1_Write_ROM(0, word_enable, data); if (ret == _FAIL) return -1;
break;
case 1:
ret = EFUSE_USER1_Write_ROM(0, 0xf, data); if (ret == _FAIL) return -1;
ret = EFUSE_USER1_Write_ROM(1, word_enable, data+8); if (ret == _FAIL) return -1;
break;
case 2:
ret = EFUSE_USER1_Write_ROM(0, 0xf, data); if (ret == _FAIL) return -1;
ret = EFUSE_USER1_Write_ROM(1, 0xf, data+8); if (ret == _FAIL) return -1;
ret = EFUSE_USER1_Write_ROM(2, word_enable, data+16); if (ret == _FAIL) return -1;
break;
case 3:
ret = EFUSE_USER1_Write_ROM(0, 0xf, data); if (ret == _FAIL) return -1;
ret = EFUSE_USER1_Write_ROM(1, 0xf, data+8); if (ret == _FAIL) return -1;
ret = EFUSE_USER1_Write_ROM(2, 0xf, data+16); if (ret == _FAIL) return -1;
ret = EFUSE_USER1_Write_ROM(3, word_enable, data+24); if (ret == _FAIL) return -1;
break;
case 4:
ret = EFUSE_USER1_Write_ROM(0, 0xf, data); if (ret == _FAIL) return -1;
ret = EFUSE_USER1_Write_ROM(1, 0xf, data+8); if (ret == _FAIL) return -1;
ret = EFUSE_USER1_Write_ROM(2, 0xf, data+16); if (ret == _FAIL) return -1;
ret = EFUSE_USER1_Write_ROM(3, 0xf, data+24); if (ret == _FAIL) return -1;
}
return len;
}
/**
* @brief Read efuse OTP contant
* @param address: Specifies the offset of the OTP.
* @param len: Specifies the length of readback data.
* @param buf: Specified the address to save the readback data.
* @retval status value:
* - 0: Success
* - -1: Failure
*/
int efuse_otp_read(u8 address, u8 len, u8 *buf)
{
u8 content[32]; // the OTP max length is 32
if((address+len) > 32) {
return -1;
}
EFUSE_OTP_Read32B(content);
_memcpy(buf, content+address, len);
return 0;
}
/**
* @brief Write user's contant to OTP efuse
* @param address: Specifies the offset of the programmed OTP.
* @param len: Specifies the data length of programmed data.
* @param buf: Specified the data to be programmed.
* @retval status value:
* - 0: Success
* - -1: Failure
*/
int efuse_otp_write(u8 address, u8 len, u8 *buf)
{
u32 ret = 0;
u8 content[32]; // the OTP max length is 32
if((address+len) > 32) {
return -1;
}
_memset(content, 0xFF, 32);
_memcpy(content+address, buf, len);
ret = EFUSE_OTP_Write32B_ROM(content);
if (ret == _SUCCESS) {
return 0;
} else {
return -1;
}
}
/**
* @brief check user's contant to OTP efuse
* @param *buf: Specified the data to be programmed.
* @param len: Specifies the data length of programmed data.
* @retval status: Success:0 or Failure: -1.
*/
int efuse_otp_chk(u8 len, u8 *buf)
{
u8 content[32]; // the OTP max length is 32
u8 Idx = 0;
u32 bResult = _SUCCESS;
_memset(content, 0xFF, 32);
_memcpy(content, buf, len);
for (Idx = 0; Idx < OTP_SECTION_LEN; Idx++){
bResult = EFUSE_OTP_Check((OTP_SECTION+Idx), (*(content+Idx)));
if (bResult != _SUCCESS){
break;
}
}
return (bResult? 0 : -1);
}
/**
* @brief Disable jtag
* @retval status: Success:0.
*/
int efuse_disable_jtag(void)
{
u32 ret = 0;
ret = EFUSE_JTAG_OFF_ROM();
if (ret == _SUCCESS) {
return 0;
} else {
return -1;
}
}
/**
* @brief Set RDP Enable.
* @param none
* @note can not change or read back after write.
*/
void efuse_rdp_enable(void)
{
EFUSE_RDP_EN();
}
/**
* @brief Set 16B RDP key into EFUSE.
* @param rdp_key: 16B EFUSE KEY
* @note can not change or read back after write.
*/
void efuse_rdp_keyset(u8 *rdp_key)
{
EFUSE_RDP_KEY(rdp_key);
RDP_key = rdp_key;
}
/**
* @brief encypt rdp check image.
* @param SW_Key: key for encyption
* @note none
*/
void efuse_rdp_check_image_encrypt(u8* SW_Key)
{
int i;
aes_encrypt_ctx enc_ctx;
u8 * pByte;
pByte = (u8 *)&rdp_bin_checksum;
memset(&enc_ctx, 0, sizeof(enc_ctx));
/*calculate checksum using plaintext*/
for(i=0; i<4; i++) {
pByte[0] ^= rdp_bin_test_plaintext[i*4];
pByte[1] ^= rdp_bin_test_plaintext[i*4 + 1];
pByte[2] ^= rdp_bin_test_plaintext[i*4 + 2];
pByte[3] ^= rdp_bin_test_plaintext[i*4 + 3];
}
/*encrypt image*/
aes_init();
aes_encrypt_key(SW_Key, 128, &enc_ctx);
aes_ecb_encrypt(rdp_bin_test_plaintext, rdp_bin_test_enc, 16, &enc_ctx);
DBG_8195A("[%s] rdp_bin_checksum = %x\n", __func__, rdp_bin_checksum);
}
/**
* @brief check RDP key.
* @param SW_key: 16B EFUSE SW-KEY
* @note only after calling API "efuse_rdp_enable()" and "efuse_rdp_keyset()" can this API be called.
*/
void efuse_rdp_check(u8* SW_key)
{
u32 temp = 0;
u32 ret = TRUE;
SYSTEM_DATA* pSysData = (SYSTEM_DATA*)(SPI_FLASH_BASE + FLASH_SYSTEM_DATA_ADDR);
u32 RDPFlashAddr = pSysData->RDP_FlashAddr;
u32 RDPLen = pSysData->RDP_Len;
u32 checksum_ipsec, checksum_rdp_flash;
u8 aes_ecb_key_dummy[16]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
u8 *rdp_bin_data_en = (u8*)((u32)__rom_top_4k_start_ - 16 * 1024);
u32 PollTimes;
u32 RdpEnable = 0;
u32 WriteKeyState = 0;
u32 RDP_ERR_Flag = 0;
EFUSE_WRITE_CHECK(ENABLE);
/*check RDP enable bit*/
for(PollTimes = 0; PollTimes < RDP_KEY_CHECK_TIMES; PollTimes++) {
/* load RDP EN from efuse */
ret = RDP_EN_Request();
if (ret == FALSE) {
DBG_8195A("BIT_RDP_EN_LOAD timeout.\n");
RDP_ERR_Flag = RDP_KEY_REQUEST_TIMEOUT;
goto exit;
}
temp = HAL_READ32(SYSTEM_CTRL_BASE, REG_FW_PPROTECT_KEY_CTRL);
if (temp & BIT_RDP_EN) {
RdpEnable = 1;
DBG_8195A("[%s] PG RDP enable bit ok: %d\n", __func__, PollTimes);
break;
} else {
EFUSE_RDP_EN();
DBG_8195A("[%s] PG RDP enable bit again: %d\n", __func__, PollTimes);
}
}
if(RdpEnable == 0) {
DBG_8195A("PG RDP enable bit fail!\n");
goto exit;
}
/*if software key is not NULL, use the encrypt firmware in ram to check the RDP-key; if NULL,
use the 4kB encrypt firmare burnt in flash to check the RDP-key*/
if(SW_key != NULL) {
efuse_rdp_check_image_encrypt(SW_key);
RDPFlashAddr = (u32)&rdp_bin_test_enc ;
RDPLen = 16;
checksum_rdp_flash = rdp_bin_checksum;
DBG_8195A("software key is valid, use firmware in ram to check RDP-key!\n");
} else {
checksum_rdp_flash = HAL_READ32(RDPFlashAddr, RDPLen);
DBG_8195A("software key is not NULL, use the 4KB firmware in flash to check RDP-key!\n");
}
if(RDP_key == NULL) {
DBG_8195A("[%s]: RDP key is NULL\n", __func__);
goto exit;
}
/*if RDP enable, check the RDP key*/
if (RdpEnable) {
for(PollTimes = 0; PollTimes < RDP_KEY_CHECK_TIMES; PollTimes++) {
DBG_8195A("BOOT_FLASH_RDP RDP enable \n");
/* enable the key request from efuse */
KEY_Request(BIT_RDP_KEY_REQ);
/* read encrypted rdp code and data from flash or ram*/
_memcpy(rdp_bin_data_en, (const void*)RDPFlashAddr, RDPLen);
if(0xFFFFFFFF == *((u32*)rdp_bin_data_en)) {
DBG_8195A("RDP.bin Empty.\n");
RDP_ERR_Flag = RDP_RDPBIN_WRONG;
goto exit;
}
/* decrypt using ctr method and DMA to RAM rdp region using IPSEC */
rtl_cryptoEngine_init();
/* RDP key will be use when RDPEN, here we just set a dummy key */
rtl_crypto_aes_ecb_init(aes_ecb_key_dummy, 16);
CRYPTO_SetCheckSumEn(1);
rtl_crypto_aes_ecb_decrypt(rdp_bin_data_en, RDPLen , NULL, 0, (u8*)0x1003F000);
CRYPTO_GetCheckSumData(&checksum_ipsec);
/* read checksum from rdp flash region and compare with checksum calculated by IPSEC */
//checksum_rdp_flash = HAL_READ32(RDPFlashAddr, RDPLen);
if(checksum_rdp_flash == checksum_ipsec){
WriteKeyState = 1;
DBG_8195A("[%s] PG write RDP key ok: %d\n", __func__, PollTimes);
DBG_8195A("RDP bin decryption OK!\n");
break;
}else{
EFUSE_RDP_KEY(RDP_key);
DBG_8195A("write RDP key again: %d \n", PollTimes);
DBG_8195A("checksum_ipsec = 0x%x, checksum_rdp_flash = 0x%x\n", checksum_ipsec, checksum_rdp_flash);
RDP_ERR_Flag = RDP_CHECKSUM_ERROR;
}
}
if(WriteKeyState == 0) {
DBG_8195A("write RDP key failed\n");
goto exit;
}
} else {
RDP_ERR_Flag = RDP_NOT_ENABLE;
goto exit;
}
exit:
if(RDP_ERR_Flag != 0) {
DBG_8195A("RDP_ERR_Flag: %d\n", RDP_ERR_Flag);
}
EFUSE_WRITE_CHECK(DISABLE);
}
/**
* @brief Enable/Disable OTF function.
* @param newStatus: can be ENABLE/DISABLE
*/
void efuse_otf_cmd(u32 NewState)
{
u32 value = HAL_READ32(SYSTEM_CTRL_BASE, REG_SYS_EFUSE_SYSCFG6);
u8 ret = _SUCCESS;
if(NewState != DISABLE){
value |= BIT_SYS_FLASH_ENCRYPT_EN;
}else{
value &= ~BIT_SYS_FLASH_ENCRYPT_EN;
}
ret = EFUSE_LMAP_WRITE(0x18, 2, (u8*)&value);
if (ret == _FAIL) {
DBG_8195A("Set OTF control bit fail \n");
}
}
/**
* @brief Set 16B OTF key into EFUSE.
* @param OtfKey: 16B EFUSE KEY
* @note can not change or read back after write.
*/
void efuse_otf_keyset(u8 *otf_key)
{
EFUSE_OTF_KEY(otf_key);
}
//#endif
/**
* @brief Test whether RSIP_key is set OK.
* @usage 1. Edit a binary file user.bin, which writes 4 bytes origin_data
2. Use image tool to encrypt user.bin into user-en.bin with RSIP_key
3. Burn boot_all.binimage2_all_ota1.bin and user-en.bin(user data section, addr: 0x080F5000) into chip
4. Input atcmd ATSK=RSIP_KEY[value(hex) of RSIP_key], then input ATSK=RSIP_KEY_CHECK[value(hex) of origin_data]
5. If OK, input ATSK=RSIP_EN and download encrypted firmware
* @param origin_data: 4 bytes data writed in user.bin
*/
IMAGE2_RAM_TEXT_SECTION
void efuse_otf_check(uint32_t origin_data)
{
extern char set_key[40];
FLASH_Write_Lock();
uint32_t data = 0;
u8 otf_iv[16]={0x21, 0x32, 0x53, 0x64, 0x75, 0x86, 0xa7, 0xb8,
0xc9, 0xaa, 0xcb, 0x1c, 0x00, 0x00, 0x00, 0x00};
KEY_Request(BIT_OTF_KEY_REQ);
OTF_init(otf_iv);
OTF_Cmd(ENABLE);
//need delay after enable
Cache_Flush();
DBG_8195A("OTF ENABLE\n");
data = HAL_READ32(SPI_FLASH_BASE, 0x000F5000);
DBG_8195A("origin data: %x\n",origin_data);
DBG_8195A("read data: %x\n",data);
if(origin_data==data)
DBG_8195A("set key: %s\nRSIP key check correct!\n", set_key);
else
DBG_8195A("RSIP key check wrong!\n");
OTF_Cmd(DISABLE);
FLASH_Write_Unlock();
DBG_8195A("OTF DISABLE\n");
}
/******************* (C) COPYRIGHT 2016 Realtek Semiconductor *****END OF FILE****/

View File

@@ -0,0 +1,503 @@
/** mbed Microcontroller Library
******************************************************************************
* @file flash_api.c
* @author
* @version V1.0.0
* @date 2016-08-01
* @brief This file provides mbed API for flash.
******************************************************************************
* @attention
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
******************************************************************************
*/
#include "objects.h"
#include "PinNames.h"
#include "pinmap.h"
#include "ameba_soc.h"
#include "rtl8711b_flash.h"
#include "flash_api.h"
extern u32 ConfigDebugInfo;
/**
* global data structure
*/
u32 ISER[8] = {0};
u32 systick_ctrl;
/**
* @brief Disable interrupt and systick exception before write to flash when XIP.
* @param none
* @retval none
*/
static void flash_write_lock()
{
u8 i = 0;
for(; i < 8; i++){
ISER[i] = NVIC->ISER[i];
NVIC->ICER[i] = 0xffffffff; //disable interrupt
NVIC->ICPR[i] = 0xffffffff; //clear pending interrupt
}
systick_ctrl = SysTick->CTRL; //disable systick exception
SysTick->CTRL = 0;
}
/**
* @brief Restore interrupt and systick exception after write to flash when XIP.
* @param none
* @retval none
*/
static void flash_write_unlock()
{
u8 i = 0;
for(;i < 8; i++){
NVIC->ISER[i] = ISER[i];//restore interrupt
}
SysTick->CTRL = systick_ctrl;//restore systick exception
}
/**
* @brief Control the flash chip write protect enable/disable.
* @param obj: Flash object define in application software.
* @param protect: This parameter can be 1 or 0.
* @arg 1: Protect the whole chip from being programmed/erased.
* @arg 0: Unprotect the whole chip from being programmed/erased.
* @retval none
*/
void flash_write_protect(flash_t *obj, u32 protect)
{
flash_write_lock();
FLASH_SetStatusBits(0x1c, protect);
flash_write_unlock();
}
/**
* @brief Set the value of status register1.
* @param obj: Flash object define in application software.
* @param data: The value of status register1 to be set.
* @retval none
*/
int flash_set_status(flash_t *obj, u32 data)
{
u8 status[2];
u8 StatusLen = 1;
status[0] = (u8)data;
flash_write_lock();
/* check if status2 */
if (flash_init_para.FLASH_Status2_exist) {
StatusLen = 2;
FLASH_RxCmd(flash_init_para.FLASH_cmd_rd_status2, 1, &status[1]);
}
if(!flash_init_para.FLASH_cmd_wr_status2){
FLASH_SetStatus(flash_init_para.FLASH_cmd_wr_status, StatusLen, status);
} else {
FLASH_SetStatus(flash_init_para.FLASH_cmd_wr_status, 1, &status[0]);
FLASH_SetStatus(flash_init_para.FLASH_cmd_wr_status2, 1, &status[1]);
}
flash_write_unlock();
return 1;
}
/**
* @brief Retset the value of status register1 to 0.
* @param obj: Flash object define in application software.
* @retval none
*/
void flash_reset_status(flash_t *obj)
{
flash_set_status(obj, 0);
return;
}
/**
* @brief Get the value of status register1
* @param obj: Flash object define in application software.
* @retval The value of status register1.
*/
int flash_get_status(flash_t *obj)
{
int data;
flash_write_lock();
FLASH_RxCmd(flash_init_para.FLASH_cmd_rd_status, 1, (u8*)&data);
flash_write_unlock();
return data;
}
/**
* @brief Erase flash sector(4KB)
* @param obj: Flash object define in application software.
* @param address: Specifies the starting address to be erased. LSB 12bits will be masked.
* @retval none
*/
void flash_erase_sector(flash_t *obj, u32 address)
{
flash_write_lock();
FLASH_Erase(EraseSector, address);
Cache_Flush();
flash_write_unlock();
}
/**
* @brief Erase flash block(64KB)
* @param obj: Flash object define in application software.
* @param address: Specifies the starting address to be erased.LSB 16bits will be masked.
* @retval none
*/
void flash_erase_block(flash_t *obj, u32 address)
{
flash_write_lock();
FLASH_Erase(EraseBlock, address);
Cache_Flush();
flash_write_unlock();
}
/**
* @brief Erase the whole flash chip
* @param obj: Flash object define in application software.
* @retval none
*/
void flash_erase_chip(flash_t *obj)
{
flash_write_lock();
FLASH_Erase(EraseChip, 0);
Cache_Flush();
flash_write_unlock();
}
/**
* @brief Read a word from specified address
* @param obj: Flash object define in application software.
* @param address: Specifies the address to read from.
* @param data: Specified the address to save the readback data.
* @retval status: Success:1 or Failure: Others.
* @note auto mode read is ok, because we have flash cache
*/
int flash_read_word(flash_t *obj, u32 address, u32 * data)
{
// FLASH_RxData(0, address, 4, data);
assert_param(data != NULL);
u32 offset_to_align = address & 0x03;
u32 read_data;
u32 temp;
u32 i = 4 - offset_to_align;
if(offset_to_align){
address -= offset_to_align;
temp = HAL_READ32(SPI_FLASH_BASE, address);
read_data= temp >> (offset_to_align * 8);
address += 4;
temp = HAL_READ32(SPI_FLASH_BASE, address);
read_data |= (temp << (i * 8));
*data = read_data;
}else{
* data = HAL_READ32(SPI_FLASH_BASE, address);
}
return 1;
}
/**
* @brief Write a word to specified address
* @param obj: Flash object define in application software.
* @param address: Specifies the address to be programmed to.
* @param data: Specified the data to be programmed.
* @retval status: Success:1 or Failure: Others.
* @note user mode write used
*/
int flash_write_word(flash_t *obj, u32 address, u32 data)
{
// Disable write protection
// flash_unlock();
u32 write_word = data;
u32 offset_to_align = address & 0x03;
u32 temp;
u32 i = 4 - offset_to_align;
flash_write_lock();
if(offset_to_align){
address -= offset_to_align;
temp = HAL_READ32(SPI_FLASH_BASE, address);
temp = (temp << (i * 8))>>(8*i) | write_word << (8 * offset_to_align);
FLASH_TxData12B(address, 4, (u8*)&temp);
address += 4;
temp = HAL_READ32(SPI_FLASH_BASE, address);
temp = (temp >> (offset_to_align * 8)) << (offset_to_align * 8) | write_word >>(8*i);
FLASH_TxData12B(address, 4, (u8*)&temp);
}else{
FLASH_TxData12B(address, 4, (u8*)&write_word);
}
Cache_Flush();
flash_write_unlock();
// Enable write protection
// flash_lock();
return 1;
}
/**
* @brief Read a stream of data from specified address
* @param obj: Flash object define in application software.
* @param address: Specifies the starting address to read from.
* @param len: Specifies the length of the data to read.
* @param data: Specified the address to save the readback data.
* @retval status: Success:1 or Failure: Others.
* @note auto mode is ok, because we have flash cache
*/
int flash_stream_read(flash_t *obj, u32 address, u32 len, u8 * data)
{
assert_param(data != NULL);
u32 offset_to_align;
u32 i;
u32 read_word;
u8 *ptr;
u8 *pbuf;
offset_to_align = address & 0x03;
pbuf = data;
if (offset_to_align != 0) {
/* the start address is not 4-bytes aligned */
read_word = HAL_READ32(SPI_FLASH_BASE, (address - offset_to_align));
ptr = (u8*)&read_word + offset_to_align;
offset_to_align = 4 - offset_to_align;
for (i=0;i<offset_to_align;i++) {
*pbuf = *(ptr+i);
pbuf++;
len--;
if (len == 0) {
break;
}
}
}
/* address = next 4-bytes aligned */
address = (((address-1) >> 2) + 1) << 2;
ptr = (u8*)&read_word;
if ((u32)pbuf & 0x03) {
while (len >= 4) {
read_word = HAL_READ32(SPI_FLASH_BASE, address);
for (i=0;i<4;i++) {
*pbuf = *(ptr+i);
pbuf++;
}
address += 4;
len -= 4;
}
} else {
while (len >= 4) {
*((u32 *)pbuf) = HAL_READ32(SPI_FLASH_BASE, address);
pbuf += 4;
address += 4;
len -= 4;
}
}
if (len > 0) {
read_word = HAL_READ32(SPI_FLASH_BASE, address);
for (i=0;i<len;i++) {
*pbuf = *(ptr+i);
pbuf++;
}
}
return 1;
}
/**
* @brief Write a stream of data to specified address
* @param obj: Flash object define in application software.
* @param address: Specifies the starting address to write to.
* @param len: Specifies the length of the data to write.
* @param data: Pointer to a byte array that is to be written.
* @retval status: Success:1 or Failure: Others.
*/
int flash_stream_write(flash_t *obj, u32 address, u32 len, u8 * data)
{
// Check address: 4byte aligned & page(256bytes) aligned
u32 page_begin = address & (~0xff);
u32 page_end = (address + len) & (~0xff);
u32 page_cnt = ((page_end - page_begin) >> 8) + 1;
u32 addr_begin = address;
u32 addr_end = (page_cnt == 1) ? (address + len) : (page_begin + 0x100);
u32 size = addr_end - addr_begin;
u8 *buffer = data;
u8 write_data[12];
u32 offset_to_align;
u32 read_word;
u32 i;
flash_write_lock();
while(page_cnt){
offset_to_align = addr_begin & 0x3;
if(offset_to_align != 0){
read_word = HAL_READ32(SPI_FLASH_BASE, addr_begin - offset_to_align);
for(i = offset_to_align;i < 4;i++){
read_word = (read_word & (~(0xff << (8*i)))) |( (*buffer) <<(8*i));
size--;
buffer++;
if(size == 0)
break;
}
FLASH_TxData12B(addr_begin - offset_to_align, 4, (u8*)&read_word);
#ifdef MICRON_N25Q00AA
FLASH_ReadFlagStatusReg();
#endif
}
addr_begin = (((addr_begin-1) >> 2) + 1) << 2;
for(;size >= 12 ;size -= 12){
_memcpy(write_data, buffer, 12);
FLASH_TxData12B(addr_begin, 12, write_data);
#ifdef MICRON_N25Q00AA
FLASH_ReadFlagStatusReg();
#endif
buffer += 12;
addr_begin += 12;
}
for(;size >= 4; size -=4){
_memcpy(write_data, buffer, 4);
FLASH_TxData12B(addr_begin, 4, write_data);
#ifdef MICRON_N25Q00AA
FLASH_ReadFlagStatusReg();
#endif
buffer += 4;
addr_begin += 4;
}
if(size > 0){
read_word = HAL_READ32(SPI_FLASH_BASE, addr_begin);
for( i = 0;i < size;i++){
read_word = (read_word & (~(0xff << (8*i)))) | ((*buffer) <<(8*i));
buffer++;
}
FLASH_TxData12B(addr_begin, 4, (u8*)&read_word);
#ifdef MICRON_N25Q00AA
FLASH_ReadFlagStatusReg();
#endif
}
page_cnt--;
addr_begin = addr_end;
addr_end = (page_cnt == 1) ? (address + len) : (((addr_begin>>8) + 1)<<8);
size = addr_end - addr_begin;
}
Cache_Flush();
flash_write_unlock();
return 1;
}
/**
* @brief It is the same with flash_stream_write function which is used to write a stream of data to specified address.
* @param obj: Flash object define in application software.
* @param address: Specifies the starting address to write to.
* @param len: Specifies the length of the data to write.
* @param data: Pointer to a byte array that is to be written.
* @retval status: Success:1 or Failure: Others.
*/
int flash_burst_write(flash_t *obj, u32 address ,u32 Length, u8 * data)
{
flash_stream_write(obj, address, Length, data);
return 1;
}
/**
* @brief It is the same with flash_stream_read function which is used to read a stream of data from specified address
* @param obj: Flash object define in application software.
* @param address: Specifies the starting address to read from.
* @param len: Specifies the length of the data to read.
* @param data: Specified the address to save the readback data.
* @retval status: Success:1 or Failure: Others.
*/
int flash_burst_read(flash_t *obj, u32 address, u32 Length, u8 * data)
{
flash_stream_read(obj, address, Length, data);
return 1;
}
/**
* @brief This function is only for Micron 128MB flash to access beyond 16MB by switching between eight 16MB-area(segment).
* Please refer to flash datasheet for more information about memory mapping.
* @param obj: Flash object define in application software.
* @param data: Specified which segment to choose.
* @retval status: Success:1 or Failure: Others.
*/
int flash_set_extend_addr(flash_t *obj, u32 data)
{
/*Write Extended Address Register to select operating segment*/
u8 segnum = (u8)(data & 0x07);
flash_write_lock();
FLASH_SetStatus(0xC5, 1, &segnum);
flash_write_unlock();
return 1;
}
/**
* @brief This function is only for Micron 128MB flash to read from Extended Address Register, which shows the current segment.
* Please refer to flash datasheet for more information about memory mapping.
* @param obj: Flash object define in application software.
* @retval value: The value of current Extended Address Register.
*/
int flash_get_extend_addr(flash_t *obj)
{
u8 temp = 0;
flash_write_lock();
FLASH_RxCmd(0xC8, 1, &temp);
flash_write_unlock();
return temp;
}
/**
* @brief This function is to read flash id.
* @param obj: Flash object define in application software.
* @param buf: Specified the address to save the readback data.
* @param len: Specifies the length of the flash id to read.
* @retval : The length of the flash id.
*/
int flash_read_id(flash_t *obj, uint8_t *buf, uint8_t len)
{
assert_param(buf != NULL);
assert_param(len >= 3);
flash_write_lock();
FLASH_RxCmd(flash_init_para.FLASH_cmd_rd_id, len, buf);
flash_write_unlock();
return len;
}

View File

@@ -0,0 +1,215 @@
/** mbed Microcontroller Library
******************************************************************************
* @file gpio_api.c
* @author
* @version V1.0.0
* @date 2016-08-01
* @brief This file provides mbed API for GPIO.
******************************************************************************
* @attention
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
******************************************************************************
*/
#include "objects.h"
#include "pinmap.h"
#include "gpio_api.h"
/**
* @brief Set the given pin as GPIO.
* @param pin: PinName according to pinmux spec.
* @retval The given pin with GPIO function
*/
uint32_t gpio_set(PinName pin)
{
u32 ip_pin;
assert_param(pin != (PinName)NC);
pin_function(pin, 0);
ip_pin = pin;
return ip_pin;
}
/**
* @brief Initializes the GPIO device, include mode/direction/pull control registers.
* @param obj: gpio object define in application software.
* @param pin: PinName according to pinmux spec.
* @retval none
*/
void gpio_init(gpio_t *obj, PinName pin)
{
GPIO_InitTypeDef GPIO_InitStruct;
if (pin == (PinName)NC)
return;
obj->pin = pin;
GPIO_InitStruct.GPIO_Pin = obj->pin;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(&GPIO_InitStruct);
}
/**
* @brief Set GPIO mode.
* @param obj: gpio object define in application software.
* @param mode: this parameter can be one of the following values:
* @arg PullNone: HighZ, user can input high or low use this pin
* @arg PullDown: pull down
* @arg PullUp: pull up
* @retval none
*/
void gpio_mode(gpio_t *obj, PinMode mode)
{
u32 GPIO_PuPd;
switch (mode) {
case PullNone:/* No driver -> Input & High Impendance */
GPIO_PuPd = GPIO_PuPd_NOPULL;
//GPIO_Direction(obj->pin, GPIO_Mode_IN);
break;
case PullDown:
GPIO_PuPd = GPIO_PuPd_DOWN;
break;
case PullUp:
GPIO_PuPd = GPIO_PuPd_UP;
break;
default:
GPIO_PuPd = GPIO_PuPd_NOPULL;
break;
}
PAD_PullCtrl(obj->pin, GPIO_PuPd);
}
/**
* @brief Set GPIO direction.
* @param obj: gpio object define in application software.
* @param direction: this parameter can be one of the following values:
* @arg PIN_INPUT: this pin is input
* @arg PIN_OUTPUT: this pin is output
* @retval none
*/
void gpio_dir(gpio_t *obj, PinDirection direction)
{
assert_param(obj->pin != (PinName)NC);
if (direction == PIN_OUTPUT) {
GPIO_Direction(obj->pin, GPIO_Mode_OUT);
} else {
GPIO_Direction(obj->pin, GPIO_Mode_IN);
}
}
/**
* @brief Set GPIO direction.
* @param obj: gpio object define in application software.
* @param direction: this parameter can be one of the following values:
* @arg PIN_INPUT: this pin is input
* @arg PIN_OUTPUT: this pin is output
* @retval none
*/
void gpio_change_dir(gpio_t *obj, PinDirection direction)
{
gpio_dir(obj, direction);
}
/**
* @brief Sets value to the selected output port pin.
* @param obj: gpio object define in application software.
* @param value: specifies the value to be written to the selected pin
* This parameter can be one of the following values:
* @arg 0: Pin state set to low
* @arg 1: Pin state set to high
* @retval none
*/
void gpio_write(gpio_t *obj, int value)
{
assert_param(obj->pin != (PinName)NC);
GPIO_WriteBit(obj->pin, value);
}
/**
* @brief Sets value to the selected output port pin.
* @param obj: gpio object define in application software.
* @param value: specifies the value to be written to the selected pin
* This parameter can be one of the following values:
* @arg 0: Pin state set to low
* @arg 1: Pin state set to high
* @retval none
*/
void gpio_direct_write(gpio_t *obj, BOOL value)
{
gpio_write(obj, value);
}
/**
* @brief Reads the specified gpio port pin.
* @param obj: gpio object define in application software.
* @retval state of the specified gpio port pin
* - 1: pin state is high
* - 0: pin state is low
*/
int gpio_read(gpio_t *obj)
{
assert_param(obj->pin != (PinName)NC);
return GPIO_ReadDataBit(obj->pin);
}
/**
* @brief Sets pull type to the selected pin.
* @param obj: gpio object define in application software.
* @param pull_type: this parameter can be one of the following values:
* @arg PullNone: HighZ, user can input high or low use this pin
* @arg PullDown: pull down
* @arg PullUp: pull up
* @retval none
*/
void gpio_pull_ctrl(gpio_t *obj, PinMode pull_type)
{
u32 GPIO_PuPd;
switch (pull_type) {
case PullNone:/* No driver -> Input & High Impendance */
GPIO_PuPd = GPIO_PuPd_NOPULL;
break;
case PullDown:
GPIO_PuPd = GPIO_PuPd_DOWN;
break;
case PullUp:
GPIO_PuPd = GPIO_PuPd_UP;
break;
default:
GPIO_PuPd = GPIO_PuPd_NOPULL;
break;
}
PAD_PullCtrl(obj->pin, GPIO_PuPd);
}
/**
* @brief Deinitializes the GPIO device, include mode/direction/pull control registers.
* @param obj: gpio object define in application software.
* @retval none
*/
void gpio_deinit(gpio_t *obj)
{
GPIO_DeInit(obj->pin);
}
/******************* (C) COPYRIGHT 2016 Realtek Semiconductor *****END OF FILE****/

View File

@@ -0,0 +1,204 @@
/** mbed Microcontroller Library
******************************************************************************
* @file gpio_irq_api.c
* @author
* @version V1.0.0
* @date 2016-08-01
* @brief This file provides mbed API for GPIO IRQ.
******************************************************************************
* @attention
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
******************************************************************************
*/
#include "objects.h"
#include "pinmap.h"
#include "gpio_irq_api.h"
#include "gpio_irq_ex_api.h"
/**
* @brief Initializes the GPIO device interrupt mode, include mode/trigger/polarity registers.
* @param obj: gpio irq object define in application software.
* @param pin: PinName according to pinmux spec.
* @note this API only works for Port A pins
* @param handler: Interrupt handler to be assigned to the specified pin.
* @param id: handler id.
* @retval none
*/
int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32_t id)
{
GPIO_InitTypeDef GPIO_InitStruct;
if (pin == NC) return -1;
obj->pin = pin;
RCC_PeriphClockCmd(APBPeriph_GPIO, APBPeriph_GPIO_CLOCK, ENABLE);
GPIO_INTConfig(pin, DISABLE);
GPIO_InitStruct.GPIO_Pin = obj->pin;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_INT;
GPIO_InitStruct.GPIO_ITTrigger = GPIO_INT_Trigger_EDGE;
GPIO_InitStruct.GPIO_ITPolarity = GPIO_INT_POLARITY_ACTIVE_LOW;
InterruptRegister(GPIO_INTHandler, GPIO_IRQ, NULL, 10);
InterruptEn(GPIO_IRQ, 10);
GPIO_Init(&GPIO_InitStruct);
GPIO_UserRegIrq(GPIO_InitStruct.GPIO_Pin, (VOID*) handler, (VOID*) id);
return 0;
}
/**
* @brief Deinitializes the GPIO device interrupt mode, include mode/trigger/polarity registers.
* @param obj: gpio irq object define in application software.
* @note this API only works for Port A pins
* @retval none
*/
void gpio_irq_free(gpio_irq_t *obj)
{
GPIO_DeInit(obj->pin);
}
/**
* @brief Enable/Disable gpio interrupt.
* @param obj: gpio irq object define in application software.
* @param event: gpio interrupt event, this parameter can be one of the following values:
* @arg IRQ_RISE: rising edge interrupt event
* @arg IRQ_FALL: falling edge interrupt event
* @arg IRQ_LOW: low level interrupt event
* @arg IRQ_HIGH: high level interrupt event
* @arg IRQ_NONE: no interrupt event
* @param enable: this parameter can be one of the following values:
* @arg 0 disable gpio interrupt
* @arg 1 enable gpio interrupt
* @retval none
*/
void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable)
{
u32 GPIO_ITTrigger;
u32 GPIO_ITPolarity;
u32 GPIO_ITDebounce;
switch(event) {
case IRQ_RISE:
GPIO_ITTrigger = GPIO_INT_Trigger_EDGE;
GPIO_ITPolarity = GPIO_INT_POLARITY_ACTIVE_HIGH;
break;
case IRQ_FALL:
GPIO_ITTrigger = GPIO_INT_Trigger_EDGE;
GPIO_ITPolarity = GPIO_INT_POLARITY_ACTIVE_LOW;
break;
case IRQ_LOW:
GPIO_ITTrigger = GPIO_INT_Trigger_LEVEL;
GPIO_ITPolarity = GPIO_INT_POLARITY_ACTIVE_LOW;
break;
case IRQ_HIGH:
GPIO_ITTrigger = GPIO_INT_Trigger_LEVEL;
GPIO_ITPolarity = GPIO_INT_POLARITY_ACTIVE_HIGH;
break;
case IRQ_NONE:
// ?
break;
default:
break;
}
if (enable) {
GPIO_INTMode(obj->pin, ENABLE, GPIO_ITTrigger, GPIO_ITPolarity, GPIO_INT_DEBOUNCE_ENABLE);
} else {
GPIO_INTMode(obj->pin, DISABLE, 0, 0, 0);
}
}
/**
* @brief Enable gpio interrupt.
* @param obj: gpio irq object define in application software.
* @retval none
*/
void gpio_irq_enable(gpio_irq_t *obj)
{
GPIO_INTConfig(obj->pin, ENABLE);
}
/**
* @brief Disable gpio interrupt.
* @param obj: gpio irq object define in application software.
* @retval none
*/
void gpio_irq_disable(gpio_irq_t *obj)
{
GPIO_INTConfig(obj->pin, DISABLE);
}
/**
* @brief Deinitializes the GPIO device interrupt mode, include mode/trigger/polarity registers.
* @param obj: gpio irq object define in application software.
* @retval none
*/
void gpio_irq_deinit(gpio_irq_t *obj)
{
GPIO_DeInit(obj->pin);
}
/**
* @brief Sets pull type to the selected interrupt pin.
* @param obj: gpio irq object define in application software.
* @param pull_type: this parameter can be one of the following values:
* @arg PullNone: HighZ, user can input high or low use this pin
* @arg PullDown: pull down
* @arg PullUp: pull up
* @retval none
*/
void gpio_irq_pull_ctrl(gpio_irq_t *obj, PinMode pull_type)
{
u32 GPIO_PuPd;
switch (pull_type) {
case PullNone:/* No driver -> Input & High Impendance */
GPIO_PuPd = GPIO_PuPd_NOPULL;
break;
case PullDown:
GPIO_PuPd = GPIO_PuPd_DOWN;
break;
case PullUp:
GPIO_PuPd = GPIO_PuPd_UP;
break;
default:
GPIO_PuPd = GPIO_PuPd_NOPULL;
break;
}
PAD_PullCtrl(obj->pin, GPIO_PuPd);
}
/**
* @brief Enable the specified gpio interrupt event.
* @param obj: gpio irq object define in application software.
* @param event: gpio interrupt event, this parameter can be one of the following values:
* @arg IRQ_RISE: rising edge interrupt event
* @arg IRQ_FALL: falling edge interrupt event
* @arg IRQ_LOW: low level interrupt event
* @arg IRQ_HIGH: high level interrupt event
* @arg IRQ_NONE: no interrupt event
* @retval none
*/
void gpio_irq_set_event(gpio_irq_t *obj, gpio_irq_event event)
{
gpio_irq_set(obj, event, ENABLE);
}
/******************* (C) COPYRIGHT 2016 Realtek Semiconductor *****END OF FILE****/

View File

@@ -0,0 +1,32 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_GPIO_OBJECT_H
#define MBED_GPIO_OBJECT_H
#include "mbed_assert.h"
#include "basic_types.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,854 @@
/** mbed Microcontroller Library
******************************************************************************
* @file i2c_api.c
* @author
* @version V1.0.0
* @date 2016-08-01
* @brief This file provides mbed API for I2C.
******************************************************************************
* @attention
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
******************************************************************************
*/
#include "objects.h"
#include "PinNames.h"
#include "i2c_api.h"
#include "pinmap.h"
// See I2CSlave.h
#define NoData 0 // the slave has not been addressed
#define ReadAddressed 1 // the master has requested a read from this slave (slave = transmitter)
#define WriteGeneral 2 // the master is writing to all slave
#define WriteAddressed 3 // the master is writing to this slave (slave = receiver)
static uint16_t i2c_target_addr[2];
extern u32 ConfigDebugErr;
extern u32 ConfigDebuginfo;
I2C_InitTypeDef I2CInitDat[2];
static u32 restart_enable = 0;
static u32 master_addr_retry = 1;
void i2c_send_restart(I2C_TypeDef *I2Cx, u8* pBuf, u8 len, u8 restart);
/**
* @brief Read data with special length in master mode through the I2Cx peripheral under in-house IP.
* @param I2Cx: where I2Cx can be I2C0_DEV or I2C1_DEV.
* @param pBuf: point to the buffer to hold the received data.
* @param len: the length of data that to be received.
* @note deal with condition that master send address while slave no ack
* @retval the length of data read.
*/
u8 I2C_MasterRead_Patch(I2C_TypeDef *I2Cx, u8* pBuf, u8 len)
{
u8 cnt = 0;
/* Check the parameters */
assert_param(IS_I2C_ALL_PERIPH(I2Cx));
/* read in the DR register the data to be received */
for(cnt = 0; cnt < len; cnt++) {
if(cnt >= len - 1) {
/* generate stop singal */
I2Cx->IC_DATA_CMD = 0x0003 << 8;
} else {
I2Cx->IC_DATA_CMD = 0x0001 << 8;
}
/* wait for I2C_FLAG_RFNE flag */
while((I2C_CheckFlagState(I2Cx, BIT_IC_STATUS_RFNE)) == 0) {
if(I2C_GetRawINT(I2Cx) & BIT_IC_RAW_INTR_STAT_TX_ABRT) {
DBG_8195A(" TX_ABRT\n");
I2C_ClearAllINT(I2Cx);
return cnt;
}
}
*pBuf++ = (u8)I2Cx->IC_DATA_CMD;
}
return cnt;
}
/**
* @brief Write data with special length in master mode through the I2Cx peripheral under in-house IP.
* @param I2Cx: where I2Cx can be I2C0_DEV or I2C1_DEV.
* @param pBuf: point to the data to be transmitted.
* @param len: the length of data that send.
* @note deal with condition that master send address while slave no ack
* @retval the length of data send.
*/
u8 I2C_MasterWrite_Patch(I2C_TypeDef *I2Cx, u8* pBuf, u8 len)
{
u8 cnt = 0;
u8 temp = 0;
/* Check the parameters */
assert_param(IS_I2C_ALL_PERIPH(I2Cx));
/* Write in the DR register the data to be sent */
for(cnt = 0; cnt < len; cnt++)
{
while((I2C_CheckFlagState(I2Cx, BIT_IC_STATUS_TFNF)) == 0);
if(cnt >= len - 1)
{
/*generate stop signal*/
I2Cx->IC_DATA_CMD = (*pBuf++) | (1 << 9);
}
else
{
I2Cx->IC_DATA_CMD = (*pBuf++);
}
while((I2C_CheckFlagState(I2Cx, BIT_IC_STATUS_TFE)) == 0) {
if(I2C_GetRawINT(I2Cx) & BIT_IC_RAW_INTR_STAT_TX_ABRT) {
DBG_8195A(" TX_ABRT\n");
I2C_ClearAllINT(I2Cx);
return cnt;
}
}
}
return cnt;
}
/**
* @brief Read data with special length in master mode through the I2Cx peripheral under in-house IP.
* @param I2Cx: where I2Cx can be I2C0_DEV or I2C1_DEV.
* @param pBuf: point to the buffer to hold the received data.
* @param len: the length of data that to be received.
* @param timeout_ms: specifies timeout time, unit is ms.
* @retval the length of data read.
*/
int I2C_MasterRead_TimeOut(I2C_TypeDef *I2Cx, u8* pBuf, u8 len, u32 timeout_ms)
{
int cnt = 0;
u32 InTimeoutCount = 0;
/* Check the parameters */
assert_param(IS_I2C_ALL_PERIPH(I2Cx));
/* read in the DR register the data to be received */
for(cnt = 0; cnt < len; cnt++) {
InTimeoutCount = timeout_ms*500;
if(cnt >= len - 1) {
/* generate stop singal */
I2Cx->IC_DATA_CMD = 0x0003 << 8;
} else {
I2Cx->IC_DATA_CMD = 0x0001 << 8;
}
/* wait for I2C_FLAG_RFNE flag */
while((I2C_CheckFlagState(I2Cx, BIT_IC_STATUS_RFNE)) == 0) {
if(I2C_GetRawINT(I2Cx) & BIT_IC_RAW_INTR_STAT_TX_ABRT) {
DBG_8195A(" TX_ABRT\n");
I2C_ClearAllINT(I2Cx);
return cnt;
}
DelayUs(2);
if (InTimeoutCount == 0) {
DBG_8195A("MasterRead_TimeOut\n");
return cnt;
}
InTimeoutCount--;
}
*pBuf++ = (u8)I2Cx->IC_DATA_CMD;
}
return cnt;
}
/**
* @brief Write data with special length in master mode through the I2Cx peripheral under in-house IP.
* @param I2Cx: where I2Cx can be I2C0_DEV or I2C1_DEV.
* @param pBuf: point to the data to be transmitted.
* @param len: the length of data that to be received.
* @param timeout_ms: specifies timeout time, unit is ms.
* @retval the length of data send.
*/
int I2C_MasterWrite_TimeOut(I2C_TypeDef *I2Cx, u8* pBuf, u8 len, u32 timeout_ms)
{
int cnt = 0;
u32 InTimeoutCount = 0;
/* Check the parameters */
assert_param(IS_I2C_ALL_PERIPH(I2Cx));
/* Write in the DR register the data to be sent */
for(cnt = 0; cnt < len; cnt++)
{
InTimeoutCount = timeout_ms*500;
while((I2C_CheckFlagState(I2Cx, BIT_IC_STATUS_TFNF)) == 0);
if(cnt >= len - 1)
{
/*generate stop signal*/
I2Cx->IC_DATA_CMD = (*pBuf++) | (1 << 9);
}
else
{
I2Cx->IC_DATA_CMD = (*pBuf++);
}
while((I2C_CheckFlagState(I2Cx, BIT_IC_STATUS_TFE)) == 0) {
if(I2C_GetRawINT(I2Cx) & BIT_IC_RAW_INTR_STAT_TX_ABRT) {
DBG_8195A(" TX_ABRT\n");
I2C_ClearAllINT(I2Cx);
return cnt;
}
DelayUs(2);
if (InTimeoutCount == 0) {
DBG_8195A("MasterWrite_TimeOut\n");
return cnt;
}
InTimeoutCount--;
}
}
return cnt;
}
/**
* @brief Master sends single byte through the I2Cx peripheral to detect slave device.
* @param obj: i2c object define in application software.
* @param address: the address of slave that to be detected.
* @param timeout_ms: specifies timeout time, unit is ms.
* @retval Slave ack condition:
* - 0: Slave available
* - -1: Slave not available
*/
int I2C_MasterSendNullData_TimeOut(I2C_TypeDef *I2Cx, int address, u32 timeout_ms)
{
u8 I2CTemp = (u8)(address<<1);
I2C_MasterSendNullData(I2Cx, &I2CTemp, 0, 1, 0);
DelayMs(timeout_ms);
if(I2C_GetRawINT(I2Cx) & BIT_IC_RAW_INTR_STAT_TX_ABRT) {
I2C_ClearAllINT(I2Cx);
/* Wait for i2c enter trap state from trap_stop state*/
DelayUs(100);
I2C_Cmd(I2Cx, DISABLE);
I2C_Cmd(I2Cx, ENABLE);
return -1;
}
return 0;
}
/**
* @brief Get i2c index according to the SDA PinName.
* @param sda: SDA PinName according to pinmux spec.
* @retval i2c index:
* - 0: I2C0 Device
* - 1: I2C1 Device
*/
static uint32_t
i2c_index_get(PinName sda)
{
if ((sda == _PA_4) || (sda == _PA_19)|| (sda == _PA_30)) {
return 0;
} else if ((sda == _PA_2) || (sda == _PA_23)|| (sda == _PA_27)) {
return 1;
} else {
assert_param(0);
}
return 2;
}
/**
* @brief Initializes the I2C device, include clock/function/I2C registers.
* @param obj: i2c object define in application software.
* @param sda: SDA PinName according to pinmux spec.
* @param scl: SCL PinName according to pinmux spec.
* @retval none
*/
void i2c_init(i2c_t *obj, PinName sda, PinName scl)
{
uint32_t i2c_idx = i2c_index_get(sda);
ConfigDebugErr &= (~(_DBG_I2C_|_DBG_GDMA_));
ConfigDebugInfo&= (~(_DBG_I2C_|_DBG_GDMA_));
DBG_8195A("i2c_idx:%x\n",i2c_idx);
obj->i2c_idx = i2c_idx;
obj->I2Cx = I2C_DEV_TABLE[i2c_idx].I2Cx;
/* Set I2C Device Number */
I2CInitDat[obj->i2c_idx].I2CIdx = i2c_idx;
/* Load I2C default value */
I2C_StructInit(&I2CInitDat[obj->i2c_idx]);
/* Assign I2C Pin Mux */
I2CInitDat[obj->i2c_idx].I2CMaster = I2C_MASTER_MODE;
I2CInitDat[obj->i2c_idx].I2CSpdMod = I2C_SS_MODE;
I2CInitDat[obj->i2c_idx].I2CClk = 100;
I2CInitDat[obj->i2c_idx].I2CAckAddr = 0;
/* Init I2C now */
if(I2CInitDat[obj->i2c_idx].I2CIdx == 0) {
//RCC_PeriphClockCmd(APBPeriph_I2C0, APBPeriph_I2C0_CLOCK, DISABLE);
RCC_PeriphClockCmd(APBPeriph_I2C0, APBPeriph_I2C0_CLOCK, ENABLE);
} else {
//RCC_PeriphClockCmd(APBPeriph_I2C1, APBPeriph_I2C1_CLOCK, DISABLE);
RCC_PeriphClockCmd(APBPeriph_I2C1, APBPeriph_I2C1_CLOCK, ENABLE);
}
/* I2C Pin Mux Initialization */
Pinmux_Config(sda, PINMUX_FUNCTION_I2C);
Pinmux_Config(scl, PINMUX_FUNCTION_I2C);
PAD_PullCtrl(sda, GPIO_PuPd_UP);
PAD_PullCtrl(scl, GPIO_PuPd_UP);
/* I2C HAL Initialization */
I2C_Init(obj->I2Cx, &I2CInitDat[obj->i2c_idx]);
/* I2C Enable Module */
I2C_Cmd(obj->I2Cx, ENABLE);
}
/**
* @brief Set i2c frequency.
* @param obj: i2c object define in application software.
* @param hz: i2c clock(unit is Hz).
* @retval none
*/
void i2c_frequency(i2c_t *obj, int hz)
{
uint16_t i2c_default_clk = (uint16_t) I2CInitDat[obj->i2c_idx].I2CClk;
uint16_t i2c_user_clk = (uint16_t) (hz/1000);
if (i2c_default_clk != i2c_user_clk) {
/* Deinit I2C first */
i2c_reset(obj);
if (i2c_user_clk <= 100) {
I2CInitDat[obj->i2c_idx].I2CSpdMod = I2C_SS_MODE;
}
else if ((i2c_user_clk > 100) && (i2c_user_clk <= 400)) {
I2CInitDat[obj->i2c_idx].I2CSpdMod = I2C_FS_MODE;
}
else if (i2c_user_clk > 400) {
I2CInitDat[obj->i2c_idx].I2CSpdMod = I2C_HS_MODE;
}
else {
I2CInitDat[obj->i2c_idx].I2CSpdMod = I2C_SS_MODE;
}
/* Load the user defined I2C clock */
I2CInitDat[obj->i2c_idx].I2CClk = i2c_user_clk;
/* Init I2C now */
I2C_Init(obj->I2Cx, &I2CInitDat[obj->i2c_idx]);
I2C_Cmd(obj->I2Cx, ENABLE);
}
}
/**
* @brief Start i2c device.
* @param obj: i2c object define in application software.
* @retval 0
*/
inline int i2c_start(i2c_t *obj)
{
return 0;
}
/**
* @brief Stop i2c device.
* @param obj: i2c object define in application software.
* @retval 0
*/
inline int i2c_stop(i2c_t *obj)
{
return 0;
}
/**
* @brief I2C master read in poll mode.
* @param obj: i2c object define in application software.
* @param address: slave address which will be transmitted.
* @param data: point to the buffer to hold the received data.
* @param length: the length of data that to be received.
* @param stop: specifies whether a STOP is issued after all the bytes are received.
* @param timeout_ms: specifies timeout time, unit is ms.
* @retval the length of data received. If the retval less than the data length that want to be received, this transfer is not success.
*/
int i2c_read_timeout(i2c_t *obj, int address, char *data, int length, int stop, int timeout_ms)
{
if (i2c_target_addr[obj->i2c_idx] != address) {
/* Deinit I2C first */
i2c_reset(obj);
/* Load the user defined I2C target slave address */
i2c_target_addr[obj->i2c_idx] = address;
I2CInitDat[obj->i2c_idx].I2CAckAddr = address;
/* Init I2C now */
I2C_Init(obj->I2Cx, &I2CInitDat[obj->i2c_idx]);
I2C_Cmd(obj->I2Cx, ENABLE);
}
return (I2C_MasterRead_TimeOut(obj->I2Cx, (unsigned char*)data, length,timeout_ms));
}
/**
* @brief I2C master wite in poll mode.
* @param obj: i2c object define in application software.
* @param address: slave address which will be transmitted.
* @param data: point to the buffer to hold the received data.
* @param length: the length of data that to be received.
* @param stop: specifies whether a STOP is issued after all the bytes are written.
* @param timeout_ms: specifies timeout time, unit is ms.
* @note If the length equal to zero, will call I2C_MasterSendNullData_TimeOut()
* @retval the length of data written. If the retval less than the data length that want to be sent, this transfer is not success.
*/
int i2c_write_timeout(i2c_t *obj, int address, char *data, int length, int stop, int timeout_ms)
{
if (i2c_target_addr[obj->i2c_idx] != address) {
/* Deinit I2C first */
i2c_reset(obj);
/* Load the user defined I2C target slave address */
i2c_target_addr[obj->i2c_idx] = address;
I2CInitDat[obj->i2c_idx].I2CAckAddr = address;
/* Init I2C now */
I2C_Init(obj->I2Cx, &I2CInitDat[obj->i2c_idx]);
I2C_Cmd(obj->I2Cx, ENABLE);
}
if(!length) {
return (I2C_MasterSendNullData_TimeOut(obj->I2Cx, address, timeout_ms));
}
return (I2C_MasterWrite_TimeOut(obj->I2Cx, (unsigned char*)data, length,timeout_ms));
}
/**
* @brief I2C master read in poll mode.
* @param obj: i2c object define in application software.
* @param address: slave address which will be transmitted.
* @param data: point to the buffer to hold the received data.
* @param length: the length of data that to be received.
* @param stop: specifies whether a STOP is issued after all the bytes are received.
* @retval the length of data received.
*/
int i2c_read(i2c_t *obj, int address, char *data, int length, int stop)
{
u32 I2CInTOTcnt = 0;
u32 InTimeoutCount = 0;
u32 InStartCount = 0;
if (i2c_target_addr[obj->i2c_idx] != address) {
/* Deinit I2C first */
i2c_reset(obj);
/* Load the user defined I2C target slave address */
i2c_target_addr[obj->i2c_idx] = address;
I2CInitDat[obj->i2c_idx].I2CAckAddr = address;
/* Init I2C now */
I2C_Init(obj->I2Cx, &I2CInitDat[obj->i2c_idx]);
I2C_Cmd(obj->I2Cx, ENABLE);
}
if (!master_addr_retry) {
I2C_MasterRead(obj->I2Cx, (unsigned char*)data, length);
} else {
while (0 == I2C_MasterRead_Patch(obj->I2Cx, (unsigned char*)data, length)) {
/* Wait for i2c enter trap state from trap_stop state*/
DelayUs(100);
/* Deinit I2C first */
i2c_reset(obj);
/* Load the user defined I2C target slave address */
i2c_target_addr[obj->i2c_idx] = address;
I2CInitDat[obj->i2c_idx].I2CAckAddr = address;
/* Init I2C now */
I2C_Init(obj->I2Cx, &I2CInitDat[obj->i2c_idx]);
I2C_Cmd(obj->I2Cx, ENABLE);
}
}
return length;
}
/**
* @brief I2C master write in poll mode.
* @param obj: i2c object define in application software.
* @param address: slave address which will be transmitted.
* @param data: point to the data to be sent.
* @param length: the length of data that to be sent.
* @param stop: specifies whether a STOP is issued after all the bytes are sent.
* @retval the length of data send.
*/
int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop)
{
u32 I2CInTOTcnt = 0;
u32 InTimeoutCount = 0;
u32 InStartCount = 0;
if (i2c_target_addr[obj->i2c_idx] != address) {
/* Deinit I2C first */
i2c_reset(obj);
/* Load the user defined I2C target slave address */
i2c_target_addr[obj->i2c_idx] = address;
I2CInitDat[obj->i2c_idx].I2CAckAddr = address;
/* Init I2C now */
I2C_Init(obj->I2Cx, &I2CInitDat[obj->i2c_idx]);
I2C_Cmd(obj->I2Cx, ENABLE);
}
if ((!restart_enable) |(1==stop)) {
return (I2C_MasterWrite_Patch(obj->I2Cx, (unsigned char*)data, length));
} else {
i2c_send_restart(obj->I2Cx, (unsigned char*)data, length, 1);
}
return length;
}
/**
* @brief I2C master send data and read data in poll mode.
* @param obj: i2c object define in application software.
* @param address: slave address which will be transmitted.
* @param pWriteBuf: point to the data to be sent.
* @param Writelen: the length of data that to be sent.
* @param pReadBuf: point to the buffer to hold the received data.
* @param Readlen: the length of data that to be received.
* @retval the length of data received.
*/
int i2c_repeatread(i2c_t *obj, int address, uint8_t *pWriteBuf, int Writelen, uint8_t *pReadBuf, int Readlen)
{
u8 cnt = 0;
if (i2c_target_addr[obj->i2c_idx] != address) {
/* Deinit I2C first */
i2c_reset(obj);
/* Load the user defined I2C target slave address */
i2c_target_addr[obj->i2c_idx] = address;
I2CInitDat[obj->i2c_idx].I2CAckAddr = address;
/* Init I2C now */
I2C_Init(obj->I2Cx, &I2CInitDat[obj->i2c_idx]);
I2C_Cmd(obj->I2Cx, ENABLE);
}
/* write in the DR register the data to be sent */
for(cnt = 0; cnt < Writelen; cnt++)
{
while((I2C_CheckFlagState(obj->I2Cx, BIT_IC_STATUS_TFNF)) == 0);
if(cnt >= Writelen - 1)
{
/*generate stop signal*/
obj->I2Cx->IC_DATA_CMD = (*pWriteBuf++) | (1 << 10);
}
else
{
obj->I2Cx->IC_DATA_CMD = (*pWriteBuf++);
}
}
/*Wait I2C TX FIFO not full*/
while((I2C_CheckFlagState(obj->I2Cx, BIT_IC_STATUS_TFNF)) == 0);
I2C_MasterRead(obj->I2Cx, pReadBuf, Readlen);
return Readlen;
}
/**
* @brief I2C master restart after all bytes are sent.
* @param I2Cx: where I2Cx can be I2C0_DEV or I2C1_DEV to select the I2C peripheral.
* @param pBuf: point to the data to be sent.
* @param len: the length of data that to be sent.
* @param restart: specifies whether a RESTART is issued after all the bytes are sent.
* @retval none
*/
void i2c_send_restart(I2C_TypeDef *I2Cx, u8* pBuf, u8 len, u8 restart)
{
u8 cnt = 0;
/* Check the parameters */
assert_param(IS_I2C_ALL_PERIPH(I2Cx));
/* Write in the DR register the data to be sent */
for(cnt = 0; cnt < len; cnt++)
{
while((I2C_CheckFlagState(I2Cx, BIT_IC_STATUS_TFNF)) == 0);
if(cnt >= len - 1)
{
/*generate restart signal*/
I2Cx->IC_DATA_CMD = (*pBuf++) | (restart << 10);
}
else
{
I2Cx->IC_DATA_CMD = (*pBuf++);
}
}
while((I2C_CheckFlagState(I2Cx, BIT_IC_STATUS_TFE)) == 0);
}
/**
* @brief I2C master receive single byte.
* @param obj: i2c object define in application software.
* @param last: hold the received data.
* @retval the data that received.
*/
int i2c_byte_read(i2c_t *obj, int last)
{
uint8_t i2cdatlocal;
I2C_MasterRead(obj->I2Cx, &i2cdatlocal, 1);
return (int)i2cdatlocal;
}
/**
* @brief I2C master send single byte.
* @param obj: i2c object define in application software.
* @param data: the data to be sent.
* @retval result.
*/
int i2c_byte_write(i2c_t *obj, int data)
{
uint8_t i2cdatlocal = data;
I2C_MasterWrite(obj->I2Cx, &i2cdatlocal, 1);
return 1;
}
/**
* @brief Deinitializes the I2C device
* @param obj: i2c object define in application software.
* @retval none
*/
void i2c_reset(i2c_t *obj)
{
/* Deinit I2C directly */
/* I2C HAL DeInitialization */
I2C_Cmd(obj->I2Cx, DISABLE);
}
/**
* @brief Enable i2c master RESTART function
* @param obj: i2c object define in application software.
* @retval none
*/
void i2c_restart_enable(i2c_t *obj)
{
uint32_t i2cen;
if (obj->I2Cx->IC_ENABLE & BIT_CTRL_IC_ENABLE) {
I2C_Cmd(obj->I2Cx, DISABLE);
i2cen = 1;
}
obj->I2Cx->IC_CON |= BIT_CTRL_IC_CON_IC_RESTART_EN;
if (i2cen) {
I2C_Cmd(obj->I2Cx, ENABLE);
}
restart_enable = 1;
}
/**
* @brief Disable i2c Master RESTART function
* @param obj: i2c object define in application software.
* @retval none
*/
void i2c_restart_disable(i2c_t *obj)
{
uint32_t i2cen;
if (obj->I2Cx->IC_ENABLE & BIT_CTRL_IC_ENABLE) {
I2C_Cmd(obj->I2Cx, DISABLE);
i2cen = 1;
}
obj->I2Cx->IC_CON &= ~BIT_CTRL_IC_CON_IC_RESTART_EN;
if (i2cen) {
I2C_Cmd(obj->I2Cx, ENABLE);
}
restart_enable = 0;
}
/**
* @brief Enable/Disable i2c Device
* @param obj: i2c object define in application software.
* @param enable: this parameter can be one of the following values:
* @arg 0 disable
* @arg 1 enable
* @retval result
*/
int i2c_enable_control(i2c_t *obj, int enable)
{
if (enable) {
I2C_Cmd(obj->I2Cx, ENABLE);
} else {
I2C_Cmd(obj->I2Cx, DISABLE);
}
return 0;
}
//#if DEVICE_I2CSLAVE
/**
* @brief Set i2c slave address.
* @param obj: i2c object define in application software.
* @param idx: i2c index, this parameter can be one of the following values:
* @arg 0 I2C0 Device
* @arg 1 I2C1 Device
* @param address: slave address.
* @param mask: the mask of address
* @retval none
*/
void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask)
{
uint16_t i2c_default_addr = (uint16_t) I2CInitDat[obj->i2c_idx].I2CAckAddr;
uint16_t i2c_user_addr = (uint16_t) address;
if (i2c_default_addr != i2c_user_addr) {
/* Deinit I2C first */
i2c_reset(obj);
/* Load the user defined I2C clock */
I2CInitDat[obj->i2c_idx].I2CAckAddr = i2c_user_addr;
/* Init I2C now */
I2C_Init(obj->I2Cx, &I2CInitDat[obj->i2c_idx]);
I2C_Cmd(obj->I2Cx, ENABLE);
}
}
/**
* @brief Set i2c device to be slave.
* @param obj: i2c object define in application software.
* @param enable_slave: enable slave function, this parameter can be one of the following values:
* @arg 0 disable
* @arg 1 enable
* @retval none
*/
void i2c_slave_mode(i2c_t *obj, int enable_slave)
{
/* Deinit I2C first */
i2c_reset(obj);
/* Load the user defined I2C clock */
I2CInitDat[obj->i2c_idx].I2CMaster = I2C_MASTER_MODE;
if (enable_slave)
I2CInitDat[obj->i2c_idx].I2CMaster = I2C_SLAVE_MODE;
/* Init I2C now */
I2C_Init(obj->I2Cx, &I2CInitDat[obj->i2c_idx]);
I2C_Cmd(obj->I2Cx, ENABLE);
}
/**
* @brief Get i2c slave state.
* @param obj: i2c object define in application software.
* @retval the state of i2c slave.
*/
int i2c_slave_receive(i2c_t *obj)
{
u32 I2CLocalTemp = I2C_GetRawINT(obj->I2Cx);
if (I2CLocalTemp & BIT_IC_RAW_INTR_STAT_GEN_CALL) {
return WriteGeneral;
}
else if (I2CLocalTemp & BIT_IC_RAW_INTR_STAT_RD_REQ) {
return ReadAddressed;
}
if (I2C_CheckFlagState(obj->I2Cx, BIT_IC_STATUS_RFNE)) {
return WriteAddressed;
}
return 0;
}
/**
* @brief I2C slave read in poll mode.
* @param obj: i2c object define in application software.
* @param data: point to the buffer to hold the received data.
* @param length: the length of data that to be received.
* @retval the length of data received.
*/
int i2c_slave_read(i2c_t *obj, char *data, int length)
{
I2C_SlaveRead(obj->I2Cx, (unsigned char*)data, length);
return length;
}
/**
* @brief I2C slave write in poll mode.
* @param obj: i2c object define in application software.
* @param data: point to the data to be sent.
* @param length: the length of data that to be sent.
* @retval result.
*/
int i2c_slave_write(i2c_t *obj, const char *data, int length)
{
I2C_SlaveWrite(obj->I2Cx, (unsigned char*)data, length);
return 1;
}
/**
* @brief Set/clear i2c slave RD_REQ interrupt mask.
* @param obj: i2c object define in application software.
* @param set: set or clear for read request.
* @retval result.
*/
int i2c_slave_set_for_rd_req(i2c_t *obj, int set)
{
if (set) {
I2C_INTConfig(obj->I2Cx, BIT_IC_INTR_MASK_M_RD_REQ, ENABLE);
} else {
I2C_INTConfig(obj->I2Cx, BIT_IC_INTR_MASK_M_RD_REQ, DISABLE);
}
return _TRUE;
}
/**
* @brief Set/clear i2c slave NAK or ACK data part in transfer.
* @param obj: i2c object define in application software.
* @param set_nak: set or clear for data NAK.
* @retval result.
*/
int i2c_slave_set_for_data_nak(i2c_t *obj, int set_nak)
{
I2C_TypeDef * I2Cx = obj->I2Cx;
u32 temp;
while (1) {
temp = I2Cx->IC_STATUS;
if ((BIT_IC_STATUS_SLV_ACTIVITY & temp) == 0) {
break;
}
}
I2Cx->IC_SLV_DATA_NACK_ONLY = set_nak;
return 0;
}
//#endif // CONFIG_I2C_SLAVE_EN
/******************* (C) COPYRIGHT 2016 Realtek Semiconductor *****END OF FILE****/

View File

@@ -0,0 +1,361 @@
/** mbed Microcontroller Library
******************************************************************************
* @file i2s_api.c
* @author
* @version V1.0.0
* @date 2016-08-01
* @brief This file provides mbed API for I2S.
******************************************************************************
* @attention
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
******************************************************************************
*/
#include "objects.h"
#include "i2s_api.h"
#include "pinmap.h"
typedef struct {
VOID (*TxCCB)(uint32_t id, char *pbuf);
u32 TxCBId;
VOID (*RxCCB)(uint32_t id, char *pbuf);
u32 RxCBId;
} I2S_USER_CB;
static I2S_InitTypeDef I2SInitStruct;
static I2S_USER_CB I2SUserCB; //Pointer to I2S User Callback
static u32 next_tx_complete = 0;
extern u32 i2s_cur_tx_page;
extern u32 i2s_cur_rx_page;
static void i2s_sw_reset(void)
{
i2s_cur_tx_page = 0;
i2s_cur_rx_page = 0;
next_tx_complete = 0;
}
static void i2s_isr(void *Data)
{
u32 I2STxIsr, I2SRxIsr;
u8 I2SPageNum = I2SInitStruct.I2S_PageNum;
u32 i;
u32 pbuf;
u32 cur_tx_page = 0;
u32 cur_rx_page = 0;
I2S_ISRGet(I2S_DEV, &I2STxIsr, &I2SRxIsr);
I2S_INTClear(I2S_DEV, I2STxIsr, I2SRxIsr);
for (i=0 ; i<I2SPageNum; i++) { // page 0, 1, 2, 3
cur_rx_page = I2S_GetRxPage(I2S_DEV);
if (I2SRxIsr & (1<<cur_rx_page)) {
pbuf = I2S_GetRxPageAddr(cur_rx_page);
I2SRxIsr &= ~(1<<cur_rx_page);
I2SUserCB.RxCCB(I2SUserCB.RxCBId, (char*)pbuf);
} else {
break;
}
}
for (i=0 ; i<I2SPageNum; i++) { // page 0, 1, 2, 3
if (I2STxIsr & (1<<next_tx_complete)) {
pbuf = I2S_GetTxPageAddr(next_tx_complete);
I2STxIsr &= ~(1<<next_tx_complete);
next_tx_complete++;
next_tx_complete &= 0x03;
I2SUserCB.TxCCB(I2SUserCB.TxCBId, (char*)pbuf);
} else {
break;
}
}
}
/**
* @brief Initializes the I2S device, include clock/function/interrupt/I2S registers.
* @param obj: i2s object define in application software.
* @param sck: Serial clock PinName according to pinmux spec.
* @param ws: Word select PinName according to pinmux spec.
* @param sd_tx: Tx PinName according to pinmux spec.
* @param sd_rx: Rx PinName according to pinmux spec.
* @param mck: Master clock PinName according to pinmux spec.
* @retval none
*/
void i2s_init(i2s_t *obj, PinName sck, PinName ws, PinName sd_tx, PinName sd_rx, PinName mck)
{
obj->i2s_idx = 0;
DBG_PRINTF(MODULE_I2S, LEVEL_INFO, "%s: Use I2S%d \n", __func__, obj->i2s_idx);
// Load user defined parameters
I2S_StructInit(&I2SInitStruct);
/*I2S Interrupt Initialization*/
InterruptRegister((IRQ_FUN) i2s_isr, I2S0_PCM0_IRQ, NULL, 3);
InterruptEn(I2S0_PCM0_IRQ, 3);
/* enable system pll */
PLL1_Set(BIT_SYS_SYSPLL_CK22P5792_EN | BIT_SYS_SYSPLL_CK24P576_EN, ENABLE);
/* enable lx bus for i2s */
LXBUS_FCTRL(ON);
/*I2S Pin Mux Initialization*/
RCC_PeriphClockCmd(APBPeriph_I2S0, APBPeriph_I2S0_CLOCK, ENABLE);
Pinmux_Config(sck, PINMUX_FUNCTION_I2S);
Pinmux_Config(ws, PINMUX_FUNCTION_I2S);
Pinmux_Config(sd_tx, PINMUX_FUNCTION_I2S);
Pinmux_Config(sd_rx, PINMUX_FUNCTION_I2S);
Pinmux_Config(mck, PINMUX_FUNCTION_I2S);
next_tx_complete = 0;
I2SInitStruct.I2S_TRxAct = obj->direction;
I2SInitStruct.I2S_ChNum = obj->channel_num;
I2SInitStruct.I2S_Rate = obj->sampling_rate;
I2SInitStruct.I2S_WordLen = obj->word_length;
/*I2S HAL Initialization*/
I2S_Init(I2S_DEV, &I2SInitStruct);
/*I2S Enable Module*/
I2S_Cmd(I2S_DEV, ENABLE);
I2S_INTConfig(I2S_DEV, (I2S_TX_INT_PAGE0_OK|I2S_TX_INT_PAGE1_OK| I2S_TX_INT_PAGE2_OK|I2S_TX_INT_PAGE3_OK),
(I2S_RX_INT_PAGE0_OK|I2S_RX_INT_PAGE1_OK | I2S_RX_INT_PAGE2_OK|I2S_RX_INT_PAGE3_OK));
}
/**
* @brief Sets page number, page size, page address.
* @param obj: i2s object define in application software.
* @param tx_buf: pointer to the start address of Tx page.
* @param rx_buf: pointer to the start address of Rx page.
* @param page_num: page number. This parameter must be set to a value in the 2~4 range
* @param page_size: page size. This parameter must be set to a value in the 4~16384 bytes range
* @retval none
*/
void i2s_set_dma_buffer(i2s_t *obj, char *tx_buf, char *rx_buf,
uint32_t page_num, uint32_t page_size)
{
u32 i;
//uint8_t i2s_idx = obj->i2s_idx;
if ((page_num < 2) || (page_num > 4) || (page_size < 8)) {
DBG_PRINTF(MODULE_I2S, LEVEL_INFO, "%s: PageNum(%d) valid value is 2~4; PageSize(%d must > 8)\r\n", \
__FUNCTION__, page_num, page_size);
return;
}
I2SInitStruct.I2S_PageNum = page_num;
I2SInitStruct.I2S_PageSize = page_size/4; // unit is 4-bytes
I2S_SetPageSize(I2S_DEV, (page_size/4));
I2S_SetPageNum(I2S_DEV, (page_num));
I2S_SetDMABuf(I2S_DEV, (u8*)tx_buf, (u8*)rx_buf);
for (i=0;i<page_num;i++) {
I2S_SetTxPageAddr(i, (uint32_t)(tx_buf + ((page_size) * i)));
I2S_SetRxPageAddr(i, (uint32_t)(rx_buf + ((page_size) * i)));
}
}
/**
* @brief Sets TX interrupt handler.
* @param obj: i2s object define in application software.
* @param handler: TX interrupt callback function.
* @param id: TX interrupt callback function parameter.
* @retval none
*/
void i2s_tx_irq_handler(i2s_t *obj, i2s_irq_handler handler, uint32_t id)
{
//uint8_t i2s_idx = obj->i2s_idx;
I2SUserCB.TxCCB = handler;
I2SUserCB.TxCBId = id;
}
/**
* @brief Sets RX interrupt handler.
* @param obj: i2s object define in application software.
* @param handler: RX interrupt callback function.
* @param id: RX interrupt callback function parameter.
* @retval none
*/
void i2s_rx_irq_handler(i2s_t *obj, i2s_irq_handler handler, uint32_t id)
{
//uint8_t i2s_idx = obj->i2s_idx;
I2SUserCB.RxCCB = handler;
I2SUserCB.RxCBId = id;
}
/**
* @brief Sets i2s data transfer direction.
* @param obj: i2s object define in application software.
* @param trx_type: transfer direction.
* This parameter can be one of the following values:
* @arg I2S_DIR_RX: Rx receive direction
* @arg I2S_DIR_TX: Tx transmission direction
* @arg I2S_DIR_TXRX: Tx & Rx bi-direction
* @retval none
*/
void i2s_set_direction(i2s_t *obj, int trx_type)
{
obj->direction = trx_type;
I2SInitStruct.I2S_TRxAct = trx_type;
I2S_SetDirection(I2S_DEV, trx_type);
if (trx_type == I2S_DIR_TX) {
I2S_RxDmaCmd(I2S_DEV, DISABLE);
} else if ((trx_type == I2S_DIR_TXRX) ||(trx_type == I2S_DIR_RX) ) {
I2S_RxDmaCmd(I2S_DEV, ENABLE);
}
}
/**
* @brief Sets i2s channel number, sample rate, word length.
* @param obj: i2s object define in application software.
* @param channel_num: this parameter can be one of the following values:
* @arg CH_STEREO: stereo channel
* @arg CH_MONO: mono channel
* @param rate: this parameter can be one of the following values:
* @arg SR_8KHZ: sample rate is 8kHz
* @arg SR_16KHZ: sample rate is 16kHz
* @arg SR_24KHZ: sample rate is 24kHz
* @arg SR_32KHZ: sample rate is 32kHz
* @arg SR_48KHZ: sample rate is 48kHz
* @arg SR_96KHZ: sample rate is 96kHz
* @arg SR_7p35KHZ: sample rate is 7.35kHz
* @arg SR_14p7KHZ: sample rate is 14.7kHz
* @arg SR_22p05KHZ: sample rate is 22.05kHz
* @arg SR_29p4KHZ: sample rate is 29.4kHz
* @arg SR_44p1KHZ: sample rate is 44.1kHz
* @arg SR_88p2KHZ: sample rate is 88.2kHz
* @param word_len: this parameter can be one of the following values:
* @arg WL_16b: sample bit is 16 bit
* @arg WL_24b: sample bit is 24 bit
* @retval none
*/
void i2s_set_param(i2s_t *obj, int channel_num, int rate, int word_len)
{
obj->channel_num = channel_num;
obj->sampling_rate = rate;
obj->word_length = word_len;
I2SInitStruct.I2S_ChNum = channel_num;
I2SInitStruct.I2S_Rate = rate;
I2SInitStruct.I2S_WordLen = word_len;
I2S_SetChNum(I2S_DEV, I2SInitStruct.I2S_ChNum);
I2S_SetRate(I2S_DEV, rate);
I2S_SetWordLen(I2S_DEV, I2SInitStruct.I2S_WordLen);
}
/**
* @brief Deinitializes the I2S device, include function/interrupt/I2S registers.
* @param obj: i2s object define in application software.
* @retval none
*/
void i2s_deinit(i2s_t *obj)
{
//uint8_t i2s_idx = obj->i2s_idx;
IRQn_Type IrqNum = I2S0_PCM0_IRQ;
/*I2S Interrupt DeInitialization*/
InterruptDis(IrqNum);
InterruptUnRegister(IrqNum);
/*I2S Disable Module*/
I2S_INTConfig(I2S_DEV, 0, 0);
I2S_Cmd(I2S_DEV, DISABLE);
i2s_sw_reset();
}
/**
* @brief Gets current tx page address.
* @param obj: i2s object define in application software.
* @retval address of current tx page or NULL
* @note current page own by cpu, return address of current tx page
* @note current page own by i2s, return NULL
*/
int* i2s_get_tx_page(i2s_t *obj)
{
//uint8_t i2s_idx = obj->i2s_idx;
u8 cur_tx_page;
cur_tx_page = I2S_GetTxPage(I2S_DEV);
if (!I2S_TxPageBusy(I2S_DEV, cur_tx_page)) {
return ((int*)I2S_GetTxPageAddr(cur_tx_page));
} else {
return NULL;
}
}
/**
* @brief Sets current tx page own by i2s.
* @param obj: i2s object define in application software.
* @param pbuf: tx buffer adderss.
* @retval none
*/
void i2s_send_page(i2s_t *obj, uint32_t *pbuf)
{
u32 cur_tx_page;
cur_tx_page = I2S_GetTxPage(I2S_DEV);
if (I2S_GetTxPageAddr(cur_tx_page) != (uint32_t)pbuf)
DBG_8195A("%s: tx buffer not match cur_tx_page \n", __func__);
I2S_TxPageDMA_EN(I2S_DEV, cur_tx_page);
}
/**
* @brief Sets current rx page own by i2s.
* @param obj: i2s object define in application software.
* @retval none
*/
void i2s_recv_page(i2s_t *obj)
{
u32 cur_rx_page;
cur_rx_page = I2S_GetRxPage(I2S_DEV);
if ((I2S_DEV->IS_RX_PAGE_OWN[cur_rx_page] & BIT(31)) == 0) {
I2S_RxPageDMA_EN(I2S_DEV,cur_rx_page);
} else {
//DBG_8195A("i2s_recv_page: re-enable\r\n");
}
}
/**
* @brief Enable i2s interrupt and function.
* @retval none
*/
void i2s_enable(i2s_t *obj)
{
//uint8_t i2s_idx = obj->i2s_idx;
I2S_Cmd(I2S_DEV, ENABLE);
I2S_INTConfig(I2S_DEV, (I2S_TX_INT_PAGE0_OK|I2S_TX_INT_PAGE1_OK| I2S_TX_INT_PAGE2_OK|I2S_TX_INT_PAGE3_OK),
(I2S_RX_INT_PAGE0_OK|I2S_RX_INT_PAGE1_OK | I2S_RX_INT_PAGE2_OK|I2S_RX_INT_PAGE3_OK));
}
/**
* @brief Disable i2s interrupt and function.
* @retval none
*/
void i2s_disable(i2s_t *obj)
{
//uint8_t i2s_idx = obj->i2s_idx;
I2S_INTConfig(I2S_DEV, 0, 0);
I2S_Cmd(I2S_DEV, DISABLE);
i2s_sw_reset();
}
/******************* (C) COPYRIGHT 2016 Realtek Semiconductor *****END OF FILE****/

View File

@@ -0,0 +1,243 @@
/* mbed Microcontroller Library
*******************************************************************************
* Copyright (c) 2014, Realtek Semiconductor Corp.
* All rights reserved.
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*******************************************************************************
*/
#include "objects.h"
#include "pinmap.h"
#if CONFIG_NFC_NORMAL
#include "nfc_api.h"
/**
* @brief The NFC tag write callback function wrapper
*
* @return None
*
*/
void nfc_tagwrite_callback(PNFC_ADAPTER pNFCAdp, uint32_t page, uint32_t wr_data)
{
nfctag_t *obj;
nfc_write_cb handler;
obj = pNFCAdp->nfc_obj;
handler = (nfc_write_cb)obj->nfc_wr_cb;
if (NULL != handler) {
handler(obj->wr_cb_arg, page, wr_data);
}
}
/**
* @brief The NFC tag read callback function wrapper
*
* @return None
*
*/
void nfc_event_callback(PNFC_ADAPTER pNFCAdp, uint32_t event)
{
nfctag_t *obj;
nfc_event_cb handler;
obj = pNFCAdp->nfc_obj;
handler = (nfc_event_cb)obj->nfc_ev_cb;
if (NULL != handler) {
if (obj->event_mask & event) {
handler(obj->ev_cb_arg, event);
}
}
}
/**
* @brief The NFC tag read callback function wrapper
*
* @return None
*
*/
void nfc_tagread_callback(PNFC_ADAPTER pNFCAdp, uint32_t page)
{
// notify upper layer when read tag page 0 only
if (0 == page) {
nfc_event_callback(pNFCAdp, NFC_EV_READ);
}
}
/**
* @brief The NFC cache read done callback function wrapper
*
* @return None
*
*/
void nfc_cache_read_callback(PNFC_ADAPTER pNFCAdp, uint32_t start_pg, uint32_t *pbuf)
{
nfctag_t *obj;
nfc_write_cb handler;
obj = pNFCAdp->nfc_obj;
handler = (nfc_write_cb)obj->nfc_cache_rd_cb;
if (NULL != handler) {
handler(obj->cache_read_cb_arg, start_pg, (uint32_t)pbuf);
}
}
/**
* @brief To initial NFC tag hardware and resource
*
* @return The result
*
*/
int nfc_init(nfctag_t *obj, uint32_t *pg_init_val)
{
_memset((void *)obj, 0, sizeof(nfctag_t));
HalNFCDmemInit(pg_init_val, NFCTAGLENGTH);
HalNFCInit(&(obj->NFCAdapter));
HalNFCFwDownload();
obj->NFCAdapter.nfc_obj = obj;
obj->pwr_status = NFC_PWR_RUNNING;
return NFC_OK;
}
/**
* @brief To free NFC tag hardware and resource
*
* @return The result
*
*/
int nfc_free(nfctag_t *obj)
{
HalNFCDeinit(&(obj->NFCAdapter));
return NFC_OK;
}
/**
* @brief To register the callback function for NFC read occurred
*
* @return None
*
*/
void nfc_read(nfctag_t *obj, nfc_read_cb handler, void *arg)
{
obj->nfc_rd_cb = (void *)handler;
obj->rd_cb_arg = arg;
}
/**
* @brief To register the callback function for NFC write occurred
*
* @return None
*
*/
void nfc_write(nfctag_t *obj, nfc_write_cb handler, void *arg)
{
obj->nfc_wr_cb = (void *)handler;
obj->wr_cb_arg = arg;
}
/**
* @brief To register the callback function for NFC events occurred
* and the event mask
*
* @return None
*
*/
void nfc_event(nfctag_t *obj, nfc_event_cb handler, void *arg, unsigned int event_mask)
{
obj->nfc_ev_cb = (void *)handler;
obj->ev_cb_arg = arg;
obj->event_mask = event_mask;
}
/**
* @brief To set a new power mode to the NFC device
*
* @return The result
*
*/
int nfc_power(nfctag_t *obj, int pwr_mode, int wake_event)
{
// TODO:
return NFC_OK;
}
/**
* @brief to update the NFC read cache. The data in the NFC read cache
* buffer will be transmitted out when NFC read occurred
*
* @return The result
*
*/
int nfc_cache_write(nfctag_t *obj, uint32_t *tbuf, unsigned int spage, unsigned int pg_num)
{
u8 remain_pg;
u8 pg_offset=0;
u8 i;
if ((spage+pg_num) > NFC_MAX_CACHE_PAGE_NUM) {
return NFC_ERROR;
}
remain_pg = pg_num;
while (remain_pg > 0) {
if (remain_pg >= 4) {
A2NWriteCatch (&obj->NFCAdapter, (spage+pg_offset), 4, (u32*)(&tbuf[pg_offset]));
remain_pg -= 4;
pg_offset += 4;
}
else {
for(i=0;i<remain_pg;i++) {
A2NWriteCatch (&obj->NFCAdapter, (spage+pg_offset), 1, (u32*)(&tbuf[pg_offset]));
pg_offset++;
}
remain_pg = 0;
}
}
return NFC_OK;
}
/**
* @brief To get current NFC status
*
* @return The result
*
*/
int nfc_cache_raed(nfctag_t *obj, nfc_cache_read_cb handler,
void *arg, unsigned int start_pg)
{
if (start_pg > NFC_MAX_CACHE_PAGE_NUM) {
return NFC_ERROR;
}
obj->nfc_cache_rd_cb = (void *)handler;
obj->cache_read_cb_arg = arg;
A2NReadCatch(&(obj->NFCAdapter), (u8)start_pg);
return NFC_OK;
}
/**
* @brief to read back the NFC read cache.
*
* @return The result
*
*/
int nfc_status(nfctag_t *obj)
{
// TODO:
return (obj->pwr_status);
}
#endif

View File

@@ -0,0 +1,106 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_OBJECTS_H
#define MBED_OBJECTS_H
#include "cmsis.h"
#include "PortNames.h"
#include "PeripheralNames.h"
#include "PinNames.h"
#include "rtl8710b.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct gpio_irq_s {
PinName pin;
} gpio_irq_t;
typedef struct gpio_s {
PinName pin;
} gpio_t;
struct port_s {
PortName port;
uint32_t mask;
};
struct serial_s {
uint8_t uart_idx;
uint32_t tx_len;
uint32_t rx_len;
};
struct spi_s {
/* user variables */
uint32_t spi_idx;
/* internal variables */
uint32_t irq_handler;
uint32_t irq_id;
uint32_t state;
uint8_t sclk;
uint32_t bus_tx_done_handler;
uint32_t bus_tx_done_irq_id;
};
struct pwmout_s {
uint8_t pwm_idx;
uint32_t period;//in us
float pulse;//in us
};
struct i2c_s {
uint32_t i2c_idx;
I2C_TypeDef * I2Cx;
};
struct flash_s {
FLASH_InitTypeDef SpicInitPara;
};
struct analogin_s {
uint8_t adc_idx;
};
struct gtimer_s {
void *handler;
uint32_t hid;
uint8_t timer_id;
uint8_t is_periodcal;
};
struct i2s_s {
uint8_t i2s_idx;
uint8_t sampling_rate;
uint8_t channel_num;
uint8_t word_length;
uint8_t direction;
};
struct gdma_s {
u8 index;
u8 ch_num;
IRQ_FUN user_cb;
u32 user_cb_data;
};
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,75 @@
/* mbed Microcontroller Library
*******************************************************************************
* Copyright (c) 2014, Realtek Semiconductor Corp.
* All rights reserved.
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*******************************************************************************
*/
#include "objects.h"
#include "pinmap.h"
/**
* Configure pin enable and function
*/
void pin_function(PinName pin, int function)
{
u8 dword_index = 0;
u8 shift_bits = 0;
u32 Temp = 0;
assert_param(pin != NC);
/* 16bit per one pad */
/* get PADCTR dword inedex*/
dword_index = pin >> 1;
/* get shift_bits in PADCTR dword */
shift_bits = (pin % 2) * 16;
/* get PADCTR */
Temp = PINMUX->PADCTR[dword_index];
/* clear Pin_Num PADCTR */
if(shift_bits){
Temp &= 0x0000FFFF;
}else{
Temp &= 0xFFFF0000;
}
/* set needs function */
Temp |= ((function & 0xFF) | BIT(8)) << shift_bits; /* bit8 is close pad power down */
/* set PADCTR register */
PINMUX->PADCTR[dword_index] = Temp;
}
/**
* Configure pin pull-up/pull-down
*/
void pin_mode(PinName pin, PinMode mode)
{
u8 pull_type;
switch (mode) {
case PullNone:
pull_type = GPIO_PuPd_NOPULL;
break;
case PullDown:
pull_type = GPIO_PuPd_DOWN;
break;
case PullUp:
pull_type = GPIO_PuPd_UP;
break;
default:
pull_type = GPIO_PuPd_NOPULL;
break;
}
PAD_PullCtrl((u32)pin, (u32)pull_type);
}

View File

@@ -0,0 +1,78 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "basic_types.h"
#include "diag.h"
#include "pinmap.h"
void pinmap_pinout(PinName pin, const PinMap *map)
{
if (pin == NC)
return;
while (map->pin != NC) {
if (map->pin == pin) {
pin_mode(pin, PullNone);
pin_function(pin, map->function);
return;
}
map++;
}
}
uint32_t pinmap_merge(uint32_t a, uint32_t b)
{
/* both are the same (inc both NC) */
if (a == b)
return a;
/* one (or both) is not connected */
if (a == (uint32_t)NC)
return b;
if (b == (uint32_t)NC)
return a;
/* mis-match error case */
DBG_8195A("%s: pinmap mis-match\n", __FUNCTION__);
return (uint32_t)NC;
}
uint32_t pinmap_find_peripheral(PinName pin, const PinMap* map)
{
while (map->pin != NC) {
if (map->pin == pin) {
return map->peripheral;
}
map++;
}
return (uint32_t)NC;
}
uint32_t pinmap_peripheral(PinName pin, const PinMap* map)
{
uint32_t peripheral = (uint32_t)NC;
if (pin == (PinName)NC)
return (uint32_t)NC;
peripheral = pinmap_find_peripheral(pin, map);
if ((uint32_t)NC == peripheral) {// no mapping available
DBG_8195A("%s: pinmap not found for peripheral\n", __FUNCTION__);
}
return peripheral;
}

View File

@@ -0,0 +1,136 @@
/** mbed Microcontroller Library
******************************************************************************
* @file port_api.c
* @author
* @version V1.0.0
* @date 2016-08-01
* @brief This file provides mbed API for GPIO PORT.
******************************************************************************
* @attention
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
******************************************************************************
*/
#include "objects.h"
#include "port_api.h"
#include "pinmap.h"
#include "gpio_api.h"
#include "PinNames.h"
//#include "mbed_error.h"
#define GPIO_PORT_NUM 2
/**
* @brief Get GPIO port pin name
* @param port: PortName according to pinmux spec, this parameter can be one of the following values:
* @arg PortA: port number is A, has 32 pins
* @arg PortB: port number is B, has 7 pins
* @param pin_n: pin number.
* @note pin_n must be set to a value in the 0~31 range when PortA
* @note pin_n must be set to a value in the 0~6 range when PortB
* @retval none
*/
PinName port_pin(PortName port, int pin_n)
{
return (PinName)(port << 5 | pin_n);
}
/**
* @brief Initializes the GPIO device port, include data direction registers.
* @param obj: gpio port object define in application software.
* @param port: PortName according to pinmux spec, this parameter can be one of the following values:
* @arg PortA: port A, has 32 pins
* @arg PortB: port B, has 7 pins
* @param mask: One bit one gpio pin, select one or multiple pins of the specified port.
* @param dir: gpio port direction, this parameter can be one of the following values:
* @arg PIN_INPUT: port pins are input
* @arg PIN_OUTPUT: port pins are output
* @retval none
*/
void port_init(port_t *obj, PortName port, int mask, PinDirection dir)
{
u32 i;
RCC_PeriphClockCmd(APBPeriph_GPIO, APBPeriph_GPIO_CLOCK, ENABLE);
assert_param(port < GPIO_PORT_NUM);
obj->port = port;
obj->mask = mask;
port_dir(obj, dir);
}
/**
* @brief Set GPIO port pins data direction.
* @param obj: gpio port object define in application software.
* @param dir: this parameter can be one of the following values:
* @arg PIN_INPUT: port pins are input
* @arg PIN_OUTPUT: port pins are output
* @retval none
*/
void port_dir(port_t *obj, PinDirection dir)
{
if (dir == PIN_OUTPUT) {
GPIO_PortDirection(obj->port, obj->mask, GPIO_Mode_OUT);
} else {
GPIO_PortDirection(obj->port, obj->mask, GPIO_Mode_IN);
}
}
/**
* @brief Configure GPIO port pins pull up/pull down.
* @param obj: gpio port object define in application software.
* @param mode: this parameter can be one of the following values:
* @arg PullNone: HighZ
* @arg PullDown: pull down
* @arg PullUp: pull up
* @retval none
*/
void port_mode(port_t *obj, PinMode mode)
{
uint32_t pin_idx;
uint32_t max_num = 0;
if (obj->port == PORT_A) {
max_num = 32;
} else {
max_num = 7;
}
for (pin_idx = 0; pin_idx < max_num; pin_idx++) {
if (obj->mask & BIT(pin_idx)) {
/* PinName = (obj->port << 5 | pin_idx) */
pin_mode((obj->port << 5 | pin_idx), mode);
}
}
}
/**
* @brief Sets value to the selected port pins.
* @param obj: gpio port object define in application software.
* @param value: One bit one gpio pin, set value to one or multiple pins of the specified port.
* @note corresponding bit is 1, pin state set to high; corresponding bit is 0, pin state set to low
* @retval none
*/
void port_write(port_t *obj, int value)
{
GPIO_PortWrite(obj->port, obj->mask, value);
}
/**
* @brief Reads the specified gpio port pins.
* @param obj: gpio port object define in application software.
* @retval state of the specified gpio port pins
* @note corresponding bit is 1, pin state is high; corresponding bit is 0, pin state is low
*/
int port_read(port_t *obj)
{
u32 value = GPIO_PortRead(obj->port, obj->mask);
return value;
}
/******************* (C) COPYRIGHT 2016 Realtek Semiconductor *****END OF FILE****/

View File

@@ -0,0 +1,294 @@
/** mbed Microcontroller Library
******************************************************************************
* @file pwmout_api.c
* @author
* @version V1.0.0
* @date 2016-08-01
* @brief This file provides mbed API for PWM.
******************************************************************************
* @attention
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
******************************************************************************
*/
#include "device.h"
#include "objects.h"
#include "pinmap.h"
#include "pwmout_api.h"
#define PWM_TIMER 5
#define XTAL_CLK_MHz (XTAL_ClkGet()/1000000)
u32 pin2chan[13][2] = {
{PA_23, 0},
{PA_15, 1},
{PA_0 , 2},
{PA_30, 3},
{PA_13, 4},
{PA_22, 5},
{PA_14, 0},
{PA_16, 1},
{PA_17, 2},
{PA_12, 3},
{PA_5 , 4},
{PA_21, 3},
{PA_29, 4}
};
u8 timer5_start = 0;
u8 ch_start[6] = {0};
u8 prescaler = 0;
/**
* @brief Return PWM channel number according to pin name.
* @param pin: The pin to be told.
* @retval value: PWM channel number corresponding to the pin.
*/
u32 pwmout_pin2chan(PinName pin)
{
int i = 0;
for(;i < 13;i++){
if(pin2chan[i][0] == pin){
return pin2chan[i][1];
}
}
return NC;
}
/**
* @brief Initializes the TIM5 device, include TIM5 registers and function.
* @param obj: PWM object define in application software.
* @retval none
*/
void pwmout_timer5_init(pwmout_t* obj)
{
RTIM_TimeBaseInitTypeDef TIM_InitStruct;
RTIM_TimeBaseStructInit(&TIM_InitStruct);
TIM_InitStruct.TIM_Idx = PWM_TIMER;
RTIM_TimeBaseInit(TIM5, &TIM_InitStruct, TIMER5_IRQ, NULL, (u32)&TIM_InitStruct);
RTIM_Cmd(TIM5, ENABLE);
timer5_start = 1;
}
/**
* @brief Initializes the PWM function/registers of the specified pin with default parameters.
* @param obj: PWM object define in application software.
* @param pin: the pinname of specified channel to be set.
* @retval none
* @note
* - default period: 1638us
* - default pulse width: 102us
* - default duty cycle: 6.227%
*/
void pwmout_init(pwmout_t* obj, PinName pin)
{
u32 pwm_chan;
TIM_CCInitTypeDef TIM_CCInitStruct;
pwm_chan = pwmout_pin2chan(pin);
if(pwm_chan == NC)
DBG_8195A("PinName error: pwm channel of PinName doesn't exist!\n");
if(!timer5_start)
pwmout_timer5_init(obj);
RTIM_CCStructInit(&TIM_CCInitStruct);
RTIM_CCxInit(TIM5, &TIM_CCInitStruct, pwm_chan);
RTIM_CCxCmd(TIM5, pwm_chan, TIM_CCx_Enable);
/* loguart may close here */
Pinmux_Config(pin, PINMUX_FUNCTION_PWM);
ch_start[pwm_chan] = 1;
obj->pwm_idx = pwm_chan;
obj->period = 0x10000 * (prescaler + 1) / XTAL_CLK_MHz;
obj->pulse = 0x1000 * (prescaler + 1) / XTAL_CLK_MHz;
}
/**
* @brief Deinitializes the PWM device of the specified channel.
* @param obj: PWM object define in application software.
* @retval none
* @note If all channels are released, TIM5 will also be disabled.
*/
void pwmout_free(pwmout_t* obj)
{
/* disable pwm channel */
int i = obj->pwm_idx;
if(ch_start[i]){
ch_start[i] = 0;
RTIM_CCxCmd(TIM5, obj->pwm_idx, TIM_CCx_Disable);
}
/* stop timer5 if no pwm channels starts */
for(i = 0;i < 6;i++){
if(ch_start[i]){
return;
}
}
RTIM_Cmd(TIM5, DISABLE);
timer5_start = 0;
return;
}
/**
* @brief Set the duty cycle of the specified channel.
* @param obj: PWM object define in application software.
* @param value: The duty cycle value to be set.
* @retval none
*/
void pwmout_write(pwmout_t* obj, float percent) //write duty-cycle
{
u32 ccrx;
if (percent < (float)0.0) {
percent = 0.0;
}
else if (percent > (float)1.0) {
percent = 1.0;
}
obj->pulse = (percent * obj->period);
ccrx = (u32)(obj->pulse * XTAL_CLK_MHz / (prescaler + 1)) & 0x0000ffff;
RTIM_CCRxSet(TIM5, ccrx, obj->pwm_idx);
}
/**
* @brief Get the duty cycle value of the specified channel.
* @param obj: PWM object define in application software.
* @retval value: the duty cycle value of the specified channel.
*/
float pwmout_read(pwmout_t* obj) //read duty-cycle
{
float value = 0;
if (obj->period > 0) {
value = (float)obj->pulse / (float)obj->period;
}
return ((value > 1.0) ? (1.0) : (value));
}
/**
* @brief Set the period of the specified channel in seconds.
* @param obj: PWM object define in application software.
* @param seconds: The period value to be set in seconds.
* @retval none
*/
void pwmout_period(pwmout_t* obj, float seconds)
{
pwmout_period_us(obj, (int)(seconds * 1000000.0f));
}
/**
* @brief Set the period of the specified channel in millseconds.
* @param obj: PWM object define in application software.
* @param ms: The period value to be set in millseconds.
* @retval none
*/
void pwmout_period_ms(pwmout_t* obj, int ms)
{
pwmout_period_us(obj, (int)(ms * 1000));
}
/**
* @brief Set the period of the specified channel in microseconds.
* @param obj: PWM object define in application software.
* @param us: The period value to be set in microseconds.
* @retval none
*/
void pwmout_period_us(pwmout_t* obj, int us)
{
u32 arr;
float dc = pwmout_read(obj);
u32 tmp = us * XTAL_CLK_MHz / (prescaler + 1);
if(tmp > 0x10000){
prescaler = us * XTAL_CLK_MHz / 0x10000;
RTIM_PrescalerConfig(TIM5, prescaler, TIM_PSCReloadMode_Update);
}
obj->period = us;
arr = us * XTAL_CLK_MHz / (prescaler + 1) - 1;
RTIM_ChangePeriod(TIM5, arr);
pwmout_write(obj, dc);
}
/**
* @brief Set the pulse width of the specified channel in seconds.
* @param obj: PWM object define in application software.
* @param seconds: The pulse width value to be set in seconds.
* @retval none
*/
void pwmout_pulsewidth(pwmout_t* obj, float seconds)
{
pwmout_pulsewidth_us(obj, (int)(seconds * 1000000.0f));
}
/**
* @brief Set the pulse width of the specified channel in milliseconds.
* @param obj: PWM object define in application software.
* @param ms: The pulse width value to be set in milliseconds.
* @retval none
*/
void pwmout_pulsewidth_ms(pwmout_t* obj, int ms)
{
pwmout_pulsewidth_us(obj, ms * 1000);
}
/**
* @brief Set the pulse width of the specified channel in microseconds.
* @param obj: PWM object define in application software.
* @param us: The pulse width value to be set in microseconds.
* @retval none
*/
void pwmout_pulsewidth_us(pwmout_t* obj, int us)
{
u32 ccrx;
obj->pulse = (float)us;
ccrx = (u32)(obj->pulse * XTAL_CLK_MHz / (prescaler + 1)) & 0x0000ffff;
RTIM_CCRxSet(TIM5, ccrx, obj->pwm_idx);
}
void pwmout_start(pwmout_t* obj)
{
RTIM_CCxCmd(TIM5, obj->pwm_idx, TIM_CCx_Enable);
}
void pwmout_stop(pwmout_t* obj)
{
RTIM_CCxCmd(TIM5, obj->pwm_idx, TIM_CCx_Disable);
}
/**
* @brief Set the polarity of the specified PWM channel.
* @param obj: PWM object define in application software.
* @param polarity:
0: Output low when timer count < setvalue.
1: Output high when timer count < setvalue.(default)
* note: use after setting duty cycle or pulse width.
* @retval none
*/
void pwmout_set_polarity(pwmout_t* obj, int polarity)
{
if(0 == polarity)
RTIM_CCxPolarityConfig(TIM5, TIM_CCPolarity_Low, obj->pwm_idx);
else
RTIM_CCxPolarityConfig(TIM5, TIM_CCPolarity_High, obj->pwm_idx);
}

View File

@@ -0,0 +1,358 @@
/** mbed Microcontroller Library
******************************************************************************
* @file rtc_api.c
* @author
* @version V1.0.0
* @date 2016-08-01
* @brief This file provides mbed API for RTC.
******************************************************************************
* @attention
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
******************************************************************************
*/
#include "rtc_api.h"
#include <time.h>
#include "timer_api.h"
static struct tm rtc_timeinfo;
static int rtc_en = 0;
static alarm_irq_handler rtc_alarm_handler;
const static u8 dim[12] = {
31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
/**
* @brief This function is used to tell a year is a leap year or not.
* @param year: The year need to be told.
* @retval value:
* - 1: This year is leap year.
* - 0: This year is not leap year.
*/
static inline bool is_leap_year(unsigned int year)
{
u32 full_year = year + 1900;
return (!(full_year % 4) && (full_year % 100)) || !(full_year % 400);
}
/**
* @brief This function tells how many days in a month of a year.
* @param year: Specified year
* @param month: Specified month
* @retval value: Number of days in the month.
*/
static u8 days_in_month (u8 month, u8 year)
{
u8 ret = dim[month];
if (ret == 0)
ret = is_leap_year (year) ? 29 : 28;
return ret;
}
/**
* @brief This function is used to calculate month and day of month according to year and day of the year.
* @param year: years since 1900.
* @param yday: day of the year.
* @param mon: pointer to the variable which stores month, the value can be 0-11
* @param mday: pointer to the variable which stores day of month, the value can be 1-31
* @retval value: none
*/
static void rtc_calculate_mday(int year, int yday, int* mon, int* mday)
{
int t_mon = -1, t_yday = yday + 1;
while(t_yday > 0){
t_mon ++;
t_yday -= days_in_month(t_mon, year);
}
*mon = t_mon;
*mday = t_yday + days_in_month(t_mon, year);
}
/**
* @brief This function is used to calculate day of week according to date.
* @param year: years since 1900.
* @param mon: which month of the year
* @param mday: pointer to the variable which store day of month
* @param wday: pointer to the variable which store day of week, the value can be 0-6, and 0 means Sunday
* @retval value: none
*/
static void rtc_calculate_wday(int year, int mon, int mday, int* wday)
{
int t_year = year + 1900, t_mon = mon + 1;
if(t_mon == 1 || t_mon == 2){
t_year --;
t_mon += 12;
}
int c = t_year / 100;
int y = t_year % 100;
int week = (c / 4) - 2 * c + (y + y / 4) + (26 * (t_mon + 1) / 10) + mday -1;
while(week < 0){
week += 7;
}
week %= 7;
*wday = week;
}
/**
* @brief This function is used to restore rtc_timeinfo global variable whose value is lost after system reset.
* @param none
* @retval value: none
*/
static void rtc_restore_timeinfo(void)
{
u32 value, days_in_year;
RTC_TimeTypeDef RTC_TimeStruct;
RTC_GetTime(RTC_Format_BIN, &RTC_TimeStruct);
rtc_timeinfo.tm_sec = RTC_TimeStruct.RTC_Seconds;
rtc_timeinfo.tm_min = RTC_TimeStruct.RTC_Minutes;
rtc_timeinfo.tm_hour = RTC_TimeStruct.RTC_Hours;
rtc_timeinfo.tm_yday = RTC_TimeStruct.RTC_Days;
value = BKUP_Read(0);
rtc_timeinfo.tm_year = (value & BIT_RTC_BACKUP) >> 8;
days_in_year = (is_leap_year(rtc_timeinfo.tm_year) ? 366 : 365);
if(rtc_timeinfo.tm_yday > days_in_year - 1){
rtc_timeinfo.tm_year ++;
rtc_timeinfo.tm_yday -= days_in_year;
/* over one year, update days in RTC_TR */
RTC_TimeStruct.RTC_Days = rtc_timeinfo.tm_yday;
RTC_SetTime(RTC_Format_BIN, &RTC_TimeStruct);
}
rtc_calculate_mday(rtc_timeinfo.tm_year, rtc_timeinfo.tm_yday, &rtc_timeinfo.tm_mon, &rtc_timeinfo.tm_mday);
rtc_calculate_wday(rtc_timeinfo.tm_year, rtc_timeinfo.tm_mon, rtc_timeinfo.tm_mday, &rtc_timeinfo.tm_wday);
}
/**
* @brief This function is used to backup tm_year parameter in rtc_timeinfo global variable before system reset.
* @param none
* @retval value: none
*/
void rtc_backup_timeinfo(void)
{
u32 value = BKUP_Read(0);
value = (value & ~BIT_RTC_BACKUP) | (rtc_timeinfo.tm_year << 8);
BKUP_Write(0, value);
BKUP_Set(0, BIT_RTC_RESTORE);
}
/**
* @brief Initializes the RTC device, include clock, RTC registers and function.
* @param none
* @retval none
*/
void rtc_init(void)
{
RTC_InitTypeDef RTC_InitStruct;
RTC_ClokSource(0);
RTC_StructInit(&RTC_InitStruct);
RTC_InitStruct.RTC_HourFormat = RTC_HourFormat_24;
RTC_Init(&RTC_InitStruct);
/* 32760 need add need add 15 cycles (256Hz) every 4 min*/
//RTC_SmoothCalibConfig(RTC_CalibSign_Positive, 15,
// RTC_CalibPeriod_4MIN, RTC_Calib_Enable);
rtc_en = 1;
}
/**
* @brief Deinitializes the RTC device.
* @param none
* @retval none
*/
void rtc_free(void)
{
rtc_en = 0;
rtc_alarm_handler = NULL;
}
/**
* @brief This function tells whether RTC is enabled or not.
* @param none
* @retval status:
* - 1: RTC is enable.
* - 0: RTC is disable.
*/
int rtc_isenabled(void)
{
return rtc_en;
}
/**
* @brief Set the specified timestamp in seconds to RTC.
* @param t: Seconds from 1970.1.1 00:00:00 to specified data and time
* which is to be set.
* @retval none
*/
void rtc_write(time_t t)
{
/* Convert the time in to a tm*/
struct tm *timeinfo = localtime(&t);
RTC_TimeTypeDef RTC_TimeStruct;
BKUP_Clear(0, BIT_RTC_RESTORE);
/*set time in RTC */
RTC_TimeStruct.RTC_H12_PMAM = RTC_H12_AM;
RTC_TimeStruct.RTC_Days = timeinfo->tm_yday;
RTC_TimeStruct.RTC_Hours = timeinfo->tm_hour;
RTC_TimeStruct.RTC_Minutes = timeinfo->tm_min;
RTC_TimeStruct.RTC_Seconds = timeinfo->tm_sec;
RTC_SetTime(RTC_Format_BIN, &RTC_TimeStruct);
/* Set rtc_timeinfo*/
_memcpy((void*)&rtc_timeinfo, (void*)timeinfo, sizeof(struct tm));
}
/**
* @brief Get current timestamp in seconds from RTC.
* @param none
* @retval value: The current timestamp in seconds which is calculated from
* 1970.1.1 00:00:00.
*/
time_t rtc_read(void)
{
time_t t;
struct tm tm_temp;
RTC_TimeTypeDef RTC_TimeStruct;
u32 delta_days = 0;
if(BKUP_Read(0) & BIT_RTC_RESTORE){
rtc_restore_timeinfo();
BKUP_Clear(0, BIT_RTC_RESTORE);
}
_memcpy((void*)&tm_temp, (void*)&rtc_timeinfo, sizeof(struct tm));
/*hour, min, sec get from RTC*/
RTC_GetTime(RTC_Format_BIN, &RTC_TimeStruct);
tm_temp.tm_sec = RTC_TimeStruct.RTC_Seconds;
tm_temp.tm_min = RTC_TimeStruct.RTC_Minutes;
tm_temp.tm_hour = RTC_TimeStruct.RTC_Hours;
/* calculate how many days later from last time update rtc_timeinfo */
delta_days = RTC_TimeStruct.RTC_Days - tm_temp.tm_yday;
/* calculate wday, mday, yday, mon, year*/
tm_temp.tm_wday += delta_days;
if(tm_temp.tm_wday >= 7){
tm_temp.tm_wday = tm_temp.tm_wday % 7;
}
tm_temp.tm_yday += delta_days;
tm_temp.tm_mday += delta_days;
while(tm_temp.tm_mday > days_in_month(tm_temp.tm_mon, tm_temp.tm_year)){
tm_temp.tm_mday -= days_in_month(tm_temp.tm_mon, tm_temp.tm_year);
tm_temp.tm_mon++;
if(tm_temp.tm_mon >= 12){
tm_temp.tm_mon -= 12;
tm_temp.tm_yday -= is_leap_year(tm_temp.tm_year) ? 366 : 365;
tm_temp.tm_year ++;
/* over one year, update days in RTC_TR */
RTC_TimeStruct.RTC_Days = tm_temp.tm_yday;
RTC_SetTime(RTC_Format_BIN, &RTC_TimeStruct);
/* update rtc_timeinfo */
_memcpy((void*)&rtc_timeinfo, (void*)&tm_temp, sizeof(struct tm));
}
}
/* Convert to timestamp(seconds from 1970.1.1 00:00:00)*/
t = mktime(&tm_temp);
return t;
}
/**
* @brief RTC alarm interrupt handler function.
* @param data: RTC IRQ callback data
* @retval none
*/
void rtc_alarm_intr_handler(u32 data)
{
alarm_irq_handler hdl;
/*clear alarm flag*/
RTC_AlarmClear();
/* execute user handler*/
if(rtc_alarm_handler != NULL){
hdl = (alarm_irq_handler)rtc_alarm_handler;
hdl();
}
/*disable alarm*/
rtc_disable_alarm();
}
/**
* @brief Set the specified RTC Alarm and interrupt.
* @param alarm: alarm object define in application software.
* @param alarmHandler: alarm interrupt callback function.
* @retval status:
* - 1: success
* - Others: failure
*/
u32 rtc_set_alarm(alarm_t *alrm, alarm_irq_handler alarmHandler)
{
RTC_AlarmTypeDef RTC_AlarmStruct_temp;
rtc_alarm_handler = alarmHandler;
/* set alarm */
RTC_AlarmStructInit(&RTC_AlarmStruct_temp);
RTC_AlarmStruct_temp.RTC_AlarmTime.RTC_H12_PMAM = RTC_H12_AM;
RTC_AlarmStruct_temp.RTC_AlarmTime.RTC_Days = alrm->yday;
RTC_AlarmStruct_temp.RTC_AlarmTime.RTC_Hours = alrm->hour;
RTC_AlarmStruct_temp.RTC_AlarmTime.RTC_Minutes = alrm->min;
RTC_AlarmStruct_temp.RTC_AlarmTime.RTC_Seconds = alrm->sec;
RTC_AlarmStruct_temp.RTC_AlarmMask = RTC_AlarmMask_None;
RTC_AlarmStruct_temp.RTC_Alarm2Mask = RTC_Alarm2Mask_None;
RTC_SetAlarm(RTC_Format_BIN, &RTC_AlarmStruct_temp);
RTC_AlarmCmd(ENABLE);
InterruptRegister((IRQ_FUN)rtc_alarm_intr_handler, RTC_IRQ, (u32)alrm, 4);
InterruptEn(RTC_IRQ, 4);
return _TRUE;
}
/**
* @brief Disable RTC Alarm and function.
* @param none
* @retval none
*/
void rtc_disable_alarm(void)
{
InterruptDis(RTC_IRQ);
InterruptUnRegister(RTC_IRQ);
RTC_AlarmCmd(DISABLE);
rtc_alarm_handler = NULL;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,248 @@
/** mbed Microcontroller Library
******************************************************************************
* @file sleep.c
* @author
* @version V1.0.0
* @date 2016-08-01
* @brief This file provides mbed API for SLEEP.
******************************************************************************
* @attention
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
******************************************************************************
*/
#include "sleep_ex_api.h"
#include "cmsis.h"
SLEEP_WAKEUP_EVENT DStandbyWakeupEvent={0};
/**
* @brief To make the system entering the Clock Gated power saving.
* This function just make the system to enter the clock gated
* power saving mode and pending on wake up event waitting.
* The user application need to configure the peripheral to
* generate system wake up event, like GPIO interrupt,
* G-Timer timeout, etc. befor entering power saving mode.
* @param wakeup_event: A bit map of wake up event.
* This parameter can be any combination of the following values:
* @arg SLEEP_WAKEUP_BY_STIMER
* @arg SLEEP_WAKEUP_BY_GPIO_INT
* @arg SLEEP_WAKEUP_BY_WLAN
* @arg SLEEP_WAKEUP_BY_SDIO
* @arg SLEEP_WAKEUP_BY_USB
* @arg SLEEP_WAKEUP_BY_GPIO
* @arg SLEEP_WAKEUP_BY_UART
* @arg SLEEP_WAKEUP_BY_I2C
* @arg SLEEP_WAKEUP_BY_RTC
* @param sleep_duration: the system sleep duration in ms, only valid
* for SLEEP_WAKEUP_BY_STIMER wake up event.
* @retval None
*/
void sleep_ex(uint32_t wakeup_event, uint32_t sleep_duration)
{
__asm volatile( "cpsid i" );
SOCPS_SleepInit();
/* user setting have high priority */
SOCPS_SetWakeEvent(wakeup_event, ENABLE);
if (sleep_duration > 0) {
SOCPS_SET_REGUTIMER(sleep_duration, 0xFFFFFFFF);
}
SOCPS_SleepPG();
}
/**
* @brief To make the system entering the Clock Gated power saving.
* This function just make the system to enter the clock gated
* power saving mode and pending on wake up event waitting.
* The user application need to configure the peripheral to
* generate system wake up event, like GPIO interrupt
* , G-Timer timeout, etc. befor entering power saving mode.
* @param wakeup_event: A bit map of wake up event.
* This parameter can be any combination of the following values:
* @arg SLEEP_WAKEUP_BY_STIMER
* @arg SLEEP_WAKEUP_BY_GPIO_INT
* @arg SLEEP_WAKEUP_BY_WLAN
* @arg SLEEP_WAKEUP_BY_SDIO
* @arg SLEEP_WAKEUP_BY_USB
* @arg SLEEP_WAKEUP_BY_GPIO
* @arg SLEEP_WAKEUP_BY_UART
* @arg SLEEP_WAKEUP_BY_I2C
* @arg SLEEP_WAKEUP_BY_RTC
* @param sleep_duration: the system sleep duration in ms, only valid
* for SLEEP_WAKEUP_BY_STIMER wake up event.
* @param clk_sourec_enable: the option for SCLK on(1)/off(0)
* @param sdr_enable: the option for turn off the SDR controller (1:off, 0:on)
* @retval None
*/
void sleep_ex_selective(uint32_t wakeup_event, uint32_t sleep_duration, uint32_t clk_sourec_enable, uint32_t sdr_enable)
{
sleep_ex(wakeup_event, sleep_duration);
}
/**
* @brief To add a wake up event to wake up the system from the
* deep standby power saving mode.
* @param wakeup_event: A bit map of wake up event.
* This parameter can be any combination of the following values:
* @arg STANDBY_WAKEUP_BY_STIMER
* @arg STANDBY_WAKEUP_BY_GPIO
* @arg STANDBY_WAKEUP_BY_RTC
* @param sleep_duration_ms: the system sleep duration in ms, only valid
* for STANDBY_WAKEUP_BY_STIMER wake up event.
* @param gpio_active: for a GPIO pin to wake up the system by goes high or low
* This parameter can be any combination of the following values:
* @arg WAKEUP_BY_GPIO_NONE
* @arg WAKEUP_BY_GPIO_WAKEUP0_LOW
* @arg WAKEUP_BY_GPIO_WAKEUP0_HIG
* @arg WAKEUP_BY_GPIO_WAKEUP1_LOW
* @arg WAKEUP_BY_GPIO_WAKEUP1_HIG
* @arg WAKEUP_BY_GPIO_WAKEUP2_LOW
* @arg WAKEUP_BY_GPIO_WAKEUP2_HIG
* @arg WAKEUP_BY_GPIO_WAKEUP3_LOW
* @arg WAKEUP_BY_GPIO_WAKEUP3_HIG
* @retval None
*/
void standby_wakeup_event_add(uint32_t wakeup_event, u32 gpio_active)
{
DStandbyWakeupEvent.wakeup_event |= wakeup_event;
if (gpio_active != 0) {
DStandbyWakeupEvent.gpio_option |= gpio_active;
}
}
/**
* @brief To delete a wake up event for wakeing up the system from the
* deep standby power saving mode.
* @param wakeup_event: A bit map of wake up event.
* This parameter can be any combination of the following values:
* @arg STANDBY_WAKEUP_BY_STIMER
* @arg STANDBY_WAKEUP_BY_GPIO
* @arg STANDBY_WAKEUP_BY_RTC
* @retval None
*/
void standby_wakeup_event_del(uint32_t wakeup_event)
{
DStandbyWakeupEvent.wakeup_event &= ~wakeup_event;
}
/**
* @brief To make the system entering the Deep Standby power saving.
* The CPU, memory and part fo peripheral power is off when
* entering deep standby power saving mode. The program needs
* to be reload from the flash at system resume.
* @retval None
*/
void deepstandby_ex(uint32_t sleep_duration_ms)
{
__asm volatile( "cpsid i" );
/* Clear event */
SOCPS_ClearWakeEvent();
/* power mode option: */
SOCPS_DstandbyInit();
if (DStandbyWakeupEvent.wakeup_event & STANDBY_WAKEUP_BY_STIMER) {
DStandbyWakeupEvent.timer_duration = sleep_duration_ms;
}
/* user setting have high priority */
if (DStandbyWakeupEvent.wakeup_event != 0) {
SOCPS_SetWakeEvent(DStandbyWakeupEvent.wakeup_event, ENABLE);
}
if (DStandbyWakeupEvent.gpio_option != WAKEUP_BY_GPIO_NONE) {
SOCPS_WakePinsCtrl(DStandbyWakeupEvent.gpio_option);
}
if (DStandbyWakeupEvent.timer_duration > 0) {
SOCPS_SET_REGUTIMER(DStandbyWakeupEvent.timer_duration, 0xFFFFFFFF);
}
SOCPS_DeepStandby_RAM();
}
/**
* @brief To make the system entering the Deep Sleep power saving mode.
* The CPU, memory and peripheral power is off when entering
* deep sleep power saving mode. The program needs to be reload
* and all peripheral needs be re-configure when system resume.
* @param wakeup_event: A bit map of wake up event.
* This parameter can be any combination of the following values:
* @arg DSLEEP_WAKEUP_BY_TIMER
* @arg DSLEEP_WAKEUP_BY_GPIO
* @param sleep_duration: the system sleep duration in ms, only valid
* for DSLEEP_WAKEUP_BY_TIMER wake up event.
* @retval None
*/
void deepsleep_ex(uint32_t wakeup_event, uint32_t sleep_duration)
{
__asm volatile( "cpsid i" );
SOCPS_DsleepInit();
if (sleep_duration > 0) {
SOCPS_SET_REGUTIMER(sleep_duration, 0xFFFFFFFF);
}
SOCPS_DeepSleep_RAM();
}
/**
* @brief get deep sleep wakeup reason.
* @retval BIT(0): Timer, BIT(2): GPIO
*/
int deepsleep_get_bootup_reason()
{
int Reason = SOCPS_DsleepWakeReason();
if (Reason & BIT_SYSON_DSLP_WTIMER33)
return DSLEEP_WAKEUP_BY_TIMER;
else if (Reason & BIT_SYSON_DSLP_GPIO)
return DSLEEP_WAKEUP_BY_GPIO;
else
return 0;
}
/**
* @brief get deep standby wakeup reason.
* @retval BIT(29): GPIO, BIT(28): REGU A33, BIT(13): RTC, BIT(0): ANA
* @ANA and other return 0
*/
int deepstandby_get_bootup_reason()
{
int Reason = SOCPS_DstandbyWakeReason();
if (Reason & BIT_SYSON_WEVT_GPIO_DSTBY_STS)
return STANDBY_WAKEUP_BY_GPIO;
else if (Reason & BIT_SYSON_WEVT_A33_STS)
return STANDBY_WAKEUP_BY_STIMER;
else if (Reason & BIT_SYSON_WEVT_RTC_STS)
return STANDBY_WAKEUP_BY_RTC;
else
return 0;
}
/**
* @brief get deep standby gpio wakeup reason.
* @retval BIT(24): _PA_18, BIT(25): _PA_5, BIT(26): _PA_22, BIT(27): _PA_23
*/
int deepstandby_get_bootup_reason_gpio() {
int reason_gpio = 0;
reason_gpio = SOCPS_DstandbyWakeReason_gpio();
if (reason_gpio & BIT_SYS_WAKEPIN0_WEVENT_STS)
return WAKUP_0;
else if (reason_gpio & BIT_SYS_WAKEPIN1_WEVENT_STS)
return WAKUP_1;
else if (reason_gpio & BIT_SYS_WAKEPIN2_WEVENT_STS)
return WAKUP_2;
else if (reason_gpio & BIT_SYS_WAKEPIN3_WEVENT_STS)
return WAKUP_3;
}
/******************* (C) COPYRIGHT 2016 Realtek Semiconductor *****END OF FILE****/

View File

@@ -0,0 +1,704 @@
#include "FreeRTOS.h"
#include "ameba_soc.h"
//#include "rtl8710b_sdio.h"
//#include "rtl8711b_tim.h"
#include "spdio_api.h"
#include "rtl8710b_inic.h"
#include "rtl8710b_sdio.h"
#define SPDIO_IRQ_PRIORITY 10
#define SPDIO_TX_BUF_SZ_UNIT 64
#define RX_BD_FREE_TH 5
#define MIN_RX_BD_SEND_PKT 2
#define MAX_RX_BD_BUF_SIZE 16380 // the Maximum size for a RX_BD point to, make it 4-bytes aligned
typedef struct {
u32 Address; /* The TX buffer physical address, it must be 4-bytes aligned */
}SPDIO_TX_BD;
/* The RX Buffer Descriptor format */
typedef struct {
u32 BuffSize:14; /* bit[13:0], RX Buffer Size, Maximum 16384-1 */
u32 LS:1; /* bit[14], is the Last Segment ? */
u32 FS:1; /* bit[15], is the First Segment ? */
u32 Seq:16; /* bit[31:16], The sequence number, it's no use for now */
u32 PhyAddr; /* The RX buffer physical address, it must be 4-bytes aligned */
} SPDIO_RX_BD;
/* the data structer to bind a TX_BD with a TX Packet */
typedef struct {
SPDIO_TX_BD *pTXBD; // Point to the TX_BD buffer
VOID *priv;
u8 isPktEnd; // For a packet over 1 BD , this flag to indicate is this BD contains a packet end
u8 isFree; // is this TX BD free
} SPDIO_TX_BD_HANDLE;
/* the data structer to bind a RX_BD with a RX Packet */
typedef struct {
VOID *priv;
SPDIO_RX_BD *pRXBD; // Point to the RX_BD buffer
INIC_RX_DESC *pRXDESC; // point to the Rx Packet
u8 isPktEnd; // For a packet over 1 BD , this flag to indicate is this BD contains a packet end
u8 isFree; // is this RX BD free (DMA done and its RX packet has been freed)
} SPDIO_RX_BD_HANDLE;
typedef struct {
VOID *spdio_priv; /*Data from User*/
u8 *pTXBDAddr; /* The TX_BD start address */
SPDIO_TX_BD *pTXBDAddrAligned; /* The TX_BD start address, it must be 4-bytes aligned */
SPDIO_TX_BD_HANDLE* pTXBDHdl; /* point to the allocated memory for TX_BD Handle array */
u16 TXBDWPtr; /* The SDIO TX(Host->Device) BD local write index, different with HW maintained write Index. */
u16 TXBDRPtr; /* The SDIO TX(Host->Device) BD read index */
u16 TXBDRPtrReg; /* The SDIO TX(Host->Device) BD read index has been write to HW register */
u8 TxOverFlow;
u8 *pRXBDAddr; /* The RX_BD start address */
SPDIO_RX_BD *pRXBDAddrAligned; /* The RX_BD start address, it must be 8-bytes aligned */
u8 *pRXDESCAddr;
INIC_RX_DESC *pRXDESCAddrAligned;
SPDIO_RX_BD_HANDLE* pRXBDHdl; /* point to the allocated memory for RX_BD Handle array */
u16 RXBDWPtr; /* The SDIO RX(Device->Host) BD write index */
u16 RXBDRPtr; /* The SDIO RX(Device->Host) BD local read index, different with HW maintained Read Index. */
_sema IrqSema; /* Semaphore for SDIO RX, use to wakeup the SDIO RX task */
xTaskHandle xSDIOIrqTaskHandle; /* The handle of the SDIO Task speical for RX, can be used to delte the task */
} HAL_SPDIO_ADAPTER, *PHAL_SPDIO_ADAPTER;
struct spdio_t *g_spdio_priv = NULL;
HAL_SPDIO_ADAPTER gSPDIODev;
PHAL_SPDIO_ADAPTER pgSPDIODev = NULL;
s8 spdio_rx_done_cb(void *padapter, void *data, u16 offset, u16 pktsize, u8 type)
{
struct spdio_buf_t *buf = (struct spdio_buf_t *)data;
struct spdio_t *obj = (struct spdio_t *)padapter;
if(obj)
return obj->rx_done_cb(obj, buf, (u8 *)(buf->buf_addr+offset), pktsize, type);
else
DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "spdio rx done callback function is null!");
return SUCCESS;
}
s8 spdio_tx_done_cb(void *padapter, IN u8 *data)
{
struct spdio_t *obj = (struct spdio_t *)padapter;
struct spdio_buf_t *buf = (struct spdio_buf_t *)data;
if(obj)
return obj->tx_done_cb(obj, buf);
else
DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "spdio tx done callback function is null!");
return SUCCESS;
}
s8 spdio_tx(struct spdio_t *obj, struct spdio_buf_t *pbuf)
{
PHAL_SPDIO_ADAPTER pgSDIODev = obj->priv;
INIC_RX_DESC *pRxDesc;
SPDIO_RX_BD_HANDLE *pRxBdHdl;
SPDIO_RX_BD *pRXBD;
u32 Offset=0;
u16 RxBdWrite=0; // to count how much RX_BD used in a Transaction
u16 RxBdRdPtr= pgSDIODev->RXBDRPtr; // RX_BD read pointer
u32 pkt_size;
#if SDIO_RX_PKT_SIZE_OVER_16K
u8 needed_rxbd_num;
#endif
/* check if RX_BD available */
#if SDIO_RX_PKT_SIZE_OVER_16K
needed_rxbd_num = ((pbuf->buf_size - 1)/MAX_RX_BD_BUF_SIZE) + MIN_RX_BD_SEND_PKT;
#endif
if (RxBdRdPtr != pgSDIODev->RXBDWPtr) {
if (pgSDIODev->RXBDWPtr > RxBdRdPtr) {
#if SDIO_RX_PKT_SIZE_OVER_16K
if ((pgSDIODev->RXBDWPtr - RxBdRdPtr) >= (obj->tx_bd_num - needed_rxbd_num))
#else
if ((pgSDIODev->RXBDWPtr - RxBdRdPtr) >= (obj->tx_bd_num - MIN_RX_BD_SEND_PKT))
#endif
{
DBG_PRINTF(MODULE_SDIO, LEVEL_WARN, "SDIO_Return_Rx_Data: No Available RX_BD, ReadPtr=%d WritePtr=%d\n", \
RxBdRdPtr, pgSDIODev->RXBDWPtr);
return _FALSE;
}
} else {
#if SDIO_RX_PKT_SIZE_OVER_16K
if ((RxBdRdPtr - pgSDIODev->RXBDWPtr) <= needed_rxbd_num)
#else
if ((RxBdRdPtr - pgSDIODev->RXBDWPtr) <= MIN_RX_BD_SEND_PKT)
#endif
{
DBG_PRINTF(MODULE_SDIO, LEVEL_WARN, "SDIO_Return_Rx_Data: No Available RX_BD, ReadPtr=%d WritePtr=%d\n", RxBdRdPtr, pgSDIODev->RXBDWPtr);
return _FALSE;
}
}
}
// TODO: Add RX_DESC before the packet
/* a SDIO RX packet will use at least 2 RX_BD, the 1st one is for RX_Desc,
other RX_BDs are for packet payload */
/* Use a RX_BD to transmit RX_Desc */
pRXBD = pgSDIODev->pRXBDAddrAligned + pgSDIODev->RXBDWPtr; // get the RX_BD head
pRxBdHdl = pgSDIODev->pRXBDHdl + pgSDIODev->RXBDWPtr;
pRxDesc = pRxBdHdl->pRXDESC;
pRxDesc->type = pbuf->type;
pRxDesc->pkt_len = pbuf->buf_size;
pRxDesc->offset = sizeof(INIC_RX_DESC);
if (!pRxBdHdl->isFree) {
DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "SDIO_Return_Rx_Data: Allocated a non-free RX_BD\n");
}
pRxBdHdl->isFree = 0;
pRXBD->FS = 1;
pRXBD->LS = 0;
pRXBD->PhyAddr = (u32)((u8 *)pRxBdHdl->pRXDESC);
pRXBD->BuffSize = sizeof(INIC_RX_DESC);
pRxBdHdl->isPktEnd = 0;
pgSDIODev->RXBDWPtr += 1;
if (pgSDIODev->RXBDWPtr >= obj->tx_bd_num) {
pgSDIODev->RXBDWPtr -= obj->tx_bd_num;
}
RxBdWrite++;
/* Take RX_BD to transmit packet payload */
pkt_size = pbuf->buf_size;
Offset = 0;
do {
pRXBD = pgSDIODev->pRXBDAddrAligned + pgSDIODev->RXBDWPtr; // get the RX_BD head
pRxBdHdl = pgSDIODev->pRXBDHdl + pgSDIODev->RXBDWPtr;
pRxBdHdl->isFree = 0;
pRXBD->FS = 0;
pRXBD->PhyAddr = (u32)((u8 *)pbuf->buf_addr + Offset);
#if SDIO_RX_PKT_SIZE_OVER_16K
if ((pkt_size - Offset) <= MAX_RX_BD_BUF_SIZE) {
pRXBD->BuffSize = pkt_size - Offset;
pRxBdHdl->isPktEnd = 1;
}else {
pRXBD->BuffSize = MAX_RX_BD_BUF_SIZE;
pRxBdHdl->isPktEnd = 0;
DBG_PRINTF(MODULE_SDIO, LEVEL_INFO, "SDIO_Return_Rx_Data: Split RX_BD, Offset=%d PktSize=%d\n", \
Offset, pkt_size);
}
#else
if (pkt_size > MAX_RX_BD_BUF_SIZE) {
// if come to here, please enable "SDIO_RX_PKT_SIZE_OVER_16K"
DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "SDIO_Return_Rx_Data: The Packet Size bigger than 16K\n");
pkt_size = MAX_RX_BD_BUF_SIZE;
}
pRXBD->BuffSize = pkt_size;
pRxBdHdl->priv = (void*)pbuf;
pRxBdHdl->isPktEnd = 1;
#endif
Offset += pRXBD->BuffSize;
// Move the RX_BD Write pointer forward
RxBdWrite++;
pgSDIODev->RXBDWPtr += 1;
if (pgSDIODev->RXBDWPtr >= obj->tx_bd_num) {
pgSDIODev->RXBDWPtr -= obj->tx_bd_num;
}
if (Offset >= pkt_size) {
pRXBD->LS = 1;
}
} while (Offset < pkt_size);
if (RxBdWrite > 0) {
SDIO_RXBD_WPTR_Set(pgSDIODev->RXBDWPtr);
HAL_SDIO_WRITE8(REG_SPDIO_HCI_RX_REQ, BIT_HCI_RX_REQ);
}
DBG_PRINTF(MODULE_SDIO, LEVEL_INFO, "SDIO_Return_Rx_Data(%d)<==\n", RxBdWrite);
return _TRUE;
}
void spdio_structinit(struct spdio_t *obj){
obj->rx_bd_bufsz = SPDIO_RX_BUFSZ_ALIGN(2048+24); //extra 24 bytes for sdio header
obj->rx_bd_num = 24;
obj->tx_bd_num = 24;
obj->priv = NULL;
obj->rx_buf = NULL;
obj->rx_done_cb = NULL;
obj->tx_done_cb = NULL;
}
/******************************************************************************
* Function: SDIO_TX_FIFO_DataReady
* Desc: Handle the SDIO FIFO data ready interrupt.
* 1. Send those data to the target driver via callback fun., like WLan.
* 2. Allocate a buffer for the TX BD
*
* Para:
* pSDIODev: The SDIO device data structor.
******************************************************************************/
VOID SPDIO_TX_FIFO_DataReady(IN PHAL_SPDIO_ADAPTER pSPDIODev)
{
SPDIO_TX_BD_HANDLE* pTxBdHdl;
PINIC_TX_DESC pTxDesc;
volatile u16 TxBDWPtr=0;
u8 isForceBreak=0;
s8 ret=FAIL;
u32 reg;
SPDIO_TX_BD *pTXBD = NULL;
struct spdio_t *obj = (struct spdio_t *)pSPDIODev->spdio_priv;
TxBDWPtr = SDIO_TXBD_WPTR_Get();
if (TxBDWPtr == pSPDIODev->TXBDRPtr) {
if (unlikely(pSPDIODev->TxOverFlow != 0)) {
pSPDIODev->TxOverFlow = 0;
DBG_PRINTF(MODULE_SDIO, LEVEL_WARN, "SDIO TX Data Read False Triggered!!, TXBDWPtr=0x%x\n", TxBDWPtr);
} else {
reg = HAL_SDIO_READ32(REG_SPDIO_AHB_DMA_CTRL);
DBG_PRINTF(MODULE_SDIO, LEVEL_WARN, "SDIO TX Overflow Case: Reg DMA_CTRL==0x%x %x %x %x\n", (reg>> 24)&0xff , (reg>>16)&0xff, (reg>>8)&0xff, (reg)&0xff);
return;
}
}
do {
DBG_PRINTF(MODULE_SDIO, LEVEL_INFO, "SDIO_TX_DataReady: TxBDWPtr=%d TxBDRPtr=%d\n", TxBDWPtr, pSPDIODev->TXBDRPtr);
pTXBD= (SPDIO_TX_BD*)(pSPDIODev->pTXBDAddrAligned + pSPDIODev->TXBDRPtr);
pTxBdHdl = pSPDIODev->pTXBDHdl + pSPDIODev->TXBDRPtr;
pTxDesc = (PINIC_TX_DESC)(pTXBD->Address);
DBG_PRINTF(MODULE_SDIO, LEVEL_INFO, "SDIO_TX_DataReady: PktSz=%d Offset=%d\n", pTxDesc->txpktsize, pTxDesc->offset);
if ((pTxDesc->txpktsize + pTxDesc->offset) <= obj->rx_bd_bufsz) {
// use the callback function to fordward this packet to target(WLan) driver
ret = spdio_rx_done_cb(obj, (u8*)pTxBdHdl->priv, pTxDesc->offset, pTxDesc->txpktsize, pTxDesc->type);
if(ret == FAIL)
DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "SDIO TX_Callback is Null!\n");
pTXBD->Address = obj->rx_buf[pSPDIODev->TXBDRPtr].buf_addr;
} else {
// Invalid packet, Just drop it
ret = SUCCESS; // pretend we call the TX callback OK
}
if (SUCCESS != ret) {
// may be is caused by TX queue is full, so we skip it and try again later
isForceBreak = 1;
break; // break the while loop
} else {
pSPDIODev->TXBDRPtr++;
if (pSPDIODev->TXBDRPtr >= obj->rx_bd_num) {
pSPDIODev->TXBDRPtr = 0;
}
pSPDIODev->TXBDRPtrReg = pSPDIODev->TXBDRPtr;
SDIO_TXBD_RPTR_Set(pSPDIODev->TXBDRPtrReg);
}
TxBDWPtr = SDIO_TXBD_WPTR_Get();
if (isForceBreak) {
break; // break the TX FIFO DMA Done processing
}
} while (pSPDIODev->TXBDRPtr != TxBDWPtr);
// if not all TX data were processed, set an event to trigger SDIO_Task to process them later
if (isForceBreak) {
DBG_PRINTF(MODULE_SDIO, LEVEL_WARN, "SDIO_TX Force Break: TXBDWP=0x%x TXBDRP=0x%x\n", TxBDWPtr, pSPDIODev->TXBDRPtr);
}
}
VOID SPDIO_Recycle_Rx_BD (IN PHAL_SPDIO_ADAPTER pgSPDIODev)
{
SPDIO_RX_BD_HANDLE *pRxBdHdl;
SPDIO_RX_BD *pRXBD;
u32 PktSize;
u32 FreeCnt=0; // for debugging
struct spdio_t *obj = (struct spdio_t *)pgSPDIODev->spdio_priv;
SDIO_INTConfig(BIT_C2H_DMA_OK, DISABLE);
while (SDIO_RXBD_RPTR_Get() != pgSPDIODev->RXBDRPtr) {
pRxBdHdl = pgSPDIODev->pRXBDHdl + pgSPDIODev->RXBDRPtr;
pRXBD = pRxBdHdl->pRXBD;
if (!pRxBdHdl->isFree) {
if(pRxBdHdl->isPktEnd){
spdio_tx_done_cb(obj, (u8*)(pRxBdHdl->priv));
}
pRxBdHdl->isPktEnd = 0;
_memset((void *)(pRxBdHdl->pRXDESC), 0, sizeof(INIC_RX_DESC));
_memset((void *)pRXBD , 0, sizeof(SPDIO_RX_BD)); // clean this RX_BD
pRxBdHdl->isFree = 1;
}
else {
DBG_PRINTF(MODULE_SDIO, LEVEL_WARN, "SDIO_Recycle_Rx_BD: Warring, Recycle a Free RX_BD,RXBDRPtr=%d\n",pgSPDIODev->RXBDRPtr);
}
pgSPDIODev->RXBDRPtr++;
if (pgSPDIODev->RXBDRPtr >= obj->tx_bd_num) {
pgSPDIODev->RXBDRPtr -= obj->tx_bd_num;
}
}
SDIO_INTConfig(BIT_C2H_DMA_OK, ENABLE);
DBG_PRINTF(MODULE_SDIO, LEVEL_INFO, "<==SDIO_Recycle_Rx_BD(%d)\n", FreeCnt);
}
/******************************************************************************
* Function: SPDIO_IRQ_Handler
* Desc: SPDIO device interrupt service routine
* 1. Read & clean the interrupt status
* 2. Wake up the SDIO task to handle the IRQ event
*
* Para:
* pSDIODev: The SDIO device data structor.
******************************************************************************/
VOID SPDIO_IRQ_Handler(VOID *pData)
{
PHAL_SPDIO_ADAPTER pSPDIODev = pData;
InterruptDis(SDIO_DEVICE_IRQ);
rtw_up_sema_from_isr(&pSPDIODev->IrqSema);
}
VOID SPDIO_IRQ_Handler_BH(VOID *pData)
{
PHAL_SPDIO_ADAPTER pgSPDIODev = pData;
u16 IntStatus;
for (;;)
{
/* Task blocked and wait the semaphore(events) here */
rtw_down_sema(&pgSPDIODev->IrqSema);
IntStatus = HAL_SDIO_READ16(REG_SPDIO_CPU_INT_STAS);
DBG_PRINTF(MODULE_SDIO, LEVEL_INFO, "%s:ISRStatus=0x%x\n", __FUNCTION__, IntStatus);
HAL_SDIO_WRITE16(REG_SPDIO_CPU_INT_STAS, IntStatus); // clean the ISR
InterruptEn(SDIO_DEVICE_IRQ, SPDIO_IRQ_PRIORITY);
if (IntStatus & BIT_C2H_DMA_OK) {
SPDIO_Recycle_Rx_BD(pgSPDIODev);
}
if (IntStatus & BIT_H2C_MSG_INT) {
HAL_SDIO_READ32(REG_SPDIO_CPU_H2C_MSG);
}
if (IntStatus & BIT_H2C_DMA_OK) {
SDIO_INTConfig(BIT_H2C_DMA_OK, DISABLE);
SPDIO_TX_FIFO_DataReady(pgSPDIODev);
SDIO_INTConfig(BIT_H2C_DMA_OK, ENABLE);
}
if (IntStatus & BIT_TXFIFO_H2C_OVF) {
pgSPDIODev->TxOverFlow = 1;
}
DBG_PRINTF(MODULE_SDIO, LEVEL_INFO, "%s @2 IntStatus=0x%x\n", __FUNCTION__, IntStatus);
}
#if 0
SDIO_SetEvent(pgSPDIODev, (u32)SDIO_EVENT_IRQ_STOPPED);
DBG_PRINTF(MODULE_SDIO, LEVEL_INFO, "SDIO irq Task Stopped!\n");
#if ( INCLUDE_vTaskDelete == 1 )
vTaskDelete(NULL);
#endif
#endif
}
/******************************************************************************
* Function: SPDIO_Device_Init
* Desc: SDIO mbed device driver initialization.
* 1. Allocate SDIO TX BD and RX BD adn RX Desc.
* 2. Allocate SDIO RX Buffer Descriptor and RX Buffer. Initial RX related
* register.
* 3. Register the Interrupt function.
*
******************************************************************************/
BOOL SPDIO_Device_Init(struct spdio_t * obj)
{
int i;
SPDIO_TX_BD_HANDLE *pTxBdHdl;
SPDIO_RX_BD_HANDLE *pRxBdHdl;
int ret;
SPDIO_TX_BD *pTXBD = NULL;
SDIO_InitTypeDef SDIO_InitStruct;
if(obj == NULL){
DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "struct spdio_t must be inited\n");
return FAIL;
}
DBG_PRINTF(MODULE_SDIO, LEVEL_INFO, "SDIO_Device_Init==>\n");
pgSPDIODev = &gSPDIODev;
pgSPDIODev->spdio_priv = (void*)obj;
obj->priv = (void *)pgSPDIODev;
// initial TX BD and RX BD
pgSPDIODev->pTXBDAddr = _rtw_malloc((obj->rx_bd_num* sizeof(SPDIO_TX_BD))+3);
if (NULL == pgSPDIODev->pTXBDAddr) {
DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "SDIO_Device_Init: Malloc for TX_BD Err!!\n");
goto SDIO_INIT_ERR;
}
pgSPDIODev->pTXBDAddrAligned = (SPDIO_TX_BD*)(((((u32)pgSPDIODev->pTXBDAddr - 1) >> 2) + 1) << 2); // Make it 4-bytes aligned
pgSPDIODev->pRXBDAddr = _rtw_malloc((obj->tx_bd_num * sizeof(SPDIO_RX_BD))+7);
if (NULL == pgSPDIODev->pRXBDAddr) {
DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "SDIO_Device_Init: Malloc for RX_BD Err!!\n");
goto SDIO_INIT_ERR;
}
pgSPDIODev->pRXBDAddrAligned = (SPDIO_RX_BD*)(((((u32)pgSPDIODev->pRXBDAddr - 1) >> 3) + 1) << 3); // Make it 8-bytes aligned
pgSPDIODev->pRXDESCAddr = _rtw_zmalloc((obj->tx_bd_num * sizeof(INIC_RX_DESC)) + 3);
if (NULL == pgSPDIODev->pRXDESCAddr) {
DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "SDIO_Device_Init: Malloc for RX_DESC Err!!\n");
goto SDIO_INIT_ERR;
}
pgSPDIODev->pRXDESCAddrAligned = (INIC_RX_DESC*)(((((u32)pgSPDIODev->pRXDESCAddr - 1) >> 2) + 1) << 2); //Make it 4-bytes aligned
// Clean boot from wakeup bit
SOCPS_BootFromPS(DISABLE);
/* SDIO Function & CLock Enable */
RCC_PeriphClockCmd(APBPeriph_SDIOD_ON, APBPeriph_SDIOD_CLOCK, ENABLE);
RCC_PeriphClockCmd(APBPeriph_SDIOD_OFF, APBPeriph_SDIOD_CLOCK, ENABLE);
// SDIO_SCLK / SPI_CLK pin pull-low
//PAD_PullCtrl(_PA_3, GPIO_PuPd_DOWN);
SDIO_StructInit(&SDIO_InitStruct);
SDIO_InitStruct.TXBD_BAR = (u32)pgSPDIODev->pTXBDAddrAligned;
SDIO_InitStruct.TXBD_RING_SIZE = obj->rx_bd_num; //SDIO_TX_BD_NUM;
SDIO_InitStruct.TX_BUFFER_SIZE = ((((obj->rx_bd_bufsz-1)/SPDIO_TX_BUF_SZ_UNIT)+1)&0xff);
SDIO_InitStruct.RXBD_BAR = (u32)pgSPDIODev->pRXBDAddrAligned;
SDIO_InitStruct.RXBD_RING_SIZE = obj->tx_bd_num;
SDIO_InitStruct.RXBD_FREE_TH = RX_BD_FREE_TH;
SDIO_Init((&SDIO_InitStruct));
pgSPDIODev->TXBDWPtr = SDIO_TXBD_WPTR_Get();
pgSPDIODev->TXBDRPtr = pgSPDIODev->TXBDWPtr;
pgSPDIODev->TXBDRPtrReg = pgSPDIODev->TXBDWPtr;
pgSPDIODev->RXBDWPtr = pgSPDIODev->RXBDRPtr = SDIO_RXBD_RPTR_Get();
DBG_PRINTF(MODULE_SDIO, LEVEL_INFO, "TXBDWPtr=0x%x TXBDRPtr=0x%x\n", pgSPDIODev->TXBDWPtr, pgSPDIODev->TXBDRPtr);
pgSPDIODev->pTXBDHdl = (SPDIO_TX_BD_HANDLE*)_rtw_zmalloc(obj->rx_bd_num * sizeof(SPDIO_TX_BD_HANDLE));
if (NULL == pgSPDIODev->pTXBDHdl) {
DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "SDIO_Device_Init: Malloc for TX_BD Handle Err!!\n");
goto SDIO_INIT_ERR;
}
for(i=0;i<obj->rx_bd_num;i++){
pTxBdHdl = pgSPDIODev->pTXBDHdl + i;
pTxBdHdl->pTXBD= pgSPDIODev->pTXBDAddrAligned + i;
// Pre-allocate buffer by User
pTxBdHdl->priv = (void *)&obj->rx_buf[i];
pTxBdHdl->pTXBD->Address = (u32)obj->rx_buf[i].buf_addr;
if(pTxBdHdl->pTXBD->Address%4){
DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "buffer address must be aligned to 4!!\n");
goto SDIO_INIT_ERR;
}
if (NULL == (u32*)(pTxBdHdl->pTXBD->Address)) {
DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "SDIO_Device_Init: Malloc buffer for TX_BD Err!!\n");
goto SDIO_INIT_ERR;
}
pTxBdHdl->isFree = 1;
DBG_PRINTF(MODULE_SDIO, LEVEL_INFO, "TX_BD%d @ 0x%x 0x%x\n", i, pTxBdHdl, pTxBdHdl->pTXBD);
}
pgSPDIODev->pRXBDHdl = (SPDIO_RX_BD_HANDLE*)_rtw_zmalloc(obj->tx_bd_num * sizeof(SPDIO_RX_BD_HANDLE));
if (NULL == pgSPDIODev->pRXBDHdl) {
DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "SDIO_Device_Init: Malloc for RX_BD Handle Err!!\n");
goto SDIO_INIT_ERR;
}
for (i=0; i<obj->tx_bd_num; i++) {
pRxBdHdl = pgSPDIODev->pRXBDHdl + i;
pRxBdHdl->pRXBD = pgSPDIODev->pRXBDAddrAligned + i;
pRxBdHdl->pRXDESC = pgSPDIODev->pRXDESCAddrAligned + i;
pRxBdHdl->isFree = 1;
}
rtw_init_sema(&(pgSPDIODev->IrqSema), 0);
if (NULL == pgSPDIODev->IrqSema){
DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "SDIO_Device_Init Create IRQ Semaphore Err!!\n");
goto SDIO_INIT_ERR;
}
ret = xTaskCreate( SPDIO_IRQ_Handler_BH, "SPDIO_IRQ_TASK", ((1024*1)/sizeof(portBASE_TYPE)), (void *)pgSPDIODev, 1 + PRIORITY_OFFSET, &pgSPDIODev->xSDIOIrqTaskHandle);
if (pdTRUE != ret )
{
DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "SDIO_Device_Init: Create IRQ Task Err(%d)!!\n", ret);
goto SDIO_INIT_ERR;
}
//pgSPDIODev->CRPWM = SDIO_RPWM1_Get();
//pgSPDIODev->CRPWM2 = SDIO_RPWM2_Get();
// Indicate Host this is a iNIC FW
//SDIO_CPWM2_Set(CPWM2_INIC_FW_RDY_BIT, ENABLE);
/* enable the interrupt */
InterruptRegister((IRQ_FUN) SPDIO_IRQ_Handler, SDIO_DEVICE_IRQ, (u32) pgSPDIODev, SPDIO_IRQ_PRIORITY);
InterruptEn(SDIO_DEVICE_IRQ, SPDIO_IRQ_PRIORITY);
HAL_SDIO_WRITE16(REG_SPDIO_CPU_INT_STAS, SDIO_INIT_INT_MASK); // Clean pending interrupt first
HAL_SDIO_WRITE16(REG_SPDIO_CPU_INT_MASK, SDIO_INIT_INT_MASK);
// Update the power state indication
SDIO_CPWM2_Set(CPWM2_ACT_BIT, ENABLE);
/* Indicate the Host system that the TX/RX is ready */
HAL_SDIO_WRITE8(REG_SPDIO_CPU_IND, \
HAL_SDIO_READ8(REG_SPDIO_CPU_IND)|BIT_SYSTEM_TRX_RDY_IND);
DBG_PRINTF(MODULE_SDIO, LEVEL_INFO, "<==SDIO_Device_Init\n");
return SUCCESS;
SDIO_INIT_ERR:
if (pgSPDIODev->pRXBDHdl) {
_rtw_mfree((u8 *)pgSPDIODev->pRXBDHdl, obj->tx_bd_num * sizeof(SPDIO_RX_BD_HANDLE));
pgSPDIODev->pRXBDHdl = NULL;
}
if ((pgSPDIODev->pTXBDHdl)) {
for (i=0;i<obj->rx_bd_num;i++){
pTxBdHdl = pgSPDIODev->pTXBDHdl + i;
if (pTxBdHdl->pTXBD->Address) {
pTxBdHdl->pTXBD->Address = (u32)NULL;
}
}
_rtw_mfree((u8 *)pgSPDIODev->pTXBDHdl, (obj->rx_bd_num * sizeof(SPDIO_TX_BD_HANDLE)));
pgSPDIODev->pTXBDHdl = NULL;
}
if (pgSPDIODev->pRXBDAddr) {
_rtw_mfree((u8 *)pgSPDIODev->pRXBDAddr, (obj->tx_bd_num * sizeof(SPDIO_RX_BD))+7);
pgSPDIODev->pRXBDAddr = NULL;
}
if (pgSPDIODev->pTXBDAddr) {
_rtw_mfree(pgSPDIODev->pTXBDAddr, ((obj->rx_bd_num * sizeof(SPDIO_TX_BD))+3));
pgSPDIODev->pTXBDAddr = NULL;
pgSPDIODev->pTXBDAddrAligned = NULL;
}
if (pgSPDIODev->pRXDESCAddr) {
_rtw_mfree(pgSPDIODev->pRXDESCAddr, (((obj->rx_bd_num)* sizeof(INIC_RX_DESC)) + 3));
pgSPDIODev->pRXDESCAddr = NULL;
pgSPDIODev->pRXDESCAddrAligned = NULL;
}
return FAIL;
}
/******************************************************************************
* Function: SPDIO_Device_DeInit
* Desc: SDIO device driver free resource. This function should be called in
* a task.
* 1. Free TX FIFO buffer
*
* Para:
* pSDIODev: The SDIO device data structor.
******************************************************************************/
//TODO: Call this function in a task
VOID SPDIO_Device_DeInit(VOID)
{
int i=0;
SPDIO_TX_BD_HANDLE *pTxBdHdl;
SPDIO_TX_BD *pTXBD = NULL;
struct spdio_t * obj;
if (NULL == pgSPDIODev)
return;
obj = pgSPDIODev->spdio_priv;
// Indicate the Host that Ameba is InActived
SDIO_CPWM2_Set(CPWM2_ACT_BIT, DISABLE);
if (pgSPDIODev->pRXBDHdl) {
_rtw_mfree((u8 *)pgSPDIODev->pRXBDHdl, obj->tx_bd_num * sizeof(SPDIO_RX_BD_HANDLE));
pgSPDIODev->pRXBDHdl = NULL;
}
/* Free TX FIFO Buffer */
for (i=0;i<obj->rx_bd_num;i++)
{
pTXBD = (SPDIO_TX_BD*)(pgSPDIODev->pTXBDAddrAligned + i);
pTxBdHdl = pgSPDIODev->pTXBDHdl + i;
if (pTXBD->Address) {
pTXBD->Address = (u32)NULL;
}
}
if ((pgSPDIODev->pTXBDHdl)) {
for (i=0;i<obj->rx_bd_num;i++){
pTxBdHdl = pgSPDIODev->pTXBDHdl + i;
if (pTxBdHdl->pTXBD->Address) {
pTxBdHdl->pTXBD->Address = (u32)NULL;
}
}
_rtw_mfree((u8 *)pgSPDIODev->pTXBDHdl, (obj->rx_bd_num * sizeof(SPDIO_TX_BD_HANDLE)));
pgSPDIODev->pTXBDHdl = NULL;
}
if (pgSPDIODev->pRXBDAddr) {
_rtw_mfree((u8 *)pgSPDIODev->pRXBDAddr, (obj->tx_bd_num * sizeof(SPDIO_RX_BD))+7);
pgSPDIODev->pRXBDAddr = NULL;
}
if (pgSPDIODev->pTXBDAddr) {
_rtw_mfree(pgSPDIODev->pTXBDAddr, ((obj->rx_bd_num * sizeof(SPDIO_TX_BD))+3));
pgSPDIODev->pTXBDAddr = NULL;
pgSPDIODev->pTXBDAddrAligned = NULL;
}
if (pgSPDIODev->pRXDESCAddr) {
_rtw_mfree(pgSPDIODev->pRXDESCAddr, (((obj->rx_bd_num)* sizeof(INIC_RX_DESC)) + 3));
pgSPDIODev->pRXDESCAddr = NULL;
pgSPDIODev->pRXDESCAddrAligned = NULL;
}
SDIO_INTConfig(0xffff, DISABLE);
HAL_SDIO_WRITE16(REG_SPDIO_CPU_INT_STAS, 0xffff); // Clean pending interrupt first
InterruptDis(SDIO_DEVICE_IRQ);
InterruptUnRegister(SDIO_DEVICE_IRQ);
if (pgSPDIODev->IrqSema) {
rtw_free_sema(&pgSPDIODev->IrqSema);
pgSPDIODev->IrqSema = NULL;
}
// Reset SDIO DMA
SDIO_DMA_Reset();
/* SDIO_OFF Disable, SDIO will lost if SDIO_ON OFF */
SDIOD_OFF_FCTRL(OFF);
}
void spdio_init(struct spdio_t *obj)
{
if(obj == NULL){
DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "spdio obj is NULL, spdio init failed!\n");
return;
}
if((obj->rx_bd_num == 0) ||(obj->rx_bd_bufsz == 0) || (obj->rx_bd_bufsz%64)
||(obj->tx_bd_num == 0) ||(obj->tx_bd_num%2)||(obj->rx_buf == NULL)) {
DBG_PRINTF(MODULE_SDIO, LEVEL_ERROR, "spdio obj resource isn't correctly inited, spdio init failed!\n");
return;
}
g_spdio_priv = obj;
SPDIO_Device_Init(obj);
}
void spdio_deinit(struct spdio_t *obj)
{
if(obj == NULL){
SPDIO_API_PRINTK("spdio obj is NULL, spdio deinit failed");
return;
}
SPDIO_Device_DeInit();
g_spdio_priv = NULL;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,242 @@
/** mbed Microcontroller Library
******************************************************************************
* @file sys_api.c
* @author
* @version V1.0.0
* @date 2016-08-01
* @brief This file provides following mbed system API:
* -JTAG OFF
* -LOGUART ON/OFF
* -OTA image switch
* -System Reset
******************************************************************************
* @attention
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
******************************************************************************
*/
#include "cmsis.h"
#include "sys_api.h"
#include "flash_api.h"
#include "device_lock.h"
extern u32 LogUart_Flag;/* ENABLE for on; DISABLE for off */
void rtc_backup_timeinfo(void);
#define OTA_Signature "81958711"
#define OTA_Signature_len 8
#define OTA_valid_offset 0x100000
#define printf DiagPrintf
/**
* @brief Turn off the JTAG function
* @retval none
*/
void sys_jtag_off(void)
{
boot_export_symbol.swd_off();
}
/**
* @brief switch OTA image if the othe OTA image is valid
* @retval none
* @note for AmebaZ, sys_clear_ota_signature is the same with sys_recover_ota_signature
*/
void sys_clear_ota_signature(void)
{
flash_t flash;
u32 part1_offset = 0;
u32 part2_offset = 0;
u32 ota1_valid = 0;
u32 ota2_valid = 0;
u8 signature[OTA_Signature_len+1] = {0};
part1_offset = (FLASH_OTA1_CODE_ADDR - 0x20);
flash_stream_read(&flash, part1_offset, OTA_Signature_len, signature);
if(!_memcmp((char const*)signature, OTA_Signature, OTA_Signature_len)){
ota1_valid = 1;
}
printf("\n\rOTA ota1_signature = %s \n", signature);
flash_stream_read(&flash, FLASH_SYSTEM_DATA_ADDR, 4, (u8*)&part2_offset);
flash_stream_read(&flash, (part2_offset -SPI_FLASH_BASE) , OTA_Signature_len, signature);
if(!_memcmp((char const*)signature, OTA_Signature, OTA_Signature_len)){
ota2_valid = 1;
}
printf("\n\rOTA ota2_signature = %s \n", signature);
printf("\n\rOTA ota1_valid = 0x%08X ota2_valid = 0x%08X \n", ota1_valid, ota2_valid);
if ((ota1_valid == 1) && (ota2_valid == 1)) {
u32 ValidIMG2 = HAL_READ32(SPI_FLASH_BASE, FLASH_SYSTEM_DATA_ADDR + 4);
u32 BitIdx = 0;
if (ValidIMG2 == 0x00000000) {
FLASH_EreaseDwordsXIP((FLASH_SYSTEM_DATA_ADDR + 4), 1);
ValidIMG2 = 0xFFFFFFFF;
}
for (BitIdx = 0; BitIdx <= 31; BitIdx++) {
if ((ValidIMG2 & BIT(BitIdx)) != 0) {
break;
}
}
/* switch OAT image */
ValidIMG2 &= ~BIT(BitIdx);
/* write flash */
FLASH_TxData12BXIP((FLASH_SYSTEM_DATA_ADDR + 4), 4, (u8*)&ValidIMG2);
}
}
/**
* @brief switch OTA image if the othe OTA image is valid
* @retval none
* @note for AmebaZ, sys_clear_ota_signature is the same with sys_recover_ota_signature
*/
void sys_recover_ota_signature(void)
{
sys_clear_ota_signature();
}
/**
* @brief open log uart
* @retval none
*/
void sys_log_uart_on(void)
{
SOCPS_SetLogUartFlag(ENABLE);
/* 0: S1 PA29 & PA30, 1: S0 PA16 & PA17 */
/* EFUSE default 0: S1 */
if (HAL_READ32(SYSTEM_CTRL_BASE, REG_SYS_EFUSE_SYSCFG6) & BIT_SYS_UART2_DEFAULT_GPIO) {
PinCtrl(PERIPHERAL_LOG_UART, S0, ON);
} else {
PinCtrl(PERIPHERAL_LOG_UART, S1, ON);
}
UART_INTConfig(UART2_DEV, RUART_IER_ERBI | RUART_IER_ELSI, ENABLE);
UART_RxCmd(UART2_DEV, ENABLE);
}
/**
* @brief close log uart
* @retval none
*/
void sys_log_uart_off(void)
{
SOCPS_SetLogUartFlag(DISABLE);
UART_INTConfig(UART2_DEV, RUART_IER_ERBI | RUART_IER_ELSI, DISABLE);
UART_RxCmd(UART2_DEV, DISABLE);
/* 0: S1 PA29 & PA30, 1: S0 PA16 & PA17 */
/* EFUSE default 0: S1 */
if (HAL_READ32(SYSTEM_CTRL_BASE, REG_SYS_EFUSE_SYSCFG6) & BIT_SYS_UART2_DEFAULT_GPIO) {
PinCtrl(PERIPHERAL_LOG_UART, S0, OFF);
} else {
PinCtrl(PERIPHERAL_LOG_UART, S1, OFF);
}
}
/**
* @brief store or load adc calibration parameter
* @param write: this parameter can be one of the following values:
* @arg 0: load adc calibration parameter offset & gain from flash system data region
* @arg 1: store adc calibration parameter offset & gain to flash system data region
* @param offset: pointer to adc parameter offset
* @param gain: pointer to adc parameter gain
* @retval none
*/
void sys_adc_calibration(u8 write, u16 *offset, u16 *gain)
{
flash_t flash;
u32 flash_data = 0;
flash_data = (u32)*offset;
flash_data |= (u32)((*gain) << 16);
if(write){
FLASH_EreaseDwordsXIP((FLASH_SYSTEM_DATA_ADDR + FLASH_ADC_PARA_OFFSET), 1);
FLASH_TxData12BXIP((FLASH_SYSTEM_DATA_ADDR + FLASH_ADC_PARA_OFFSET), 4, (u8*)&flash_data);
printf("\n\rStore ADC calibration success.");
}
flash_stream_read(&flash, (FLASH_SYSTEM_DATA_ADDR + FLASH_ADC_PARA_OFFSET), 4, (u8*)&flash_data);
printf("\n\rADC offset = 0x%04X, gain = 0x%04X.\n\r", (flash_data & 0xFFFF), (flash_data & 0xFFFF0000) >> 16);
}
/**
* @brief system software reset
* @retval none
*/
void sys_reset(void)
{
rtc_backup_timeinfo();
/* Set processor clock to default(125MHz) before system reset */
HAL_WRITE32(SYSTEM_CTRL_BASE, REG_SYS_CLK_CTRL1,
((HAL_READ32(SYSTEM_CTRL_BASE, REG_SYS_CLK_CTRL1) & (~0x70))));
DelayUs(100*1000);
/* Cortex-M3 SCB->AIRCR */
SCB->AIRCR = ((0x5FA << SCB_AIRCR_VECTKEY_Pos) | // VECTKEY
(SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | // PRIGROUP
SCB_AIRCR_SYSRESETREQ_Msk); // SYSRESETREQ
}
/**
* @brief vector reset
* @retval none
*/
void sys_cpu_reset(void)
{
u32 reg_value;
rtc_backup_timeinfo();
reg_value = HAL_READ32(PERI_ON_BASE, REG_SOC_FUNC_EN);
reg_value |= BIT_SOC_PATCH_FUNC1;
HAL_WRITE32(PERI_ON_BASE, REG_SOC_FUNC_EN, reg_value);
/* Ensure all outstanding memory accesses included */
/* buffered write are completed before reset */
__DSB();
/* CPU reset */
/* Keep priority group unchanged */
SCB->AIRCR = ((0x5FA << SCB_AIRCR_VECTKEY_Pos) |
(SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) |
SCB_AIRCR_VECTRESET_Pos | SCB_AIRCR_VECTCLRACTIVE_Pos);
/* Ensure completion of memory access */
__DSB();
while(1);
}
/**
* @brief get rdp status
* @retval :RDP valid status
* This parameter can be one of the following values:
* @arg 0: rdp valid
* @arg 1: system.bin not load to flash
* @arg 2: rdp.bin not load to flash
* @arg 3: Key request timeout
* @arg 4: RDP not enable in efuse
* @arg 5: Check sum error
*/
u32 sys_get_rdp_valid(void)
{
return boot_export_symbol.rdp_valid();
}
/******************* (C) COPYRIGHT 2016 Realtek Semiconductor *****END OF FILE****/

View File

@@ -0,0 +1,201 @@
/** mbed Microcontroller Library
******************************************************************************
* @file timer_api.c
* @author
* @version V1.0.0
* @date 2016-08-01
* @brief This file provides mbed API for gtimer.
******************************************************************************
* @attention
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
******************************************************************************
*/
#include "objects.h"
#include "timer_api.h"
/**
* @brief gtimer interrupt handler function.
* @param data: timer IRQ callback parameter
* @retval none
*/
static void gtimer_timeout_handler (uint32_t data)
{
gtimer_t *obj = (gtimer_t *)data;
uint32_t tid = obj->timer_id;
gtimer_irq_handler handler;
RTIM_INTClear(TIMx[tid]);
if (obj->handler != NULL) {
handler = (gtimer_irq_handler)obj->handler;
handler(obj->hid);
}
if (!obj->is_periodcal) {
gtimer_stop(obj);
}
}
/**
* @brief Initializes the timer device, include timer registers and interrupt.
* @param obj: timer object define in application software.
* @param tid: general timer ID, which can be one of the following parameters:
* @arg TIMER0
* @arg TIMER1
* @arg TIMER2
* @arg TIMER3
* @note TIMER0 is reserved, TIMER1/2/3 are recommended.
* @retval none
*/
void gtimer_init (gtimer_t *obj, uint32_t tid)
{
RTIM_TimeBaseInitTypeDef TIM_InitStruct;
assert_param((tid < GTIMER_MAX) && (tid > TIMER0));
obj->timer_id = tid;
RTIM_TimeBaseStructInit(&TIM_InitStruct);
TIM_InitStruct.TIM_Idx = (u8)tid;
TIM_InitStruct.TIM_UpdateEvent = ENABLE; /* UEV enable */
TIM_InitStruct.TIM_UpdateSource = TIM_UpdateSource_Overflow;
TIM_InitStruct.TIM_ARRProtection = ENABLE;
RTIM_TimeBaseInit(TIMx[tid], &TIM_InitStruct, TIMx_irq[tid], (IRQ_FUN) gtimer_timeout_handler, (u32)obj);
}
/**
* @brief Deinitializes the timer device, include timer function and interrupt.
* @param obj: timer object define in application software.
* @retval none
*/
void gtimer_deinit (gtimer_t *obj)
{
uint32_t tid = obj->timer_id;
assert_param((tid < GTIMER_MAX) && (tid > TIMER0));
RTIM_DeInit(TIMx[tid]);
}
/**
* @brief Get counter value of the specified timer.
* @param obj: timer object define in application software.
* @retval value: counter value
*/
uint32_t gtimer_read_tick (gtimer_t *obj)
{
uint32_t tid = obj->timer_id;
assert_param((tid < GTIMER_MAX) && (tid > TIMER0));
return (RTIM_GetCount(TIMx[tid]));
}
/**
* @brief Get count value in microseconds of the specified timer.
* @param obj: timer object define in application software.
* @retval value: count value in microseconds.
*/
uint64_t gtimer_read_us (gtimer_t *obj) //need to be test in IAR(64bit computing)
{
assert_param((obj->timer_id < GTIMER_MAX) && (obj->timer_id > TIMER0));
uint64_t time_us;
time_us = gtimer_read_tick(obj) *1000000 /32768;
return (time_us);
}
/**
* @brief Change period of the specified timer.
* @param obj: timer object define in application software.
* @param duration_us: the new period to be set in microseconds.
* @retval none
*/
void gtimer_reload (gtimer_t *obj, uint32_t duration_us)
{
uint32_t tid = obj->timer_id;
uint32_t temp = (uint32_t)((float)duration_us / 1000000 *32768);
assert_param((tid < GTIMER_MAX) && (tid > TIMER0));
RTIM_ChangePeriod(TIMx[tid], temp);
}
/**
* @brief Start the specified timer and enable update interrupt.
* @param obj: timer object define in application software.
* @retval none
*/
void gtimer_start (gtimer_t *obj)
{
uint32_t tid = obj->timer_id;
assert_param((tid < GTIMER_MAX) && (tid > TIMER0));
RTIM_INTConfig(TIMx[tid], TIM_IT_Update, ENABLE);
RTIM_Cmd(TIMx[tid], ENABLE);
}
/**
* @brief Start the specified timer in one-shot mode with specified period and interrupt handler.
* @param obj: timer object define in application software.
* @param duration_us: the new period to be set in microseconds.
* @param handler: user defined IRQ callback function
* @param hid: user defined IRQ callback parameter
* @retval none
* @note This function set the timer into one-shot mode which stops after the first time the counter overflows.
*/
void gtimer_start_one_shout (gtimer_t *obj, uint32_t duration_us, void* handler, uint32_t hid)
{
assert_param((obj->timer_id < GTIMER_MAX) && (obj->timer_id > TIMER0));
obj->is_periodcal = _FALSE;
obj->handler = handler;
obj->hid = hid;
gtimer_reload(obj, duration_us);
gtimer_start(obj);
}
/**
* @brief Start the specified timer in periodical mode with specified period and interrupt handler.
* @param obj: timer object define in application software.
* @param duration_us: the new period to be set in microseconds.
* @param handler: user defined IRQ callback function
* @param hid: user defined IRQ callback parameter
* @retval none
* @note This functon set the timer into periodical mode which will restart to count from 0 each time the counter overflows.
*/
void gtimer_start_periodical (gtimer_t *obj, uint32_t duration_us, void* handler, uint32_t hid)
{
assert_param((obj->timer_id < GTIMER_MAX) && (obj->timer_id > TIMER0));
obj->is_periodcal = _TRUE;
obj->handler = handler;
obj->hid = hid;
gtimer_reload(obj, duration_us);
gtimer_start(obj);
}
/**
* @brief Disable the specified timer peripheral.
* @param obj: timer object define in application software.
* @retval none
*/
void gtimer_stop (gtimer_t *obj)
{
uint32_t tid = obj->timer_id;
assert_param((tid < GTIMER_MAX) && (tid > TIMER0));
RTIM_Cmd(TIMx[tid], DISABLE);
}

View File

@@ -0,0 +1,69 @@
/** mbed Microcontroller Library
******************************************************************************
* @file timer_api.h
* @author
* @version V1.0.0
* @date 2016-08-01
* @brief This file provides mbed timer API
******************************************************************************
* @attention
*
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************
*/
#ifndef MBED_EXT_TIMER_API_EXT_H
#define MBED_EXT_TIMER_API_EXT_H
#include "device.h"
typedef void (*gtimer_irq_handler)(uint32_t id);
typedef struct gtimer_s gtimer_t;
enum {
TIMER0 = 0, /*!< GTimer 0, 32k timer, share with us_tick(wait_ms()) functions. This timer is reserved and users are not recommended to use it */
TIMER1 = 1, /*!< GTimer 1, 32k timer, share with APP_TIM_ID */
TIMER2 = 2, /*!< GTimer 2, 32k timer, users can use it */
TIMER3 = 3, /*!< GTimer 3, 32k timer, users can use it */
GTIMER_MAX = 4
};
/** @defgroup AmebaZ_Mbed_API
* @{
*/
/** @defgroup MBED_TIMER
* @brief MBED_TIMER driver modules
* @{
*/
/** @defgroup MBED_TIMER_Standard_Functions MBED_TIMER standard Functions
* @{
*/
void gtimer_init (gtimer_t *obj, uint32_t tid);
void gtimer_deinit (gtimer_t *obj);
uint32_t gtimer_read_tick (gtimer_t *obj);
uint64_t gtimer_read_us (gtimer_t *obj);
void gtimer_reload (gtimer_t *obj, uint32_t duration_us);
void gtimer_start (gtimer_t *obj);
void gtimer_start_one_shout (gtimer_t *obj, uint32_t duration_us, void* handler, uint32_t hid);
void gtimer_start_periodical (gtimer_t *obj, uint32_t duration_us, void* handler, uint32_t hid);
void gtimer_stop (gtimer_t *obj);
/** @} */
/** @} */
/** @} */
#endif

View File

@@ -0,0 +1,128 @@
/* mbed Microcontroller Library
*******************************************************************************
* Copyright (c) 2014, Realtek Semiconductor Corp.
* All rights reserved.
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*******************************************************************************
*/
#include "objects.h"
#include <stddef.h>
#include "us_ticker_api.h"
#include "PeripheralNames.h"
#define TICK_READ_FROM_CPU 0 //1: read tick from CPU, 0: read tick from G-Timer
#define GTIMER_CLK_HZ (32768)
#define GTIMER_TICK_US (1000000/GTIMER_CLK_HZ)
#define SYS_TIM_ID 0 // the G-Timer ID for System
#define APP_TIM_ID 1 // the G-Timer ID for Application
static int us_ticker_inited = 0;
VOID _us_ticker_irq_handler(void *Data)
{
us_ticker_irq_handler();
}
void us_ticker_init(void)
{
RTIM_TimeBaseInitTypeDef TIM_InitStruct;
if (us_ticker_inited)
return;
us_ticker_inited = 1;
RTIM_TimeBaseStructInit(&TIM_InitStruct);
TIM_InitStruct.TIM_Idx = APP_TIM_ID;
TIM_InitStruct.TIM_Prescaler = 0;
TIM_InitStruct.TIM_Period = 0xFFFFFFFF;
TIM_InitStruct.TIM_UpdateEvent = ENABLE; /* UEV enable */
TIM_InitStruct.TIM_UpdateSource = TIM_UpdateSource_Overflow;
TIM_InitStruct.TIM_ARRProtection = ENABLE;
RTIM_TimeBaseInit(TIM1, &TIM_InitStruct, 0, (IRQ_FUN) _us_ticker_irq_handler, (u32)NULL);
RTIM_Cmd(TIM0, ENABLE);
DBG_PRINTF(MODULE_TIMER, LEVEL_INFO, "%s: Timer_Id=%d\n", __FUNCTION__, APP_TIM_ID);
}
#if (!TICK_READ_FROM_CPU) || !defined(PLATFORM_FREERTOS)
uint32_t us_ticker_read()
{
uint32_t tick_cnt;
uint32_t ticks_125ms;
uint32_t ticks_remain;
uint64_t us_tick;
tick_cnt = SYSTIMER_TickGet(); //up counter
us_tick = tick_cnt * (1000000/32768);
return ((uint32_t)us_tick);
}
#else
// if the system tick didn't be initialed, call delay function may got system hang
#define OS_CLOCK (200000000UL/6*5) // CPU clock = 166.66 MHz
#define OS_TICK 1000 // OS ticks 1000/sec
#define OS_TRV ((uint32_t)(((double)OS_CLOCK*(double)OS_TICK)/1E6)-1)
#define NVIC_ST_CTRL (*((volatile uint32_t *)0xE000E010))
#define NVIC_ST_RELOAD (*((volatile uint32_t *)0xE000E014))
#define NVIC_ST_CURRENT (*((volatile uint32_t *)0xE000E018))
extern uint32_t xTaskGetTickCount( void );
uint32_t us_ticker_read()
{
uint32_t tick_cnt;
uint32_t us_tick, ms;
static uint32_t last_us_tick=0;
ms = xTaskGetTickCount();
us_tick = (uint32_t)(ms*1000);
tick_cnt = OS_TRV - NVIC_ST_CURRENT;
us_tick += (uint32_t)((tick_cnt*1000)/(OS_TRV+1) );
if ( (last_us_tick > us_tick) && (last_us_tick < 0xFFFFFC00) ) {
us_tick += 1000;
}
last_us_tick = us_tick;
return us_tick;
}
#endif
void us_ticker_set_interrupt(timestamp_t timestamp)
{
uint32_t cur_time_us;
uint32_t duration_us;
uint32_t timer_tick = 0;
cur_time_us = us_ticker_read();
if ((uint32_t)timestamp >= cur_time_us) {
duration_us = (uint32_t)timestamp - cur_time_us;
}
else {
duration_us = 0xffffffff - cur_time_us + (uint32_t)timestamp;
}
if (duration_us < TIMER_TICK_US) {
duration_us = TIMER_TICK_US; // at least 1 tick
}
timer_tick = (uint32_t)((float)duration_us / 1000000 *32000);
RTIM_ChangePeriod(TIMx[APP_TIM_ID], timer_tick);
}
void us_ticker_disable_interrupt(void)
{
RTIM_Cmd(TIMx[APP_TIM_ID], DISABLE);
}
void us_ticker_clear_interrupt(void)
{
RTIM_INTClear(TIMx[APP_TIM_ID]);
}

View File

@@ -0,0 +1,119 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stddef.h>
#include "us_ticker_api.h"
#include "cmsis.h"
static ticker_event_handler event_handler;
static ticker_event_t *head = NULL;
void us_ticker_set_handler(ticker_event_handler handler)
{
us_ticker_init();
event_handler = handler;
}
void us_ticker_irq_handler(void)
{
us_ticker_clear_interrupt();
/* Go through all the pending TimerEvents */
while (1) {
if (head == NULL) {
/* There are no more TimerEvents left, so disable matches. */
us_ticker_disable_interrupt();
return;
}
if ((int)(head->timestamp - us_ticker_read()) <= 0) {
/* This event was in the past: point to the following one and execute its handler */
ticker_event_t *p = head;
head = head->next;
if (event_handler != NULL) {
event_handler(p->id); // NOTE: the handler can set new events
}
/* Note: We continue back to examining the head because calling the */
/* event handler may have altered the chain of pending events. */
} else {
/* This event and the following ones in the list are in the future: set it as next interrupt and return */
us_ticker_set_interrupt(head->timestamp);
return;
}
}
}
void us_ticker_insert_event(ticker_event_t *obj, timestamp_t timestamp, uint32_t id)
{
/* disable interrupts for the duration of the function */
__disable_irq();
/* initialise our data */
obj->timestamp = timestamp;
obj->id = id;
/* Go through the list until we either reach the end, or find */
/* an element this should come before (which is possibly the head). */
ticker_event_t *prev = NULL, *p = head;
while (p != NULL) {
/* check if we come before p */
if ((int)(timestamp - p->timestamp) <= 0) {
break;
}
/* go to the next element */
prev = p;
p = p->next;
}
/* if prev is NULL we're at the head */
if (prev == NULL) {
head = obj;
us_ticker_set_interrupt(timestamp);
} else {
prev->next = obj;
}
/* if we're at the end p will be NULL, which is correct */
obj->next = p;
__enable_irq();
}
void us_ticker_remove_event(ticker_event_t *obj)
{
__disable_irq();
/* remove this object from the list */
if (head == obj) {
/* first in the list, so just drop me */
head = obj->next;
if (head == NULL) {
us_ticker_disable_interrupt();
} else {
us_ticker_set_interrupt(head->timestamp);
}
} else {
/* find the object before me, then drop me */
ticker_event_t* p = head;
while (p != NULL) {
if (p->next == obj) {
p->next = obj->next;
break;
}
p = p->next;
}
}
__enable_irq();
}

View File

@@ -0,0 +1,32 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "wait_api.h"
#include "us_ticker_api.h"
void wait(float s)
{
DelayUs((int)(s * 1000000.0f));
}
void wait_ms(int ms)
{
DelayUs(ms * 1000);
}
void wait_us(int us)
{
DelayUs(us);
}

View File

@@ -0,0 +1,87 @@
/** mbed Microcontroller Library
******************************************************************************
* @file wdt_api.c
* @author
* @version V1.0.0
* @date 2016-08-01
* @brief This file provides mbed API for WDG.
******************************************************************************
* @attention
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
******************************************************************************
*/
#include "objects.h"
#include "ameba_soc.h"
#include "wdt_api.h"
#include "cmsis.h"
/**
* @brief Initializes the watch dog, include time setting, mode register
* @param timeout_ms: the watch-dog timer timeout value, in ms.
* default action of timeout is to reset the whole system.
* @retval none
*/
void watchdog_init(uint32_t timeout_ms)
{
WDG_InitTypeDef WDG_InitStruct;
u32 CountProcess;
u32 DivFacProcess;
WDG_Scalar(timeout_ms, &CountProcess, &DivFacProcess);
WDG_InitStruct.CountProcess = CountProcess;
WDG_InitStruct.DivFacProcess = DivFacProcess;
WDG_Init(&WDG_InitStruct);
}
/**
* @brief Start the watchdog counting
* @param None
* @retval none
*/
void watchdog_start(void)
{
WDG_Cmd(ENABLE);
}
/**
* @brief Stop the watchdog counting
* @param None
* @retval none
*/
void watchdog_stop(void)
{
WDG_Cmd(DISABLE);
}
/**
* @brief Refresh the watchdog counting to prevent WDT timeout
* @param None
* @retval none
*/
void watchdog_refresh(void)
{
WDG_Refresh();
}
/**
* @brief Switch the watchdog timer to interrupt mode and
* register a watchdog timer timeout interrupt handler.
* The interrupt handler will be called when the watch-dog
* timer is timeout.
* @param handler: the callback function for WDT timeout interrupt.
* @param id: the parameter for the callback function
* @retval none
*/
void watchdog_irq_init(wdt_irq_handler handler, uint32_t id)
{
WDG_IrqInit((VOID*)handler, (u32)id);
}