800*320工程文件+初始demo提交

This commit is contained in:
2024-03-07 16:46:43 +08:00
parent 33e6eb45b3
commit 70ec3005bb
3306 changed files with 3374364 additions and 2563 deletions

View File

@ -0,0 +1,155 @@
/*
******************************************************************************
* @file driver_adc.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief ADC module driver.
* This file provides firmware functions to manage the
* Analog to Digital Converter (ADC) peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/******************************************************************************
* @fn adc_init
*
* @brief Initialize the ADC according to the specified parameters
* in the adc_InitConfig_t
*
* @param InitParam : adc_InitConfig_t structure that contains the
* configuration information for ADC module.
*/
void adc_init(adc_InitConfig_t InitConfig)
{
/* ADC reset */
__ADC_RESET();
/* analog config */
if (InitConfig.ADC_Reference == ADC_REF_1P2V)
ADC->ACT0 = ADC_ACT0_REF_1P2V;
else
ADC->ACT0 = ADC_ACT0_REF_IOLDO;
ADC->ACT1 = ADC_ACT1_VBE_EN | ADC_ACT1_VBAT_EN | ADC_ACT1_IS;
/* Timing config */
__ADC_SET_CLK_DIV(2); /*!< ADC clock = 24Mhz / ((ADC_CLK_DIV + 1) * 2). Fixed 2 */
__ADC_SET_SETUP_CYCLE(60); /*!< Convert setup cycle. Fixed 60 */
__ADC_SET_SAMPLE_CYCLE(30); /*!< Convert sample cycle. Fixed 30 */
__ADC_SET_TIMEOUT_CYCLE(0x1F); /*!< Convert timeoout cycle. Fixed 31 */
/* Init default channel maping */
for (int i = 0; i < ADC_MAX_IO_INPUT_MAP; i++)
{
__ADC_SET_CHANNEL_MAP(i, i);
}
/* Hrad trigger mode */
if (InitConfig.ADC_TriggerMode == ADC_HARDWARE_TRIGGER)
{
__ADC_SET_TRIGGER_MODE(ADC_HARDWARE_TRIGGER);
/* set Max channel */
__ADC_SET_MAX_CHANNEL(InitConfig.HardTriggerConfig.ADC_Channel_Max - 1);
/* set convert mode */
__ADC_SET_CONVERT_MODE(InitConfig.HardTriggerConfig.ADC_Convert_Mode);
}
/* Soft trigger mode */
else
{
__ADC_SET_TRIGGER_MODE(ADC_SOFTWARE_TRIGGER);
/* Soft trigger mode default use single convert */
__ADC_SET_CONVERT_MODE(ADC_SINGLE_MODE);
}
}
/******************************************************************************
* @fn adc_soft_trigger_convert
*
* @brief Software triggers the specified channel convert.
*
* @param fu8_Channel : channel number(0 ~ 7)
*/
void adc_soft_trigger_convert(uint8_t fu8_Channel)
{
/* select soft trigger channel */
__ADC_SET_SOFT_TRIGGER_CHANNEL(fu8_Channel);
/* soft trigger */
__ADC_SOFT_TRIGGER();
}
/******************************************************************************
* @fn adc_convert_start/stop
*
* @brief hardware triggers channel convert start/stop.
*/
void adc_convert_start(void)
{
__ADC_CONVERT_ENABLE();
}
void adc_convert_start_IT(void)
{
__ADC_CONVERT_ENABLE();
__ADC_INT_ENABLE(ADC_INT_CHANNEL_VALID);
}
void adc_convert_stop(void)
{
__ADC_CONVERT_DISABLE();
__ADC_INT_DISABLE(ADC_INT_CHANNEL_VALID);
}
/******************************************************************************
* @fn adc_channel_valid_int_enable/disable
*
* @brief channel valid interrupt enable/disable.
*/
void adc_channel_valid_int_enable(void)
{
__ADC_INT_ENABLE(ADC_INT_CHANNEL_VALID);
}
void adc_channel_valid_int_disable(void)
{
__ADC_INT_DISABLE(ADC_INT_CHANNEL_VALID);
}
/******************************************************************************
* @fn adc_get_channel_valid_status
*
* @brief get Channel valid status.
*
* @param fu8_Channel : channel number(0 ~ 7)
*/
bool adc_get_channel_valid_status(uint8_t fu8_Channel)
{
return (__ADC_GET_CHANNEL_STATUS() & (1 << fu8_Channel)) ? true : false;
}
/******************************************************************************
* @fn adc_get_channel_data
*
* @brief get Channel convert Data.
* @param fu8_Channel : channel number(0 ~ 7)
*/
uint32_t adc_get_channel_data(uint8_t fu8_Channel)
{
return __ADC_GET_CHANNEL_DATA(fu8_Channel);
}
/******************************************************************************
* @fn adc_set_channel_maping
*
* @brief set Channel maping.
*
* @param fu8_Channel : channel number(0 ~ 7)
* @param fe_Map : channel map select.
*/
void adc_set_channel_maping(uint8_t fu8_Channel, enum_ADC_Channel_Map_t fe_Map)
{
__ADC_SET_CHANNEL_MAP(fu8_Channel, fe_Map);
}

View File

@ -0,0 +1,179 @@
/*
******************************************************************************
* @file driver_aes.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2022
* @brief IIR module driver.
* This file provides firmware functions to manage the
* SEC AES peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2022 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/*********************************************************************
* @fn aes_config
*
* @brief config the aes mode and Endia.
*
* @param fe_Mode : select AES mode.
* @param fe_Endian: select AES Endian.
*/
void aes_config(enum_AES_MODE_t fe_Mode, enum_ENDIAN_t fe_Endian)
{
/* AES Endian */
SEC_AES->AES_CTRL.Bits.ENDIAN_SEL = fe_Endian;
/* AES Mode */
if (fe_Mode >= AES_CBC_128){
SEC_AES->AES_CTRL.Bits.CBC = AES_CBC_MODE_ENABLE;
SEC_AES->AES_CTRL.Bits.KEY_LEN = fe_Mode - AES_CBC_128;
}
else{
SEC_AES->AES_CTRL.Bits.CBC = AES_CBC_MODE_DISABLE;
SEC_AES->AES_CTRL.Bits.KEY_LEN = fe_Mode;
}
}
/*********************************************************************
* @fn aes_set_encrypt_key
*
* @brief Set AES encryption key.
*
* @param key : points to the AES key.
*/
void aes_set_encrypt_key(uint8_t *key)
{
uint32_t *lp_Key = (uint32_t *)key;
SEC_AES->KEY_0 = lp_Key[0];
SEC_AES->KEY_1 = lp_Key[1];
SEC_AES->KEY_2 = lp_Key[2];
SEC_AES->KEY_3 = lp_Key[3];
switch(SEC_AES->AES_CTRL.Bits.KEY_LEN)
{
case AES_ECB_192:{
SEC_AES->KEY_4 = lp_Key[4];
SEC_AES->KEY_5 = lp_Key[5];
}break;
case AES_ECB_256:{
SEC_AES->KEY_4 = lp_Key[4];
SEC_AES->KEY_5 = lp_Key[5];
SEC_AES->KEY_6 = lp_Key[6];
SEC_AES->KEY_7 = lp_Key[7];
}break;
default:break;
}
}
/*********************************************************************
* @fn aes_set_encrypt_iv
*
* @brief Set IV for the encrypt/decrypt.
*
* @param key : points to the AES key.
*/
void aes_set_encrypt_iv(uint8_t *iv)
{
uint32_t *lp_IV = (uint32_t *)iv;
SEC_AES->IV_0 = lp_IV[0];
SEC_AES->IV_1 = lp_IV[1];
SEC_AES->IV_2 = lp_IV[2];
SEC_AES->IV_3 = lp_IV[3];
}
/*********************************************************************
* @fn aes_encrypt
*
* @brief aes encrypt.
*
* @param fp_Data_In: the pointer of data which is to encrypt.
* @param fu32_Size: encrypt size.
* @param fp_Data_Out: the pointer of data which saves the encryption data.
*/
void aes_encrypt(uint8_t *fp_Data_In, uint32_t fu32_Size, uint8_t *fp_Data_Out)
{
uint32_t *DataIN = (uint32_t *)fp_Data_In;
uint32_t *DataOUT = (uint32_t *)fp_Data_Out;
uint32_t InIndex = 0;
uint32_t lu32_size;
lu32_size = fu32_Size/16;
if (fu32_Size % 16)
lu32_size++;
/* Block 16 byte */
while(InIndex < lu32_size)
{
SEC_AES->DATAIN_0 = *DataIN++;
SEC_AES->DATAIN_1 = *DataIN++;
SEC_AES->DATAIN_2 = *DataIN++;
SEC_AES->DATAIN_3 = *DataIN++;
__AES_SET_OPCODE(AES_OPCODE_ENCRYPT);
__AES_WORK_START();
while(__AES_IS_BUSY());
*DataOUT++ = SEC_AES->DATAOUT_0;
*DataOUT++ = SEC_AES->DATAOUT_1;
*DataOUT++ = SEC_AES->DATAOUT_2;
*DataOUT++ = SEC_AES->DATAOUT_3;
InIndex++;
}
}
/*********************************************************************
* @fn aes_decrypt
*
* @brief aes decrypt
*
* @param fp_Data_In: the pointer of data which is to decrypt.
* @param fu32_Size: decrypt size.
* @param fp_Data_Out: the pointer of data which saves the decryption data.
*/
void aes_decrypt(uint8_t *fp_Data_In, uint32_t fu32_Size, uint8_t *fp_Data_Out)
{
uint32_t *DataIN = (uint32_t *)fp_Data_In;
uint32_t *DataOUT = (uint32_t *)fp_Data_Out;
uint32_t InIndex = 0;
uint32_t lu32_size;
lu32_size = fu32_Size/16;
if (fu32_Size % 16)
lu32_size++;
while (InIndex < lu32_size)
{
SEC_AES->DATAIN_0 = *DataIN++;
SEC_AES->DATAIN_1 = *DataIN++;
SEC_AES->DATAIN_2 = *DataIN++;
SEC_AES->DATAIN_3 = *DataIN++;
__AES_SET_OPCODE(AES_OPCODE_KEY_EXPAND);
__AES_WORK_START();
while(__AES_IS_BUSY());
__AES_SET_OPCODE(AES_OPCODE_DECRYPT);
__AES_WORK_START();
while(__AES_IS_BUSY());
*DataOUT++ = SEC_AES->DATAOUT_0;
*DataOUT++ = SEC_AES->DATAOUT_1;
*DataOUT++ = SEC_AES->DATAOUT_2;
*DataOUT++ = SEC_AES->DATAOUT_3;
InIndex++;
}
}

View File

@ -0,0 +1,264 @@
/*
******************************************************************************
* @file driver_blend.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2022
* @brief BLEND module driver.
* This file provides firmware functions to manage the
* BLEND peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2022 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/************************************************************************************
* @fn blend_IRQHandler
*
* @brief Handle BLEND interrupt request.
*
* @param hblend: BLEND handle.
*/
void blend_IRQHandler(BLEND_HandleTypeDef *hblend)
{
uint32_t isr_status;
isr_status = BLEND_AHB0->ISR_STATUS.Word;
/*Out image interrupt handle*/
if(BLEND_AHB0->ISR_STATUS.Bits.ORGB_ALFULL_INT_STS == 1)
{
while(BLEND_AHB0->FIFO_STATUS.Bits.ORGB_EMPTY == 0)
{
if(hblend->DataOutIndex >= hblend->OutSize)
{
__BLEND_INT_ORGB_FIFO_ALFULL_DISABLE();
if(hblend->Callback)
{
hblend->Callback(hblend);
}
return;
}
hblend->OutRgb[hblend->DataOutIndex++] = BLEND_AHB1->ORGB_DATA;
}
}
/*Src image interrupt handle*/
if(isr_status & BLEND_RGB0_EMPTY_INT_STS)
{
while(!__RGB0_FIFO_IS_ALFULL())
{
BLEND_AHB0->RGB0_DATA = hblend->SrcRgb[hblend->SrcInIndex++];
if(hblend->SrcInIndex >= hblend->SrcSize)
{
__BLEND_INT_RGB0_FIFO_EMPTY_DISABLE();
break;
}
}
}
/*Back image interrupt handle*/
if(isr_status & BLEND_RGB1_EMPTY_INT_STS)
{
while(!__RGB1_FIFO_IS_ALFULL())
{
BLEND_AHB0->RGB1_DATA = hblend->BackRgb[hblend->BackInIndex++];
if(hblend->BackInIndex >= hblend->BackSize)
{
__BLEND_INT_RGB1_FIFO_EMPTY_DISABLE();
break;
}
}
}
/*Mask image interrupt handle*/
if(isr_status & BLEND_MASK_EMPTY_INT_STS)
{
while(!__MASK_FIFO_IS_ALFULL())
{
BLEND_AHB1->MASK_DATA = hblend->MaskRgb[hblend->MaskInIndex++];
if(hblend->MaskInIndex >= hblend->MaskSize)
{
__BLEND_INT_MASK_FIFO_EMPTY_DISABLE();
break;
}
}
}
}
/******************************************************************************
* @fn blend_init
*
* @brief Initialize the BLEND according to the specified parameters
* in the BLEND_HandleTypeDef
*
* @param hblend : BLEND_HandleTypeDef structure that contains the
* configuration information for blend module.
*/
void blend_init(BLEND_HandleTypeDef *hblend)
{
/*general config*/
BLEND_AHB0->CONFIG.Bits.BLEND_MODE = hblend->BlendInit.Bits.BLEND_MODE;
BLEND_AHB0->CONFIG.Bits.ORGB_FORMAT = hblend->BlendInit.Bits.OUTRGB_FORMAT;
BLEND_AHB0->CONFIG.Bits.RGB0_FORMAT = hblend->BlendInit.Bits.INRGB0_FORMAT;
BLEND_AHB0->CONFIG.Bits.RGB1_FORMAT = hblend->BlendInit.Bits.INRGB1_FORMAT;
BLEND_AHB0->SRC_ALPHA.Bits.SRC_ALPHA = hblend->BlendInit.Bits.SRC_ALPHA;
BLEND_AHB0->CONFIG.Bits.MASK_CAL_EN = hblend->BlendInit.Bits.MASK_CAL_EN;
BLEND_AHB0->CONFIG.Bits.RGB0_CAL_EN = 1;
BLEND_AHB0->CONFIG.Bits.RGB1_CAL_EN = 1;
BLEND_AHB0->CTRL.Bits.MASK_FF_RST = 1;
BLEND_AHB0->CTRL.Bits.ORGB_FF_RST = 1;
BLEND_AHB0->CTRL.Bits.RGB0_FF_RST = 1;
BLEND_AHB0->CTRL.Bits.RGB1_FF_RST = 1;
BLEND_AHB0->CONFIG.Bits.R_MUL_TC_EN = 1;
BLEND_AHB0->CONFIG.Bits.G_MUL_TC_EN = 1;
BLEND_AHB0->CONFIG.Bits.B_MUL_TC_EN = 1;
BLEND_AHB0->CONFIG.Bits.A_MUL_TC_EN = 1;
BLEND_AHB0->CONFIG.Bits.ORGB_565_R_TC_EN = 1;
BLEND_AHB0->CONFIG.Bits.ORGB_565_G_TC_EN = 1;
BLEND_AHB0->CONFIG.Bits.ORGB_565_B_TC_EN = 1;
BLEND_AHB0->CONFIG.Bits.ORGB_332_R_TC_EN = 1;
BLEND_AHB0->CONFIG.Bits.ORGB_332_G_TC_EN = 1;
BLEND_AHB0->CONFIG.Bits.ORGB_332_B_TC_EN = 1;
BLEND_AHB0->PIXEL_THR.Bits.O565_B_THR = 4;
BLEND_AHB0->PIXEL_THR.Bits.O565_G_THR = 2;
BLEND_AHB0->PIXEL_THR.Bits.O565_R_THR = 4;
BLEND_AHB0->PIXEL_THR.Bits.O332_B_THR = 32;
BLEND_AHB0->PIXEL_THR.Bits.O332_G_THR = 16;
BLEND_AHB0->PIXEL_THR.Bits.O332_R_THR = 16;
/*some option select to config*/
if(hblend->BlendInit.Bits.SRC_IS_PURE == 1)
{
BLEND_AHB0->PIXEL.Bits.PIXEL_ALPHA = hblend->BlendInit.Bits.SRC_ALPHA;
BLEND_AHB0->PIXEL.Bits.PIXEL_DATA = hblend->Pure.Bits.PIXEL;
BLEND_AHB0->CONFIG.Bits.ORGB_MODE = 0;
}
else
{
BLEND_AHB0->CONFIG.Bits.ORGB_MODE = 1;
}
if(hblend->BlendInit.Bits.DMA_IN_EN == 1)
{
BLEND_AHB0->DMAC.Bits.RGB0_DMA_EN = 1;
BLEND_AHB0->DMAC.Bits.RGB1_DMA_EN = 1;
BLEND_AHB0->DMAC.Bits.MASK_DMA_EN = 1;
}
if(hblend->BlendInit.Bits.DMA_OUT_EN == 1)
{
BLEND_AHB0->DMAC.Bits.ORGB_DMA_EN = 1;
}
/*fifo threshold config*/
BLEND_AHB0->INFIFO0_THR_CTL.Bits.RGB0_ALEMPTY_THR = hblend->Infifo0Thr.Bits.ALEMPTY_THR;
BLEND_AHB0->INFIFO0_THR_CTL.Bits.RGB0_ALFULL_THR = 30;
BLEND_AHB0->INFIFO0_THR_CTL.Bits.RGB0_DMA_THR = hblend->Infifo0Thr.Bits.DMA_THR;
BLEND_AHB0->INFIFO1_THR_CTL.Bits.RGB1_ALEMPTY_THR = hblend->Infifo1Thr.Bits.ALEMPTY_THR;
BLEND_AHB0->INFIFO1_THR_CTL.Bits.RGB1_ALFULL_THR = 30;
BLEND_AHB0->INFIFO1_THR_CTL.Bits.RGB1_DMA_THR = hblend->Infifo1Thr.Bits.DMA_THR;
BLEND_AHB0->INFIFOMASK_THR_CTL.Bits.MASK_ALEMPTY_THR = hblend->InfifoMaskThr.Bits.ALEMPTY_THR;
BLEND_AHB0->INFIFOMASK_THR_CTL.Bits.MASK_ALFULL_THR = 30;
BLEND_AHB0->INFIFOMASK_THR_CTL.Bits.MASK_DMA_THR = hblend->InfifoMaskThr.Bits.DMA_THR;
BLEND_AHB0->OUTFIFO_THR_CTL.Bits.ORGB_ALFULL_THR = hblend->OutfifoThr.Bits.ALFULL_THR;
BLEND_AHB0->OUTFIFO_THR_CTL.Bits.ORGB_DMA_THR = hblend->OutfifoThr.Bits.DMA_THR;
BLEND_AHB0->CTRL.Bits.BLEND_EN = 1;
}
/******************************************************************************
* @fn blend_start
*
* @brief Blend start without interrupt.
*
* @param hblend : BLEND HANDLE
* DataParam : BLEND_DataParam_t structure contain pixel need to handle
*/
void blend_start(BLEND_HandleTypeDef *hblend, BLEND_DataParam_t DataParam)
{
uint32_t *SrcRgb;
uint32_t *BackRgb;
uint32_t *Mask;
uint32_t *OutRgb;
uint32_t SrcSize;
uint32_t BackSize;
uint32_t MaskSize;
uint32_t OutSize;
SrcRgb = (uint32_t *)DataParam.SrcRgb;
BackRgb = (uint32_t *)DataParam.BackRgb;
Mask = (uint32_t *)DataParam.MaskRgb;
OutRgb = (uint32_t *)DataParam.OutRgb;
SrcSize = DataParam.PixelCount;
BackSize = DataParam.PixelCount;
MaskSize = DataParam.PixelCount;
OutSize = DataParam.PixelCount;
uint32_t MaskAddValue = 0;
while(hblend->DataOutIndex < OutSize)
{
/*whether txfifo 0 is almost full or not*/
if((!__RGB0_FIFO_IS_ALFULL()) && (hblend->SrcInIndex < SrcSize))
{
BLEND_AHB0->RGB0_DATA = SrcRgb[hblend->SrcInIndex++];
}
/*whether txfifo 1 is full or not*/
if((!__RGB1_FIFO_IS_ALFULL()) && (hblend->BackInIndex < BackSize))
{
BLEND_AHB0->RGB1_DATA = BackRgb[hblend->BackInIndex++];
}
/*whether txfifo mask is full or not*/
if((!__MASK_FIFO_IS_ALFULL()) && (hblend->MaskInIndex < MaskSize) &&
(hblend->BlendInit.Bits.MASK_CAL_EN))
{
BLEND_AHB1->MASK_DATA = Mask[hblend->MaskInIndex++];
}
/*whether rx fifo is empty or not*/
if(BLEND_AHB0->FIFO_STATUS.Bits.ORGB_EMPTY != 1)
{
DataParam.OutRgb[hblend->DataOutIndex++] = BLEND_AHB1->ORGB_DATA;
}
}
}
/******************************************************************************
* @fn blend_start_IT
*
* @brief Blend start with interrupt.
*
* @param hblend : BLEND HANDLE
* DataParam : BLEND_DataParam_t structure contain pixel need to handle
*/
void blend_start_IT(BLEND_HandleTypeDef *hblend, BLEND_DataParam_t DataParam)
{
hblend->SrcRgb = (uint32_t *)DataParam.SrcRgb;
hblend->BackRgb = (uint32_t *)DataParam.BackRgb;
hblend->OutRgb = (uint32_t *)DataParam.OutRgb;
hblend->SrcSize = DataParam.PixelCount;
hblend->BackSize = DataParam.PixelCount;
hblend->MaskSize = DataParam.PixelCount;
hblend->OutSize = DataParam.PixelCount;
hblend->PixelCount = DataParam.PixelCount;
if(hblend->BlendInit.Bits.MASK_CAL_EN == 1)
{
hblend->MaskRgb = (uint32_t *)DataParam.MaskRgb;
__BLEND_INT_MASK_FIFO_EMPTY_ENABLE();
}
__BLEND_INT_RGB0_FIFO_EMPTY_ENABLE();
__BLEND_INT_RGB1_FIFO_EMPTY_ENABLE();
__BLEND_INT_ORGB_FIFO_ALFULL_ENABLE();
}

View File

@ -0,0 +1,117 @@
/*
******************************************************************************
* @file driver_cali.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2023
* @brief Calibration module driver.
* This file provides firmware functions to calibrate RC frequency
******************************************************************************
* @attention
*
* Copyright (c) 2023 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
#include "co_util.h"
/************************************************************************************
* @fn cali_IRQHandler
*
* @brief Handle Calibration interrupt request.
*
* @param hcali: Calibration handle.
*/
__WEAK void cali_IRQHandler(CALI_HandleTypeDef *hcali)
{
__CALI_INT_CLR();
if (hcali->DoneCallback) {
hcali->DoneCallback(hcali, __CALI_RESULT_GET());
}
}
/************************************************************************************
* @fn cali_init
*
* @brief Initialize the calibration module
*
* @param hcali: calibration handle.
*/
void cali_init(CALI_HandleTypeDef *hcali)
{
__CALI_DISABLE();
__CALI_INT_DISABLE();
__CALI_UP_MODE_SET(hcali->mode);
__CALI_CNT_SET(hcali->rc_cnt);
}
/************************************************************************************
* @fn cali_start
*
* @brief start calibration with block mode, call cali_calc_rc_freq to calcuate RC
* frequency with calibration result.
*
* @param hcali: calibration handle.
*
* @return calibration result
*/
uint32_t cali_start(CALI_HandleTypeDef *hcali)
{
uint32_t result;
__CALI_ENABLE();
while (__CALI_IS_DONE() == 0);
result = __CALI_RESULT_GET();
__CALI_DISABLE();
return result;
}
/************************************************************************************
* @fn cali_start_IT
*
* @brief start calibration with interrupt mode
*
* @param hcali: calibration handle.
*/
void cali_start_IT(CALI_HandleTypeDef *hcali)
{
__CALI_INT_ENABLE();
__CALI_ENABLE();
}
/************************************************************************************
* @fn cali_stop
*
* @brief stop on-going calibration
*
* @param hcali: calibration handle.
*/
void cali_stop(CALI_HandleTypeDef *hcali)
{
__CALI_DISABLE();
}
/************************************************************************************
* @fn cali_calc_rc_freq
*
* @brief calculate RC frequency with calibrated result
*
* @param hcali: calibration handle.
* cali_result: calibration result from cali_start or DoneCallback
*
* @return calculate result
*/
uint32_t cali_calc_rc_freq(CALI_HandleTypeDef *hcali, uint32_t cali_result)
{
uint32_t tmp_high,tmp_low;
uint32_t lp_frequency;
mul_64(&tmp_low, &tmp_high, 24000000, hcali->rc_cnt);
lp_frequency = simple_div_64(tmp_low, tmp_high, cali_result);
return lp_frequency;
}

View File

@ -0,0 +1,743 @@
/*
******************************************************************************
* @file driver_can.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2022
* @brief SD controller HAL module driver.
* This file provides firmware functions to manage the
* Controller Area Network (CAN) peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2022 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/************************************************************************************
* @fn can_init
*
* @brief Initializes the CAN peripheral according to the specified
* parameters in the struct_CANInit_t
*
* @param hcan: CAN handle.
*/
void can_init(CAN_HandleTypeDef *hcan)
{
/* Initialization start */
__CAN_INIT_START(hcan->CANx);
__CAN_CHANGE_ENABLE(hcan->CANx);
/* Timestamp enable */
__CAN_SET_TIMESTAMP_SELECT_INTERNAL(hcan->CANx);
/* Bit Rate Prescaler */
__CAN_SET_NOMINAL_RATE_PRESCALER(hcan->CANx, hcan->Init.Prescaler);
/* Data time segment1/segment2 */
__CAN_SET_NOMINAL_TIME_SEG_1(hcan->CANx, hcan->Init.TimeSeg1);
__CAN_SET_NOMINAL_TIME_SEG_2(hcan->CANx, hcan->Init.TimeSeg2);
/* Synchronization Jump Width */
__CAN_SET_NOMINAL_SYNC_WIDTH(hcan->CANx, hcan->Init.SyncJumpWidth);
/* Bus Monitor Mode */
hcan->CANx->CCCtrl.MON = hcan->Init.BusMonitorMode ? 1 : 0;
/* Auto Retransmission mode */
hcan->CANx->CCCtrl.DAR = hcan->Init.AutoRetransmission ? 0 : 1;
/* default transmit Pause enable */
hcan->CANx->CCCtrl.TXP = 1;
hcan->CANx->CCCtrl.BRSE = CAN_FUNC_DISABLE;
/* Global Filter Config */
__CAN_STANDARD_REJECT_UNMATCHED_FRAME(hcan->CANx);
__CAN_EXTENDED_REJECT_UNMATCHED_FRAME(hcan->CANx);
__CAN_STANDARD_FILTER_REMOTE_FRAME(hcan->CANx);
__CAN_EXTENDED_FILTER_REMOTE_FRAME(hcan->CANx);
/* Tx Buffer Transmission Occurred enable */
__CAN_Tx_OCCURRED_INT_ENABLE(hcan->CANx, 0xFFFFFFFF);
/* Int status enable */
__CAN_INT_LINE_ENABLE(hcan->CANx);
}
/************************************************************************************
* @fn can_message_ram_init
*
* @brief initialize standard ID filter / extended ID filter /
* Tx queue Buffer /
* Rx FIFO 0/1 / Rx Buffer
* element size, Nums and start address.
*
* @param hcan: CAN handle.
*/
void can_message_ram_init(CAN_HandleTypeDef *hcan)
{
uint16_t lu16_AddrOffset;
uint16_t lu16_ElementSize;
/* Set message ram high 16bit address */
__CAN_SET_MESSAGE_RAM_HIGHH_16BIT_ADDR(hcan->CANx, hcan->RAMConfig.StartAddress >> 16);
/* ---------------------------------------------*/
/* ----- standard ID filter Buffer config ------*/
/* ---------------------------------------------*/
/* Calculate Start address */
lu16_AddrOffset = hcan->RAMConfig.StartAddress;
/* Set the number of standard message ID filter element */
__CAN_SET_STANDARD_ID_FILTER_LIST_NUMS(hcan->CANx, hcan->RAMConfig.StandardIDFilterNums);
/* Set the start address of standard Message ID filter list */
__CAN_SET_STANDARD_ID_FILTER_LIST_START_ADDRESS(hcan->CANx, lu16_AddrOffset);
/* ---------------------------------------------*/
/* ----- extended ID filter Buffer config ------*/
/* ---------------------------------------------*/
/* Calculate offset address */
lu16_AddrOffset += hcan->RAMConfig.StandardIDFilterNums * 4;
/* Set the number of extended message ID filter element */
__CAN_SET_EXTENDED_ID_FILTER_LIST_NUMS(hcan->CANx, hcan->RAMConfig.ExtendedIDFilterNums);
/* Set the start address of extended Message ID filter list */
__CAN_SET_EXTENDED_ID_FILTER_LIST_START_ADDRESS(hcan->CANx, lu16_AddrOffset);
/* ---------------------------------------------*/
/* ---------- Tx queue Buffer congfig ----------*/
/* ---------------------------------------------*/
/* Calculate offset address */
lu16_AddrOffset += hcan->RAMConfig.ExtendedIDFilterNums * 8;
/* Tx queue operation */
__CAN_SET_Tx_QUEUE_OPERATION(hcan->CANx);
/* Set the Number of Tx Queue element */
__CAN_SET_Tx_FIFO_QUEUE_NUMS(hcan->CANx, hcan->RAMConfig.TxQueueNums);
__CAN_SET_Tx_BUFFER_NUMS(hcan->CANx, 0);
/* Set the start address of Tx Queue section in Message RAM */
__CAN_SET_Tx_BUFFER_START_ADDRESS(hcan->CANx, lu16_AddrOffset);
/* Tx queue element size /
Rx FIFO0 element size /
Rx FIFO1 element size /
Rx Buffer element size */
lu16_ElementSize = 16;
/* classical CAN fixed 16byte */
/* Record element size */
hcan->ElementSize = lu16_ElementSize;
/* ---------------------------------------------*/
/* ------------- Rx FIFO 0 congfig -------------*/
/* ---------------------------------------------*/
/* Calculate offset address */
lu16_AddrOffset += hcan->RAMConfig.TxQueueNums * lu16_ElementSize;
/* FIFO 0 blocking mode */
__CAN_SET_Rx_FIFO0_BLOCKING_MODE(hcan->CANx);
/* Set the Number of Rx FIFO0 element */
__CAN_SET_Rx_FIFO0_NUMS(hcan->CANx, hcan->RAMConfig.RxFIFO0Nums);
/* Set the start address of Rx FIFO 0 section in Message RAM */
__CAN_SET_Rx_FIFO0_START_ADDRESS(hcan->CANx, lu16_AddrOffset);
/* ---------------------------------------------*/
/* ------------- Rx FIFO 1 congfig -------------*/
/* ---------------------------------------------*/
/* Calculate offset address */
lu16_AddrOffset += hcan->RAMConfig.RxFIFO0Nums * lu16_ElementSize;
/* FIFO 1 blocking mode */
__CAN_SET_Rx_FIFO1_BLOCKING_MODE(hcan->CANx);
/* Set the Number of Rx FIFO1 element */
__CAN_SET_Rx_FIFO1_NUMS(hcan->CANx, hcan->RAMConfig.RxFIFO1Nums);
/* Set the start address of Rx FIFO 1 section in Message RAM */
__CAN_SET_Rx_FIFO1_START_ADDRESS(hcan->CANx, lu16_AddrOffset);
/* ---------------------------------------------*/
/* -------- Rx dedicated buffer congfig --------*/
/* ---------------------------------------------*/
/* Calculate offset address */
lu16_AddrOffset += hcan->RAMConfig.RxFIFO1Nums * lu16_ElementSize;
/* Set the start address of Rx dedicated buffer section in Message RAM */
__CAN_SET_Rx_BUFFER_START_ADDRESS(hcan->CANx, lu16_AddrOffset);
/* Initialization stop */
__CAN_CHANGE_DISABLE(hcan->CANx);
__CAN_INIT_STOP(hcan->CANx);
}
/************************************************************************************
* @fn can_ram_watch_dog_config
*
* @brief ram watch dog config.
*
* @param fu8_InitValue: Start value of the Message RAM Watchdog Counter.
* if the value config '00' the counter is disabled.
*/
void can_ram_watch_dog_config(CAN_HandleTypeDef *hcan, uint8_t fu8_InitValue)
{
/* Initialization start */
__CAN_INIT_START(hcan->CANx);
__CAN_CHANGE_ENABLE(hcan->CANx);
__CAM_SET_RAM_WATCHDOG_INITIAL_VALUE(hcan->CANx, fu8_InitValue);
/* Initialization stop */
__CAN_CHANGE_DISABLE(hcan->CANx);
__CAN_INIT_STOP(hcan->CANx);
}
/************************************************************************************
* @fn can_get_ram_watch_dog_value
*
* @brief get ram watch dog counter value.
*/
uint8_t can_get_ram_watch_dog_value(CAN_HandleTypeDef *hcan)
{
return __CAM_GET_RAM_WATCHDOG_VALUE(hcan->CANx);
}
/************************************************************************************
* @fn can_timestamp_Prescaler_config
*
* @brief Configures the timestamp unit in multiples of CAN bit times 1 ~ 16.
*
* @param fu8_prescaler: prescaler value can be 1 ~ 16.
*/
void can_timestamp_prescaler_config(CAN_HandleTypeDef *hcan, uint8_t fu8_prescaler)
{
/* Initialization start */
__CAN_INIT_START(hcan->CANx);
__CAN_CHANGE_ENABLE(hcan->CANx);
__CAN_SET_TIMESTAMP_PRESCALER(hcan->CANx, fu8_prescaler);
/* Initialization stop */
__CAN_CHANGE_DISABLE(hcan->CANx);
__CAN_INIT_STOP(hcan->CANx);
}
/************************************************************************************
* @fn can_timestamp_counter_reset
*
* @brief timestamp counter reset 0.
*/
void can_timestamp_counter_reset(CAN_HandleTypeDef *hcan)
{
__CAN_SET_TIMESTAMP(hcan->CANx);
}
/************************************************************************************
* @fn can_timestamp_counter_reset
*
* @brief get timestamp counter value.
*/
uint16_t can_get_timestamp_counter(CAN_HandleTypeDef *hcan)
{
return __CAN_GET_TIMESTAMP(hcan->CANx);
}
/************************************************************************************
* @fn can_get_transmit_error_counter
* @fn can_get_receive_error_counter
*
* @brief get transmit/receive error counter value.
*/
uint8_t can_get_transmit_error_counter(CAN_HandleTypeDef *hcan)
{
return __CAN_GET_TRANSMIT_ERROR_COUNTER(hcan->CANx);
}
uint8_t can_get_receive_error_counter(CAN_HandleTypeDef *hcan)
{
return __CAN_GET_RECEIVE_ERROR_COUNTER(hcan->CANx);
}
/************************************************************************************
* @fn can_add_tx_message
*
* @brief Add a message to the Tx queue.(classics can)
*
* @param hcan: CAN handle.
* fstr_TxHeader: Tx message header.
* Data: Data buffer pointer.
* @return lu32_PutIndex > 0: Put index in Tx queue.
* Error < 0.
*/
int32_t can_add_tx_message(CAN_HandleTypeDef *hcan, struct_CANTxHeaderDef_t fstr_TxHeader, uint8_t *Data)
{
uint32_t i;
struct_CanTxElement_t *CanTxElement;
uint32_t lu32_Address;
uint32_t lu32_PutIndex;
/* Tx queue full */
if (__CAN_IS_TxFIFO_QUEUE_FULL(hcan->CANx))
return CAN_ERR_TXFIFO_FULL;
/* the start address of Tx Queue section in Message RAM */
lu32_Address = __CAN_GET_MESSAGE_RAM_HIGHH_16BIT_ADDR(hcan->CANx) << 16;
lu32_Address |= __CAN_GET_Tx_BUFFER_START_ADDRESS(hcan->CANx);
/* Calculate element offset address */
lu32_PutIndex = __CAN_GET_TxFIFO_QUEUE_PUT_INDEX(hcan->CANx);
lu32_Address += lu32_PutIndex * hcan->ElementSize;
/* write param/data to message ram */
CanTxElement = (struct_CanTxElement_t *)lu32_Address;
/* Frame type, data or remote */
CanTxElement->FrameCFG.XTD = fstr_TxHeader.IdType;
if (fstr_TxHeader.IdType == CAN_ID_STANDARD)
CanTxElement->FrameCFG.ID = fstr_TxHeader.Identifier << 18;
else
CanTxElement->FrameCFG.ID = fstr_TxHeader.Identifier;
/* Data frame */
if (fstr_TxHeader.FrameType == CAN_DATA_FRAME)
{
CanTxElement->FrameCFG.DLC = fstr_TxHeader.DLC;
CanTxElement->FrameCFG.RTR = CAN_DATA_FRAME;
for (i = 0; i < fstr_TxHeader.DLC; i++)
{
CanTxElement->Data[i] = Data[i];
}
}
/* Remote frame */
else
{
CanTxElement->FrameCFG.DLC = 0;
CanTxElement->FrameCFG.RTR = CAN_REMOTE_FRAM;
}
/* Add request */
__CAN_ADD_Tx_REQUEST(hcan->CANx, 1 << lu32_PutIndex);
return lu32_PutIndex;
}
/************************************************************************************
* @fn can_is_tx_message_pending
*
* @brief Check if a transmission request is pending.
*
* @param hcan: CAN handle.
* fu32_PutIndex: tx message index in Tx queue.
* @return true: tx message pending.
* false: tx message not pending.
*/
bool can_is_tx_message_pending(CAN_HandleTypeDef *hcan, uint32_t fu32_PutIndex)
{
bool lb_status;
return lb_status = (__CAN_GET_Tx_REQUEST_PENDING(hcan->CANx) & (1 << fu32_PutIndex)) ? true : false;
}
/************************************************************************************
* @fn can_abort_tx_message
*
* @brief abort a message from the Tx queue.
*
* @param hcan: CAN handle.
* fu32_PutIndex: tx message index in Tx queue.
*/
void can_abort_tx_message(CAN_HandleTypeDef *hcan, uint32_t fu32_PutIndex)
{
/* Tx Buffer Cancellation Request */
__CAN_CANCELLATION_Tx_REQUEST(hcan->CANx, 1 << fu32_PutIndex);
}
/************************************************************************************
* @fn can_add_standard_filter
*
* @brief Added standard filter config.
*
* @param hcan: CAN handle.
* fstr_FilterCfg: standard filter config param.
* fu32_Index: filter number index.
*/
void can_add_standard_filter(CAN_HandleTypeDef *hcan, struct_FilterCfg_t fstr_FilterCfg, uint32_t fu32_Index)
{
uint32_t lu32_Address;
struct_StdFilterElement_t *StdFilterElement;
/* Set the start address of standard Message ID filter list */
lu32_Address = __CAN_GET_MESSAGE_RAM_HIGHH_16BIT_ADDR(hcan->CANx) << 16;
lu32_Address |= __CAN_GET_STANDARD_ID_FILTER_LIST_START_ADDRESS(hcan->CANx);
/* Calculate element offset address */
lu32_Address += fu32_Index * 4;
/* write param/data to message ram */
StdFilterElement = (struct_StdFilterElement_t *)lu32_Address;
StdFilterElement->SFT = fstr_FilterCfg.FilterType;
StdFilterElement->SFEC = fstr_FilterCfg.ProcessMode;
StdFilterElement->SFID1 = fstr_FilterCfg.StdFilterID_1;
StdFilterElement->SFID2 = fstr_FilterCfg.StdFilterID_2;
if (fstr_FilterCfg.ProcessMode == FILTER_PROCESS_STORE_IN_RxBUFFER)
{
StdFilterElement->SFID2 = fstr_FilterCfg.RxBufferIndex;
if (fstr_FilterCfg.RxBufferIndex < 32)
hcan->RxBufferUsed_L |= 1 << fstr_FilterCfg.RxBufferIndex;
else
hcan->RxBufferUsed_H |= 1 << (fstr_FilterCfg.RxBufferIndex - 32);
}
}
/************************************************************************************
* @fn can_add_extended_filter
*
* @brief Added extended filter config.
*
* @param hcan: CAN handle.
* fstr_FilterCfg: extended filter config param.
* fu32_Index: filter number index.
*/
void can_add_extended_filter(CAN_HandleTypeDef *hcan, struct_FilterCfg_t fstr_FilterCfg, uint32_t fu32_Index)
{
uint32_t lu32_Address;
struct_ExtFilterElement_t *ExtFilterElement;
/* Set the start address of extended Message ID filter list */
lu32_Address = __CAN_GET_MESSAGE_RAM_HIGHH_16BIT_ADDR(hcan->CANx) << 16;
lu32_Address |= __CAN_GET_EXTENDED_ID_FILTER_LIST_START_ADDRESS(hcan->CANx);
/* Calculate element offset address */
lu32_Address += fu32_Index * 8;
/* write param/data to message ram */
ExtFilterElement = (struct_ExtFilterElement_t *)lu32_Address;
ExtFilterElement->EFT = fstr_FilterCfg.FilterType;
ExtFilterElement->EFEC = fstr_FilterCfg.ProcessMode;
ExtFilterElement->EFID1 = fstr_FilterCfg.StdFilterID_1;
ExtFilterElement->EFID2 = fstr_FilterCfg.StdFilterID_2;
if (fstr_FilterCfg.ProcessMode == FILTER_PROCESS_STORE_IN_RxBUFFER)
{
ExtFilterElement->EFID2 = fstr_FilterCfg.RxBufferIndex;
if (fstr_FilterCfg.RxBufferIndex < 32)
hcan->RxBufferUsed_L |= 1 << fstr_FilterCfg.RxBufferIndex;
else
hcan->RxBufferUsed_H |= 1 << (fstr_FilterCfg.RxBufferIndex - 32);
}
}
/************************************************************************************
* @fn can_remove_standard_filter
*
* @brief Remove standard filter config.
*
* @param hcan: CAN handle.
* fu32_Index: filter number index.
*/
void can_remove_standard_filter(CAN_HandleTypeDef *hcan, uint32_t fu32_Index)
{
uint32_t lu32_Address;
struct_StdFilterElement_t *StdFilterElement;
/* Set the start address of standard Message ID filter list */
lu32_Address = __CAN_GET_MESSAGE_RAM_HIGHH_16BIT_ADDR(hcan->CANx) << 16;
lu32_Address |= __CAN_GET_STANDARD_ID_FILTER_LIST_START_ADDRESS(hcan->CANx);
/* Calculate element offset address */
lu32_Address += fu32_Index * 4;
/* write param/data to message ram */
StdFilterElement = (struct_StdFilterElement_t *)lu32_Address;
/* Disable selected element */
if (StdFilterElement->SFEC == FILTER_PROCESS_STORE_IN_RxBUFFER)
{
if (StdFilterElement->SFID2 < 32)
hcan->RxBufferUsed_L &= ~(1 << StdFilterElement->SFID2);
else
hcan->RxBufferUsed_H &= ~(1 << (StdFilterElement->SFID2 - 32));
}
StdFilterElement->SFT = CAN_FILTER_DISABLE;
StdFilterElement->SFEC = FILTER_PROCESS_DISABLE;
}
/************************************************************************************
* @fn can_remove_extended_filter
*
* @brief Remove extended filter config.
*
* @param hcan: CAN handle.
* fu32_Index: filter number index.
*/
void can_remove_extended_filter(CAN_HandleTypeDef *hcan, uint32_t fu32_Index)
{
uint32_t lu32_Address;
struct_ExtFilterElement_t *ExtFilterElement;
/* Set the start address of extended Message ID filter list */
lu32_Address = __CAN_GET_MESSAGE_RAM_HIGHH_16BIT_ADDR(hcan->CANx) << 16;
lu32_Address |= __CAN_GET_EXTENDED_ID_FILTER_LIST_START_ADDRESS(hcan->CANx);
/* Calculate element offset address */
lu32_Address += fu32_Index * 8;
/* write param/data to message ram */
ExtFilterElement = (struct_ExtFilterElement_t *)lu32_Address;
/* Disable selected element */
if (ExtFilterElement->EFEC == FILTER_PROCESS_STORE_IN_RxBUFFER)
{
if (ExtFilterElement->EFID2 < 32)
hcan->RxBufferUsed_L &= ~(1 << ExtFilterElement->EFID2);
else
hcan->RxBufferUsed_H &= ~(1 << (ExtFilterElement->EFID2 - 32));
}
ExtFilterElement->EFEC = FILTER_PROCESS_DISABLE;
}
/************************************************************************************
* @fn can_get_rxbuffer_message
*
* @brief Get an CAN frame from the Rx buffer.
*
* @param hcan: CAN handle.
* fu32_RxBufferIndex: The message index in the RxBuffer.
*/
void can_get_rxbuffer_message(CAN_HandleTypeDef *hcan, uint32_t fu32_RxBufferIndex, struct_CANRxHeaderDef_t *RxHeader, uint8_t *Data)
{
uint32_t lu32_Address;
struct_CanRxElement_t *CanRxElement;
/* Get the start address of Rx dedicated buffer section in Message RAM */
lu32_Address = __CAN_GET_MESSAGE_RAM_HIGHH_16BIT_ADDR(hcan->CANx) << 16;
lu32_Address |= __CAN_GET_Rx_BUFFER_START_ADDRESS(hcan->CANx);
/* Calculate element offset address */
lu32_Address += fu32_RxBufferIndex * hcan->ElementSize;
/* Read message param/data from RxBuffer ram */
CanRxElement = (struct_CanRxElement_t *)lu32_Address;
RxHeader->IdType = CanRxElement->FrameCFG.XTD ? CAN_ID_EXTENDED : CAN_ID_STANDARD;
RxHeader->Identifier = CanRxElement->FrameCFG.ID;
RxHeader->FrameType = CanRxElement->FrameCFG.RTR ? CAN_REMOTE_FRAM : CAN_DATA_FRAME;
if (RxHeader->FrameType == CAN_DATA_FRAME)
{
RxHeader->DLC = CanRxElement->FrameCFG.DLC;
for (int i = 0; i < RxHeader->DLC; i++)
{
Data[i] = CanRxElement->Data[i];
}
}
RxHeader->Timestamp = CanRxElement->FrameCFG.RXTS;
if (CanRxElement->FrameCFG.ANMF == 0)
{
RxHeader->FilterMatchIndex = CanRxElement->FrameCFG.FIDX;
}
}
/************************************************************************************
* @fn can_get_rxfifo0_message
*
* @brief Get an CAN frame from the Rx FIFO 0.
*
* @param hcan: CAN handle.
*/
uint32_t can_get_rxfifo0_message(CAN_HandleTypeDef *hcan, struct_CANRxHeaderDef_t *RxHeader, uint8_t *Data)
{
uint32_t lu32_Address, lu32_GetIndex;
struct_CanRxElement_t *CanRxElement;
/* Rx FIFO0 get index */
lu32_GetIndex = __CAN_GET_Rx_FIFO0_GET_INDEX(hcan->CANx);
/* Get the start address of Rx FIFO 0 section in Message RAM */
lu32_Address = __CAN_GET_MESSAGE_RAM_HIGHH_16BIT_ADDR(hcan->CANx) << 16;
lu32_Address |= __CAN_GET_Rx_FIFO0_START_ADDRESS(hcan->CANx);
/* Calculate element offset address */
lu32_Address += lu32_GetIndex * hcan->ElementSize;
/* Read message param/data from RxBuffer ram */
CanRxElement = (struct_CanRxElement_t *)lu32_Address;
RxHeader->IdType = CanRxElement->FrameCFG.XTD ? CAN_ID_EXTENDED : CAN_ID_STANDARD;
RxHeader->FrameType = CanRxElement->FrameCFG.RTR ? CAN_REMOTE_FRAM : CAN_DATA_FRAME;
if (RxHeader->IdType == CAN_ID_STANDARD)
RxHeader->Identifier = CanRxElement->FrameCFG.ID >> 18;
else
RxHeader->Identifier = CanRxElement->FrameCFG.ID;
if (RxHeader->FrameType == CAN_DATA_FRAME)
{
RxHeader->DLC = CanRxElement->FrameCFG.DLC;
for (int i = 0; i < RxHeader->DLC; i++)
{
Data[i] = CanRxElement->Data[i];
}
}
RxHeader->Timestamp = CanRxElement->FrameCFG.RXTS;
if (CanRxElement->FrameCFG.ANMF == 0)
{
RxHeader->FilterMatchIndex = CanRxElement->FrameCFG.FIDX;
}
/* Read message ack */
__CAN_SET_Rx_FIFO0_ACKNOWLEDGE(hcan->CANx, lu32_GetIndex);
return lu32_GetIndex;
}
/************************************************************************************
* @fn can_get_rxfifo1_message
*
* @brief Get an CAN frame from the Rx FIFO 1.
*
* @param hcan: CAN handle.
*/
uint32_t can_get_rxfifo1_message(CAN_HandleTypeDef *hcan, struct_CANRxHeaderDef_t *RxHeader, uint8_t *Data)
{
uint32_t lu32_Address, lu32_GetIndex;
struct_CanRxElement_t *CanRxElement;
/* Rx FIFO1 get index */
lu32_GetIndex = __CAN_GET_Rx_FIFO1_GET_INDEX(hcan->CANx);
/* Get the start address of Rx FIFO 1 section in Message RAM */
lu32_Address = __CAN_GET_MESSAGE_RAM_HIGHH_16BIT_ADDR(hcan->CANx) << 16;
lu32_Address |= __CAN_GET_Rx_FIFO1_START_ADDRESS(hcan->CANx);
/* Calculate element offset address */
lu32_Address += lu32_GetIndex * hcan->ElementSize;
/* Read message param/data from RxBuffer ram */
CanRxElement = (struct_CanRxElement_t *)lu32_Address;
RxHeader->IdType = CanRxElement->FrameCFG.XTD ? CAN_ID_EXTENDED : CAN_ID_STANDARD;
RxHeader->FrameType = CanRxElement->FrameCFG.RTR ? CAN_REMOTE_FRAM : CAN_DATA_FRAME;
if (RxHeader->IdType == CAN_ID_STANDARD)
RxHeader->Identifier = CanRxElement->FrameCFG.ID >> 18;
else
RxHeader->Identifier = CanRxElement->FrameCFG.ID;
if (RxHeader->FrameType == CAN_DATA_FRAME)
{
RxHeader->DLC = CanRxElement->FrameCFG.DLC;
for (int i = 0; i < RxHeader->DLC; i++)
{
Data[i] = CanRxElement->Data[i];
}
}
RxHeader->Timestamp = CanRxElement->FrameCFG.RXTS;
if (CanRxElement->FrameCFG.ANMF == 0)
{
RxHeader->FilterMatchIndex = CanRxElement->FrameCFG.FIDX;
}
/* Read message ack */
__CAN_SET_Rx_FIFO1_ACKNOWLEDGE(hcan->CANx, lu32_GetIndex);
return lu32_GetIndex;
}
/************************************************************************************
* @fn can_get_rxfifo0_fill_level
*
* @brief Get number of elements stored in Rx FIFO 0, range 0 to 64.
*
* @param hcan: CAN handle.
*/
uint32_t can_get_rxfifo0_fill_level(CAN_HandleTypeDef *hcan)
{
return __CAN_GET_Rx_FIFO0_FILL_LEVEL(hcan->CANx);
}
/************************************************************************************
* @fn can_get_rxfifo1_fill_level
*
* @brief Get number of elements stored in Rx FIFO 0, range 0 to 64.
*
* @param hcan: CAN handle.
*/
uint32_t can_get_rxfifo1_fill_level(CAN_HandleTypeDef *hcan)
{
return __CAN_GET_Rx_FIFO1_FILL_LEVEL(hcan->CANx);
}
/************************************************************************************
* @fn can_get_rxbuffer_0_31_status
*
* @brief get rx buffer new data 0~31 status.
*
* @param hcan: CAN handle.
*/
uint32_t can_get_rxbuffer_0_31_status(CAN_HandleTypeDef *hcan)
{
return hcan->CANx->NewData1;
}
/************************************************************************************
* @fn can_get_rxbuffer_32_63_status
*
* @brief get rx buffer new data 32~63 status.
*
* @param hcan: CAN handle.
*/
uint32_t can_get_rxbuffer_32_63_status(CAN_HandleTypeDef *hcan)
{
return hcan->CANx->NewData2;
}
/************************************************************************************
* @fn can_int_enable
*
* @brief can interrupt enable.
*/
void can_int_enable(CAN_HandleTypeDef *hcan, enum_CAN_INT_Status_t fe_INT_Index)
{
__CAN_INT_ENABLE(hcan->CANx, fe_INT_Index);
}
/************************************************************************************
* @fn can_int_disable
*
* @brief can interrupt disable.
*/
void can_int_disable(CAN_HandleTypeDef *hcan, enum_CAN_INT_Status_t fe_INT_Index)
{
__CAN_INT_DISABLE(hcan->CANx, fe_INT_Index);
}
/************************************************************************************
* @fn can_get_int_status
*
* @brief get interrupt status.
*/
bool can_get_int_status(CAN_HandleTypeDef *hcan, enum_CAN_INT_Status_t fe_INT_Index)
{
bool lb_Status = (__CAN_INT_GET_STATUS(hcan->CANx) & fe_INT_Index) ? true : false;
return lb_Status;
}
/************************************************************************************
* @fn can_clear_int_status
*
* @brief clear interrupt status.
*/
void can_clear_int_status(CAN_HandleTypeDef *hcan, enum_CAN_INT_Status_t fe_INT_Index)
{
__CAN_INT_CLEAR(hcan->CANx, fe_INT_Index);
}

View File

@ -0,0 +1,876 @@
/*
******************************************************************************
* @file driver_codec.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2022
* @brief codec HAL module driver.
* This file provides firmware functions to manage the
* codec, include ADC, DAC, DRC, GPF, etc.
******************************************************************************
* @attention
*
* Copyright (c) 2022 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/************************************************************************************
* @fn codec_ASRC0_config
*
* @brief Asynchronous Sampling Rate converter Config.
*/
__attribute__((weak)) void codec_ASRC0_config(CODEC_HandleTypeDef *hcodec)
{
__CODEC_ASRC0_BYPASS();
}
/************************************************************************************
* @fn codec_GPF0_config
*
* @brief general purpose filter Config.
*/
__attribute__((weak)) void codec_GPF0_config(CODEC_HandleTypeDef *hcodec)
{
__CODEC_GPF0_BYPASS();
}
/************************************************************************************
* @fn codec_ALC_config
*
* @brief automatic gain control Config.
*/
__attribute__((weak)) void codec_ALC_config(CODEC_HandleTypeDef *hcodec)
{
__CODEC_ALC_BYPASS();
}
/************************************************************************************
* @fn codec_ASRC1_config
*
* @brief Asynchronous Sampling Rate converter Config.
*/
__attribute__((weak)) void codec_ASRC1_config(CODEC_HandleTypeDef *hcodec)
{
__CODEC_ASRC1_BYPASS();
}
/************************************************************************************
* @fn codec_GPF1_config
*
* @brief general purpose filter Config.
*/
__attribute__((weak)) void codec_GPF1_config(CODEC_HandleTypeDef *hcodec)
{
__CODEC_GPF1_BYPASS();
}
/************************************************************************************
* @fn codec_DRC_config
*
* @brief Dynamic Range Control Config.
*/
__attribute__((weak)) void codec_DRC_config(CODEC_HandleTypeDef *hcodec)
{
__CODEC_DRC_BYPASS();
}
/************************************************************************************
* @fn codec_analog_config
*
* @brief analog Config.
*/
__attribute__((weak)) void codec_analog_config(CODEC_HandleTypeDef *hcodec)
{
CODEC->CodecAna0 = CODEC_ANALOG0_CFG;
CODEC->CodecAna1 = CODEC_ANALOG1_CFG;
CODEC->CodecAna2 = CODEC_ANALOG2_CFG;
CODEC->CodecAna3 = CODEC_ANALOG3_CFG;
}
/************************************************************************************
* @fn codec_input_config
*
* @brief Input routing config.
*/
void codec_input_config(CODEC_HandleTypeDef *hcodec)
{
/* Input ADC config */
if (hcodec->Init.Codec_Input_sel == INPUT_SELECT_ADC)
{
/* ADC clock cource */
CODEC->AdcCfg.CLK_SOURCE = hcodec->InputConfig.ADC_ClockSource; /* Default USB 24M */
if (CODEC->AdcCfg.CLK_SOURCE == CODEC_CLOCK_SOURCE_24M_MODE)
CODEC->AdcCfg.USB_MODE = 1;
else
CODEC->AdcCfg.USB_MODE = 0;
/* ADC Over sampling Level */
CODEC->AdcCfg.OV_SAMPLE_MODE = hcodec->InputConfig.ADC_Oversampling_Level;
/* ADC Sample Rate */
CODEC->AdcCfg.SAMPLE_RATE = hcodec->InputConfig.ADC_SampleRate;
/* Clock/Module control */
__CODEC_ADC_CLK_ENABLE();
__CODEC_I2S_RX_CLK_DISABLE();
__CODEC_ADC_RESET();
while(__CODEC_GET_RESET_STATUS() & CODEC_RESET_ADC);
__CODEC_ADC_ENABLE();
__CODEC_I2S_RX_DISABLE();
}
/* Input I2S config */
else
{
/* Master/Slave */
CODEC->I2SRxCtrl.I2S_MODE = hcodec->InputConfig.I2S_RX_Mode;
/* communication standard */
CODEC->I2SRxCtrl.FORMAT = hcodec->InputConfig.I2S_RX_Standard;
/* data format */
CODEC->I2SRxCtrl.DCI_WL = hcodec->InputConfig.I2S_RX_DataFormat;
/* Channel Copy Enable */
CODEC->I2SRxCtrl.CHANNEL_CP = hcodec->InputConfig.I2S_RX_ChannelCopy;
if (hcodec->InputConfig.I2S_RX_Mode == CODEC_I2S_MODE_MASTER)
{
/* frequency */
//hcodec->InputConfig.I2S_TX_AudioFreq;
}
/* Clock/Module control */
__CODEC_ADC_CLK_DISABLE();
__CODEC_I2S_RX_CLK_ENABLE();
__CODEC_ADC_DISABLE();
__CODEC_I2S_RX_ENABLE();
}
/* Input routing config */
switch (hcodec->Init.Codec_Input_Routing_sel)
{
/* IN -> ASRC0 -> GPF0 -> ALC -> ADC_FIFO */
case INPUT_ROUTING_ASRC0_GPF0_ALC_ADCFF:
{
/* Codec rxin */
__CODEC_ASRC0_SOURCE_SELECT(0);
/* ASRC0 out */
__CODEC_GPF0_CH0_SOURCE_SELECT(2);
__CODEC_GPF0_CH1_SOURCE_SELECT(2);
/* Clock control */
__CODEC_ASRC0_CLK_ENABLE();
__CODEC_ASRC0_INPUT_SAMPLE_CLK_ENABLE();
__CODEC_ASRC0_OUTPUT_SAMPLE_CLK_ENABLE();
__CODEC_ASRC0_OUT_LVD_CLK_ENABLE();
__CODEC_GPF0_CLK_ENABLE();
__CODEC_ALC_CLK_ENABLE();
__CODEC_ADCFIFO_CLK_ENABLE();
/* Module control */
__CODEC_ASRC0_ENABLE();
__CODEC_GPF0_ENABLE();
__CODEC_ALC_ENABLE();
codec_ASRC0_config(hcodec);
codec_GPF0_config(hcodec);
codec_ALC_config(hcodec);
}break;
/* IN -> GPF0 -> ALC -> ADC_FIFO */
case INPUT_ROUTING_GPF0_ALC_ADCFF:
{
/* ASRC0 bypass */
__CODEC_ASRC0_BYPASS();
/* Codec rxin */
__CODEC_GPF0_CH0_SOURCE_SELECT(3);
__CODEC_GPF0_CH1_SOURCE_SELECT(3);
/* Clock control */
__CODEC_ASRC0_CLK_DISABLE();
__CODEC_ASRC0_INPUT_SAMPLE_CLK_DISABLE();
__CODEC_ASRC0_OUTPUT_SAMPLE_CLK_DISABLE();
__CODEC_ASRC0_OUT_LVD_CLK_DISABLE();
__CODEC_GPF0_CLK_ENABLE();
__CODEC_ALC_CLK_ENABLE();
__CODEC_ADCFIFO_CLK_ENABLE();
/* Module control */
__CODEC_ASRC0_DISABLE();
__CODEC_GPF0_ENABLE();
__CODEC_ALC_ENABLE();
codec_GPF0_config(hcodec);
codec_ALC_config(hcodec);
}break;
default:break;
}
}
/************************************************************************************
* @fn codec_input_config
*
* @brief output routing config.
*/
void codec_output_config(CODEC_HandleTypeDef *hcodec)
{
/* Output DAC config */
if (hcodec->Init.Codec_Output_sel == OUTPUT_SELECT_DAC)
{
/* ADC clock cource */
CODEC->DacCfg.CLK_SOURCE = hcodec->OutputConfig.DAC_ClockSource; /* Default USB 24M */
if (CODEC->DacCfg.CLK_SOURCE == CODEC_CLOCK_SOURCE_24M_MODE)
CODEC->DacCfg.USB_MODE = 1;
else
CODEC->DacCfg.USB_MODE = 0;
/* DAC Over sampling Level */
CODEC->DacCfg.OV_SAMPLE_MODE = hcodec->OutputConfig.DAC_Oversampling_Level;
/* DAC Sample Rate */
CODEC->DacCfg.SAMPLE_RATE = hcodec->OutputConfig.DAC_SampleRate;
/* Clock control */
__CODEC_DAC_CLK_ENABLE();
__CODEC_I2S_TX_CLK_DISABLE();
__CODEC_DAC_RESET();
while(__CODEC_GET_RESET_STATUS() & CODEC_RESET_DAC);
__CODEC_DAC_ENABLE();
__CODEC_I2S_TX_DISABLE();
}
/* Output I2S config */
else
{
/* Master/Slave */
CODEC->I2STxCtrl.I2S_MODE = hcodec->OutputConfig.I2S_TX_Mode;
/* communication standard */
CODEC->I2STxCtrl.FORMAT = hcodec->OutputConfig.I2S_TX_Standard;
/* data format */
CODEC->I2STxCtrl.DCI_WL = hcodec->OutputConfig.I2S_TX_DataFormat;
/* Channel Copy Enable */
CODEC->I2STxCtrl.CHANNEL_CP = hcodec->OutputConfig.I2S_TX_ChannelCopy;
if (hcodec->OutputConfig.I2S_TX_Mode == CODEC_I2S_MODE_MASTER)
{
/* frequency */
//hcodec->InputConfig.I2S_TX_AudioFreq;
}
/* Clock control */
__CODEC_DAC_CLK_DISABLE();
__CODEC_I2S_TX_CLK_ENABLE();
}
/* Output routing config */
switch (hcodec->Init.Codec_Output_Routing_sel)
{
/* DACFIFO_LR -> ASRC1 -> GPF1 -> DRC -> OUT */
case OUTPUT_ROUTING_DACFFLR_ASRC1_GPF1_DRC:
{
/* TxFIFO_LR */
__CODEC_ASRC1_SOURCE_SELECT(1);
/* ASRC1 out */
__CODEC_GPF1_CH0_SOURCE_SELECT(3);
__CODEC_GPF1_CH1_SOURCE_SELECT(3);
/* Clock control */
__CODEC_ASRC1_CLK_ENABLE();
__CODEC_ASRC1_INPUT_SAMPLE_CLK_ENABLE();
__CODEC_ASRC1_OUTPUT_SAMPLE_CLK_ENABLE();
__CODEC_ASRC1_OUT_LVD_CLK_ENABLE();
__CODEC_GPF1_CLK_ENABLE();
__CODEC_DRC_CLK_ENABLE();
__CODEC_DACFIFO_LR_CLK_ENABLE();
__CODEC_DACFIFO_01_CLK_DISABLE();
/* Module control */
__CODEC_DAC_FIFO_LR_ENABLE();
__CODEC_DAC_FIFO_01_DISABLE();
__CODEC_ASRC1_ENABLE();
__CODEC_GPF1_ENABLE();
__CODEC_DRC_ENABLE();
codec_ASRC1_config(hcodec);
codec_GPF1_config(hcodec);
codec_DRC_config(hcodec);
}break;
/* DACFIFO_LR -> GPF1 -> DRC -> OUT */
case OUTPUT_ROUTING_DACFFLR_GPF1_DRC:
{
/* ASRC1 bypass */
__CODEC_ASRC1_BYPASS();
/* TxFIFO_LR*/
__CODEC_GPF1_CH0_SOURCE_SELECT(1);
__CODEC_GPF1_CH1_SOURCE_SELECT(1);
/* Clock control */
__CODEC_ASRC1_CLK_DISABLE();
__CODEC_ASRC1_INPUT_SAMPLE_CLK_DISABLE();
__CODEC_ASRC1_OUTPUT_SAMPLE_CLK_DISABLE();
__CODEC_ASRC1_OUT_LVD_CLK_DISABLE();
__CODEC_GPF1_CLK_ENABLE();
__CODEC_DRC_CLK_ENABLE();
__CODEC_DACFIFO_LR_CLK_ENABLE();
__CODEC_DACFIFO_01_CLK_DISABLE();
/* Module control */
__CODEC_DAC_FIFO_LR_ENABLE();
__CODEC_DAC_FIFO_01_DISABLE();
__CODEC_ASRC1_DISABLE();
__CODEC_GPF1_ENABLE();
__CODEC_DRC_ENABLE();
codec_GPF1_config(hcodec);
codec_DRC_config(hcodec);
}break;
/* DACFIFO_LR & DACFIFO_01 -> ASRC1 -> GPF1 -> DRC -> OUT */
case OUTPUT_ROUTING_DACFFLR_DACFF01_ASRC1_GPF1_DRC:
{
/* TxFIFO_01 */
__CODEC_ASRC1_SOURCE_SELECT(2);
/* TxFIFO_LR*/
__CODEC_GPF1_CH0_SOURCE_SELECT(1);
/* ASRC1 out */
__CODEC_GPF1_CH1_SOURCE_SELECT(3);
/* Clock control */
__CODEC_ASRC1_CLK_ENABLE();
__CODEC_ASRC1_INPUT_SAMPLE_CLK_ENABLE();
__CODEC_ASRC1_OUTPUT_SAMPLE_CLK_ENABLE();
__CODEC_ASRC1_OUT_LVD_CLK_ENABLE();
__CODEC_GPF1_CLK_ENABLE();
__CODEC_DRC_CLK_ENABLE();
__CODEC_DACFIFO_LR_CLK_ENABLE();
__CODEC_DACFIFO_01_CLK_ENABLE();
/* Module control */
__CODEC_DAC_FIFO_LR_ENABLE();
__CODEC_DAC_FIFO_01_ENABLE();
__CODEC_ASRC1_ENABLE();
__CODEC_GPF1_ENABLE();
__CODEC_DRC_ENABLE();
codec_ASRC1_config(hcodec);
codec_GPF1_config(hcodec);
codec_DRC_config(hcodec);
}break;
/* DACFIFO_LR & DACFIFO_01 -> GPF1 -> DRC -> OUT */
case OUTPUT_ROUTING_DACFFLR_DACFF01_GPF1_DRC:
{
/* ASRC1 bypass */
__CODEC_ASRC1_BYPASS();
/* TxFIFO_LR*/
__CODEC_GPF1_CH0_SOURCE_SELECT(1);
/* TxFIFO_01 */
__CODEC_GPF1_CH1_SOURCE_SELECT(0);
/* Clock control */
__CODEC_ASRC1_CLK_DISABLE();
__CODEC_ASRC1_INPUT_SAMPLE_CLK_DISABLE();
__CODEC_ASRC1_OUTPUT_SAMPLE_CLK_DISABLE();
__CODEC_ASRC1_OUT_LVD_CLK_DISABLE();
__CODEC_GPF1_CLK_ENABLE();
__CODEC_DRC_CLK_ENABLE();
__CODEC_DACFIFO_LR_CLK_ENABLE();
__CODEC_DACFIFO_01_CLK_ENABLE();
/* Module control */
__CODEC_DAC_FIFO_LR_ENABLE();
__CODEC_DAC_FIFO_01_ENABLE();
__CODEC_ASRC1_DISABLE();
__CODEC_GPF1_ENABLE();
__CODEC_DRC_ENABLE();
codec_GPF1_config(hcodec);
codec_DRC_config(hcodec);
}break;
default:break;
}
}
/************************************************************************************
* @fn codec_init
*
* @brief Initialize the Codec according to the specified parameters.
*
* @param hcodec: Codec handle.
*/
void codec_init(CODEC_HandleTypeDef *hcodec)
{
/* FIFO Data Format */
CODEC->FFRoute.ADCFF_L_SRC = 0;
CODEC->FFRoute.ADCFF_R_SRC = 0;
CODEC->FFRoute.ADCFF_BITWD = hcodec->Init.ADC_DataFormat;
CODEC->FFRoute.DACFF_LR_BITWD = hcodec->Init.DAC_LR_DataFormat;
CODEC->FFRoute.DACFF_01_BITWD = hcodec->Init.DAC_01_DataFormat;
/* Analog config */
codec_analog_config(hcodec);
/* Input routing config */
if (hcodec->Init.Codec_Input_sel < INPUT_SELECT_BYPASS)
{
/* Input select */
CODEC->CodecRoute.ADC_SEL = hcodec->Init.Codec_Input_sel;
codec_input_config(hcodec);
}
/* Output routing config */
if (hcodec->Init.Codec_Output_sel < OUTPUT_SELECT_BYPASS)
{
/* Output select */
CODEC->CodecRoute.DAC_SEL = hcodec->Init.Codec_Output_sel;
codec_output_config(hcodec);
}
/* MCLK Out config */
if (hcodec->Init.Codec_Input_sel == INPUT_SELECT_I2S_RX || \
hcodec->Init.Codec_Output_sel == OUTPUT_SELECT_I2S_TX)
{
if (hcodec->MCLKConfig.MCLK_Out_Enable == MCLK_OUT_ENABLE)
{
CODEC->MCLKCfg.EN = MCLK_OUT_ENABLE;
CODEC->MCLKCfg.MCLK_SRC = hcodec->MCLKConfig.MCLK_Source;
CODEC->MCLKCfg.DIV_TYPE = hcodec->MCLKConfig.MCLK_DIV_Mode;
CODEC->MCLKCfg.DIV = hcodec->MCLKConfig.MCLK_DIV;
}
}
}
/************************************************************************************
* @fn codec_deinit
*
* @brief Close the Codec.
*
* @param hcodec: Codec handle.
*/
void codec_deinit(CODEC_HandleTypeDef *hcodec)
{
__CODEC_ALL_MODULE_RESET();
__CODEC_ALL_DISABLE();
__SYSTEM_CODEC_RESET();
}
/************************************************************************************
* @fn codec_Set_ADC_Volume
*
* @brief Set ADC Volume.
*
* @param fu32_Volume: volume = 20*lg(fu32_Volume/2^13)
*/
void codec_Set_ADC_Volume(uint32_t fu32_Volume)
{
CODEC->AdcVolume.VOLUME = fu32_Volume;
}
/************************************************************************************
* @fn codec_Set_DAC_Volume
*
* @brief Set DAC Volume.
*
* @param fu32_Volume: volume = 20*lg(fu32_Volume/2^13)
*/
void codec_Set_DAC_Volume(uint32_t fu32_Volume)
{
CODEC->DacVolume.VOLUME = fu32_Volume;
}
/************************************************************************************
* @fn codec_int_enable
*
* @brief Codec interrupt enable.
*
* @param fe_Int_Status: interrupt source select
*/
void codec_int_enable(enum_Codec_INT_Status_t fe_Int_Status)
{
CODEC->CodecIntEn.STATUS |= fe_Int_Status;
}
/************************************************************************************
* @fn codec_int_enable
*
* @brief Codec interrupt enable.
*
* @param fe_Int_Status: interrupt source select
*/
void codec_int_disable(enum_Codec_INT_Status_t fe_Int_Status)
{
CODEC->CodecIntEn.STATUS &= ~fe_Int_Status;
}
/************************************************************************************
* @fn codec_init_clear
*
* @brief Codec interrupt enable.
*
* @param fe_Int_Status: interrupt source select
*/
void codec_init_clear(enum_Codec_INT_Status_t fe_Int_Status)
{
CODEC->CodecIntClear.STATUS |= fe_Int_Status;
}
/************************************************************************************
* @fn codec_read_adc_fifo_left/
* codec_read_adc_fifo_right/
* codec_read_adc_fifo_left_right/
*
* @brief Codec read ADC fifo.
*
* @param fp_buffer: codec ADC data buffer.
* @param fu32_size: read data length.
*/
void codec_read_adc_fifo_left(void *fp_buffer, uint32_t fu32_length)
{
union_DataFormat_t Data;
switch (CODEC->FFRoute.ADCFF_BITWD)
{
case CODEC_FIFO_FORMAT_8BIT:
{
Data.p_u8 = fp_buffer;
while(fu32_length--)
*Data.p_u8++ = (uint8_t)CODEC->ADCDataL;
}break;
case CODEC_FIFO_FORMAT_16BIT:
{
Data.p_u16 = fp_buffer;
while(fu32_length--)
*Data.p_u16++ = (uint16_t)CODEC->ADCDataL;
}break;
case CODEC_FIFO_FORMAT_24BIT:
{
Data.p_u32 = fp_buffer;
while(fu32_length--)
*Data.p_u32++ = CODEC->ADCDataL;
}break;
default:break;
}
}
void codec_read_adc_fifo_right(void *fp_buffer, uint32_t fu32_length)
{
union_DataFormat_t Data;
switch (CODEC->FFRoute.ADCFF_BITWD)
{
case CODEC_FIFO_FORMAT_8BIT:
{
Data.p_u8 = fp_buffer;
while(fu32_length--)
*Data.p_u8++ = (uint8_t)CODEC->ADCDataR;
}break;
case CODEC_FIFO_FORMAT_16BIT:
{
Data.p_u16 = fp_buffer;
while(fu32_length--)
*Data.p_u16++ = (uint16_t)CODEC->ADCDataR;
}break;
case CODEC_FIFO_FORMAT_24BIT:
{
Data.p_u32 = fp_buffer;
while(fu32_length--)
*Data.p_u32++ = CODEC->ADCDataR;
}break;
default:break;
}
}
void codec_read_adc_fifo_left_right(void *fp_buffer, uint32_t fu32_length)
{
union_DataFormat_t Data;
switch (CODEC->FFRoute.ADCFF_BITWD)
{
case CODEC_FIFO_FORMAT_8BIT:
{
Data.p_u8 = fp_buffer;
while(fu32_length--){
*Data.p_u8++ = (uint8_t)CODEC->ADCDataL;
*Data.p_u8++ = (uint8_t)CODEC->ADCDataR;
}
}break;
case CODEC_FIFO_FORMAT_16BIT:
{
Data.p_u16 = fp_buffer;
while(fu32_length--){
*Data.p_u16++ = (uint16_t)CODEC->ADCDataL;
*Data.p_u16++ = (uint16_t)CODEC->ADCDataR;
}
}break;
case CODEC_FIFO_FORMAT_24BIT:
{
Data.p_u32 = fp_buffer;
while(fu32_length--){
*Data.p_u32++ = CODEC->ADCDataL;
*Data.p_u32++ = CODEC->ADCDataR;
}
}break;
default:break;
}
}
/************************************************************************************
* @fn codec_write_dac_fifo_left/
* codec_write_dac_fifo_right/
* codec_write_dac_fifo_left_right/
*
* @brief Codec write dac fifo LR.
*
* @param fp_buffer: codec dac data buffer.
* @param fu32_size: read data length.
*/
void codec_write_dac_fifo_left(void *fp_buffer, uint32_t fu32_length)
{
union_DataFormat_t Data;
switch (CODEC->FFRoute.DACFF_LR_BITWD)
{
case CODEC_FIFO_FORMAT_8BIT:
{
Data.p_u8 = fp_buffer;
while(fu32_length--)
CODEC->DACLRDataL = *Data.p_u8++;
}break;
case CODEC_FIFO_FORMAT_16BIT:
{
Data.p_u16 = fp_buffer;
while(fu32_length--)
CODEC->DACLRDataL = *Data.p_u16++;
}break;
case CODEC_FIFO_FORMAT_24BIT:
{
Data.p_u32 = fp_buffer;
while(fu32_length--)
CODEC->DACLRDataL = *Data.p_u32++;
}break;
default:break;
}
}
void codec_write_dac_fifo_right(void *fp_buffer, uint32_t fu32_length)
{
union_DataFormat_t Data;
switch (CODEC->FFRoute.DACFF_LR_BITWD)
{
case CODEC_FIFO_FORMAT_8BIT:
{
Data.p_u8 = fp_buffer;
while(fu32_length--)
CODEC->DACLRDataR = *Data.p_u8++;
}break;
case CODEC_FIFO_FORMAT_16BIT:
{
Data.p_u16 = fp_buffer;
while(fu32_length--)
CODEC->DACLRDataR = *Data.p_u16++;
}break;
case CODEC_FIFO_FORMAT_24BIT:
{
Data.p_u32 = fp_buffer;
while(fu32_length--)
CODEC->DACLRDataR = *Data.p_u32++;
}break;
default:break;
}
}
void codec_write_dac_fifo_left_right(void *fp_buffer, uint32_t fu32_length)
{
union_DataFormat_t Data;
switch (CODEC->FFRoute.DACFF_LR_BITWD)
{
case CODEC_FIFO_FORMAT_8BIT:
{
Data.p_u8 = fp_buffer;
while(fu32_length--){
CODEC->DACLRDataL = *Data.p_u8++;
CODEC->DACLRDataR = *Data.p_u8++;
}
}break;
case CODEC_FIFO_FORMAT_16BIT:
{
Data.p_u16 = fp_buffer;
while(fu32_length--){
CODEC->DACLRDataL = *Data.p_u16++;
CODEC->DACLRDataR = *Data.p_u16++;
}
}break;
case CODEC_FIFO_FORMAT_24BIT:
{
Data.p_u32 = fp_buffer;
while(fu32_length--){
CODEC->DACLRDataL = *Data.p_u32++;
CODEC->DACLRDataR = *Data.p_u32++;
}
}break;
default:break;
}
}
/************************************************************************************
* @fn codec_write_dac_fifo_0/
* codec_write_dac_fifo_1/
* codec_write_dac_fifo_01/
*
* @brief Codec write dac fifo 01.
*
* @param fp_buffer: codec DAC data buffer.
* @param fu32_size: read data length.
*/
void codec_write_dac_fifo_0(void *fp_buffer, uint32_t fu32_length)
{
union_DataFormat_t Data;
switch (CODEC->FFRoute.DACFF_01_BITWD)
{
case CODEC_FIFO_FORMAT_8BIT:
{
Data.p_u8 = fp_buffer;
while(fu32_length--)
CODEC->DAC01DataL = *Data.p_u8++;
}break;
case CODEC_FIFO_FORMAT_16BIT:
{
Data.p_u16 = fp_buffer;
while(fu32_length--)
CODEC->DAC01DataL = *Data.p_u16++;
}break;
case CODEC_FIFO_FORMAT_24BIT:
{
Data.p_u32 = fp_buffer;
while(fu32_length--)
CODEC->DAC01DataL = *Data.p_u32++;
}break;
default:break;
}
}
void codec_write_dac_fifo_1(void *fp_buffer, uint32_t fu32_length)
{
union_DataFormat_t Data;
switch (CODEC->FFRoute.DACFF_01_BITWD)
{
case CODEC_FIFO_FORMAT_8BIT:
{
Data.p_u8 = fp_buffer;
while(fu32_length--)
CODEC->DAC01DataR = *Data.p_u8++;
}break;
case CODEC_FIFO_FORMAT_16BIT:
{
Data.p_u16 = fp_buffer;
while(fu32_length--)
CODEC->DAC01DataR = *Data.p_u16++;
}break;
case CODEC_FIFO_FORMAT_24BIT:
{
Data.p_u32 = fp_buffer;
while(fu32_length--)
CODEC->DAC01DataR = *Data.p_u32++;
}break;
default:break;
}
}
void codec_write_dac_fifo_01(void *fp_buffer, uint32_t fu32_length)
{
union_DataFormat_t Data;
switch (CODEC->FFRoute.DACFF_01_BITWD)
{
case CODEC_FIFO_FORMAT_8BIT:
{
Data.p_u8 = fp_buffer;
while(fu32_length--){
CODEC->DAC01DataL = *Data.p_u8++;
CODEC->DAC01DataR = *Data.p_u8++;
}
}break;
case CODEC_FIFO_FORMAT_16BIT:
{
Data.p_u16 = fp_buffer;
while(fu32_length--){
CODEC->DAC01DataL = *Data.p_u16++;
CODEC->DAC01DataR = *Data.p_u16++;
}
}break;
case CODEC_FIFO_FORMAT_24BIT:
{
Data.p_u32 = fp_buffer;
while(fu32_length--){
CODEC->DAC01DataL = *Data.p_u32++;
CODEC->DAC01DataR = *Data.p_u32++;
}
}break;
default:break;
}
}
/************************************************************************************
* @fn codec_get_int_status
*
* @brief get Codec interrupt status.
*/
enum_Codec_INT_Status_t codec_get_int_status(void)
{
return CODEC->CodecIntRawStatus.STATUS;
}
/************************************************************************************
* @fn codec_mute_output
*
* @brief codec mute output enable/disable.
*
* @param fb_mute: true: mute.
*/
void codec_mute_output(bool fb_mute)
{
CODEC->Enable.CDC_TXOUT = fb_mute;
}

View File

@ -0,0 +1,53 @@
/*
******************************************************************************
* @file driver_crc.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2023
* @brief CRC module driver.
* This file provides firmware functions to manage the
* CRC(Cyclic Redundancy Check) peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2023 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/************************************************************************************
* @fn crc_init
*
* @brief Initial crc according to the mode
*
* @param fe_crc_mode: crc mode.
*/
void crc_init(enum_CRC_MODE_SEL_t fe_crc_mode)
{
/* CRC control config */
CRC->CRC_CTRL = fe_crc_mode | CRC_START;
}
/************************************************************************************
* @fn crc_Calculate
*
* @brief Calculate CRC from the input data.
*
* @param fp_Data: Input calculated data.
* @param fu32_size: The data size need to do crc.
*/
uint32_t crc_Calculate(uint8_t *fp_Data, uint32_t fu32_size)
{
if (fu32_size == 0)
{
return 0;
}
while(fu32_size--)
{
CRC->CRC_FIFO_DATA = *(fp_Data++);
}
return CRC->CRC_RESULT;
}

View File

@ -0,0 +1,394 @@
/*
******************************************************************************
* @file driver_dma.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief DMA module driver.
* This file provides firmware functions to manage the
* Direct Memory Access (DMA) peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/*********************************************************************
* @fn dma_init
*
* @brief Initialize the DMA according to the specified parameters
* in the dma_InitParameter_t
*
* @param hdma : pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for DMA module
*
* @return None.
*/
void dma_init(DMA_HandleTypeDef *hdma)
{
struct_DMA_t *DMA = hdma->DMAx;
/* FIFO_MODE_1 */
DMA->Channels[hdma->Channel].CFG2.FIFO_MODE = 1;
/* Clear Linked List Pointer Register */
DMA->Channels[hdma->Channel].LLP.LOC = 0;
DMA->Channels[hdma->Channel].LLP.LMS = 0;
/* Interrupt Enable */
DMA->Channels[hdma->Channel].CTL1.INT_EN = 1;
/* Bus Master Selection */
DMA->Channels[hdma->Channel].CTL1.SMS = hdma->Init.Source_Master_Sel;
DMA->Channels[hdma->Channel].CTL1.DMS = hdma->Init.Desination_Master_Sel;
/* Transfer Width */
DMA->Channels[hdma->Channel].CTL1.SRC_TR_WIDTH = hdma->Init.Source_Width;
DMA->Channels[hdma->Channel].CTL1.DST_TR_WIDTH = hdma->Init.Desination_Width;
/* Burst Length */
DMA->Channels[hdma->Channel].CTL1.DEST_MSIZE = hdma->Init.Desination_Burst_Len;
DMA->Channels[hdma->Channel].CTL1.SRC_MSIZE = hdma->Init.Source_Burst_Len;
/* Address Increment */
DMA->Channels[hdma->Channel].CTL1.SINC = hdma->Init.Source_Inc;
DMA->Channels[hdma->Channel].CTL1.DINC = hdma->Init.Desination_Inc;
/* DMA Data Flow */
DMA->Channels[hdma->Channel].CTL1.TT_FC = hdma->Init.Data_Flow;
/* Set Peripheral Request ID */
if (hdma->Init.Data_Flow == DMA_M2P_DMAC)
{
DMA->Channels[hdma->Channel].CFG2.DEST_PER = hdma->Init.Request_ID;
}
else if (hdma->Init.Data_Flow == DMA_P2M_DMAC)
{
DMA->Channels[hdma->Channel].CFG2.SRC_PER = hdma->Init.Request_ID;
}
/* Hardware handshaking interface */
DMA->Channels[hdma->Channel].CFG1.HS_SEL_SRC = 0;
DMA->Channels[hdma->Channel].CFG1.HS_SEL_DST = 0;
/* AHB dmac Enabled */
DMA->Misc_Reg.DmaCfgReg.DMA_EN = 1;
}
/*********************************************************************
* @fn dma_start
*
* @brief DMA transfer start.
*
* @param hdma : pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for DMA module
* SrcAddr: source address
* DstAddr: desination address
* Size: transfer size (This parameter can be a 12-bit Size)
* @return None.
*/
void dma_start(DMA_HandleTypeDef *hdma, uint32_t SrcAddr, uint32_t DstAddr, uint32_t Size)
{
struct_DMA_t *DMA = hdma->DMAx;
/* Set source address and desination address */
DMA->Channels[hdma->Channel].SAR = SrcAddr;
DMA->Channels[hdma->Channel].DAR = DstAddr;
/* Set Transfer Size */
DMA->Channels[hdma->Channel].CTL2.BLOCK_TS = Size;
/* Enable the channel */
DMA->Misc_Reg.ChEnReg |= (1 << hdma->Channel | (1 << (hdma->Channel + 8)));
}
/*********************************************************************
* @fn dma_start_IT
*
* @brief DMA transfer start and enable interrupt
*
* @param hdma : pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for DMA module
* SrcAddr: source address
* DstAddr: desination address
* Size: transfer size (This parameter can be a 12-bit Size)
* @return None.
*/
void dma_start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddr, uint32_t DstAddr, uint32_t Size)
{
struct_DMA_t *DMA = hdma->DMAx;
/* Set source address and desination address */
DMA->Channels[hdma->Channel].SAR = SrcAddr;
DMA->Channels[hdma->Channel].DAR = DstAddr;
/* Set Transfer Size */
DMA->Channels[hdma->Channel].CTL2.BLOCK_TS = Size;
/* Clear Transfer complete status */
dma_clear_tfr_Status(hdma);
/* channel Transfer complete interrupt enable */
dma_tfr_interrupt_enable(hdma);
/* Enable the channel */
DMA->Misc_Reg.ChEnReg |= (1 << hdma->Channel | (1 << (hdma->Channel + 8)));
}
/*********************************************************************
* @fn dma_linked_list_init
*
* @brief Initialize the linked list parameters
*
* @param link : The list structure that needs to be initialized
* param: Initialization parameter
* @return None
*/
void dma_linked_list_init(DMA_LLI_InitTypeDef *link, dma_LinkParameter_t *param)
{
link->SrcAddr = param->SrcAddr;
link->DstAddr = param->DstAddr;
link->Next = (DMA_LLI_InitTypeDef *)param->NextLink;
link->CTL1.INT_EN = 1;
link->CTL1.SRC_TR_WIDTH = param->Source_Width;
link->CTL1.DST_TR_WIDTH = param->Desination_Width;
link->CTL1.SMS = param->Source_Master_Sel;
link->CTL1.DMS = param->Desination_Master_Sel;
link->CTL1.SINC = param->Source_Inc;
link->CTL1.DINC = param->Desination_Inc;
link->CTL1.TT_FC = param->Data_Flow;
link->CTL1.DEST_MSIZE = param->Desination_Burst_Len;
link->CTL1.SRC_MSIZE = param->Source_Burst_Len;
link->CTL1.SRC_GATHER_EN = param->gather_enable;
link->CTL1.DST_SCATTER_EN = param->scatter_enable;
link->CTL2.BLOCK_TS = param->Size;
/* Block chaining using Linked List is enabled on the Source side */
/* Block chaining using Linked List is enabled on the Destination side */
link->CTL1.LLP_DST_EN = 1;
link->CTL1.LLP_SRC_EN = 1;
}
/*********************************************************************
* @fn dma_linked_list_start.
*
* @brief DMA linked list transfer start.
*
* @param link : The first address of the linked list
* param : Initialization parameter
* hdma : DMA handle
*
* @return None
*/
void dma_linked_list_start(DMA_HandleTypeDef *hdma, DMA_LLI_InitTypeDef *link, dma_LinkParameter_t *param)
{
struct_DMA_t *DMA = hdma->DMAx;
uint32_t Channel = hdma->Channel;
/* Set Peripheral Request ID */
if (link->CTL1.TT_FC == DMA_M2P_DMAC)
{
DMA->Channels[Channel].CFG2.DEST_PER = param->Request_ID;
}
else if (link->CTL1.TT_FC == DMA_P2M_DMAC)
{
DMA->Channels[Channel].CFG2.SRC_PER = param->Request_ID;
}
/* Hardware handshaking interface */
DMA->Channels[Channel].CFG1.HS_SEL_SRC = 0;
DMA->Channels[Channel].CFG1.HS_SEL_DST = 0;
/* Block chaining using Linked List is enabled on the Source side */
/* Block chaining using Linked List is enabled on the Destination side */
DMA->Channels[Channel].CTL1.LLP_DST_EN = link->CTL1.LLP_DST_EN;
DMA->Channels[Channel].CTL1.LLP_SRC_EN = link->CTL1.LLP_SRC_EN;
DMA->Channels[Channel].LLP.LOC = ((uint32_t)link) >> 2;
/* AHB dmac Enabled */
DMA->Misc_Reg.DmaCfgReg.DMA_EN = 1;
DMA->Misc_Reg.ChEnReg |= (1 << Channel | (1 << (Channel + 8)));
}
/*********************************************************************
* @fn dma_linked_list_start_IT
*
* @brief DMA linked list transfer start and enable interrupt
*
* @param link : The first address of the linked list
* param : Initialization parameter
* hdma : DMA handle
*
* @return None
*/
void dma_linked_list_start_IT(DMA_HandleTypeDef *hdma, DMA_LLI_InitTypeDef *link, dma_LinkParameter_t *param)
{
struct_DMA_t *DMA = hdma->DMAx;
uint32_t Channel = hdma->Channel;
/* Set Peripheral Request ID */
if (link->CTL1.TT_FC == DMA_M2P_DMAC)
{
DMA->Channels[Channel].CFG2.DEST_PER = param->Request_ID;
}
else if (link->CTL1.TT_FC == DMA_P2M_DMAC)
{
DMA->Channels[Channel].CFG2.SRC_PER = param->Request_ID;
}
/* Hardware handshaking interface */
DMA->Channels[Channel].CFG1.HS_SEL_SRC = 0;
DMA->Channels[Channel].CFG1.HS_SEL_DST = 0;
DMA->Channels[Channel].CTL1.LLP_DST_EN = link->CTL1.LLP_DST_EN;
DMA->Channels[Channel].CTL1.LLP_SRC_EN = link->CTL1.LLP_SRC_EN;
DMA->Channels[Channel].LLP.LOC = ((uint32_t)link) >> 2;
/* Clear Transfer complete status */
dma_clear_tfr_Status(hdma);
/* channel Transfer complete interrupt enable */
dma_tfr_interrupt_enable(hdma);
/* AHB dmac Enabled */
DMA->Misc_Reg.DmaCfgReg.DMA_EN = 1;
DMA->Misc_Reg.ChEnReg |= (1 << Channel | (1 << (Channel + 8)));
}
/*********************************************************************
* @fn dma_tfr_interrupt_enable
*
* @brief channel transfer complete interrupt enable
*
* @param hdma : DMA handle
*
* @return None
*/
void dma_tfr_interrupt_enable(DMA_HandleTypeDef *hdma)
{
hdma->DMAx->Int_Reg.MaskTfr = (1 << (hdma->Channel)) | (1 << ((hdma->Channel) + 8));
}
/*********************************************************************
* @fn dma_tfr_interrupt_disable
*
* @brief channel transfer complete interrupt disable
*
* @param hdma : DMA handle
*
* @return None
*/
void dma_tfr_interrupt_disable(DMA_HandleTypeDef *hdma)
{
hdma->DMAx->Int_Reg.MaskTfr = (1 << ((hdma->Channel) + 8));
}
/*********************************************************************
* @fn dma_get_tfr_Status
*
* @brief Get channel transfer complete status
*
* @param hdma : DMA handle
*
* @return true: channel Transfer complete
* false: Not
*/
bool dma_get_tfr_Status(DMA_HandleTypeDef *hdma)
{
/* Check channel Transfer complete */
if (hdma->DMAx->Int_Reg.RawTfr & (1 << (hdma->Channel)))
{
return true;
}
else
{
return false;
}
}
/*********************************************************************
* @fn dma_clear_tfr_Status
*
* @brief clear channel transfer complete status
*
* @param hdma : DMA handle
*
* @return None
*/
void dma_clear_tfr_Status(DMA_HandleTypeDef *hdma)
{
/* Clear channel Transfer complete Status */
hdma->DMAx->Int_Reg.ClearTfr = 1 << (hdma->Channel);
}
/*********************************************************************
* @fn dma_tfr_interrupt_enable
*
* @brief channel transfer complete interrupt enable
*
* @param hdma : DMA handle
*
* @return None
*/
void dma_error_interrupt_enable(DMA_HandleTypeDef *hdma)
{
hdma->DMAx->Int_Reg.MaskErr = (1 << (hdma->Channel)) | (1 << ((hdma->Channel) + 8));
}
/*********************************************************************
* @fn dma_tfr_interrupt_disable
*
* @brief channel transfer complete interrupt disable
*
* @param hdma : DMA handle
*
* @return None
*/
void dma_error_interrupt_disable(DMA_HandleTypeDef *hdma)
{
hdma->DMAx->Int_Reg.MaskErr = (1 << ((hdma->Channel) + 8));
}
/*********************************************************************
* @fn dma_get_tfr_Status
*
* @brief Get channel transfer complete status
*
* @param hdma : DMA handle
*
* @return true: channel Transfer complete
* false: Not
*/
bool dma_get_error_Status(DMA_HandleTypeDef *hdma)
{
/* Check channel Transfer complete */
if (hdma->DMAx->Int_Reg.RawErr & (1 << (hdma->Channel)))
{
return true;
}
else
{
return false;
}
}
/*********************************************************************
* @fn dma_clear_tfr_Status
*
* @brief clear channel transfer complete status
*
* @param hdma : DMA handle
*
* @return None
*/
void dma_clear_error_Status(DMA_HandleTypeDef *hdma)
{
/* Clear channel Transfer complete Status */
hdma->DMAx->Int_Reg.ClearErr = 1 << (hdma->Channel);
}

View File

@ -0,0 +1,105 @@
/*
******************************************************************************
* @file driver_efuse.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief eFuse module driver.
* This file provides firmware functions to manage the eFuse.
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/************************************************************************************
* @fn eFuse_siso_read
*
* @brief read eFuse data.
*
* @param fp_Data: read data buffer.
*/
void eFuse_siso_read(uint32_t *fp_Data)
{
/* config read mode */
EFUSE_SISO->eFuse_Ctrl = EFUSE_SISO_READ_MODE;
/* wait config done */
while(!(EFUSE_SISO->eFuse_Ctrl & EFUSE_SISO_CHECK_DONE));
EFUSE_SISO->eFuse_Ctrl |= EFUSE_SISO_CHECK_DONE;
/* read data */
fp_Data[0] = EFUSE_SISO->eFuse_Data0;
fp_Data[1] = EFUSE_SISO->eFuse_Data1;
fp_Data[2] = EFUSE_SISO->eFuse_Data2;
}
/************************************************************************************
* @fn eFuse_siso_write
*
* @brief write eFuse data.
*
* @param fp_Data: write data buffer.
*/
void eFuse_siso_write(uint32_t *fp_Data)
{
/* write data */
EFUSE_SISO->eFuse_Data0 = fp_Data[0];
EFUSE_SISO->eFuse_Data1 = fp_Data[1];
EFUSE_SISO->eFuse_Data2 = fp_Data[2];
/* config write mode */
EFUSE_SISO->eFuse_Ctrl = EFUSE_SISO_WRITE_MODE;
/* wait config done */
while(!(EFUSE_SISO->eFuse_Ctrl & EFUSE_SISO_CHECK_DONE));
EFUSE_SISO->eFuse_Ctrl |= EFUSE_SISO_CHECK_DONE;
}
/************************************************************************************
* @fn eFuse_pipo_read
*
* @brief read eFuse data.
*
* @param fu8_Addr: efuse address, unit byte, range 0x00 ~ 0xFF;
* @param fp_Data: read data buffer.
*/
void eFuse_pipo_read(uint8_t fu8_Addr, uint8_t *fp_Data)
{
EFUSE_PIPO->eFuse_Addr = fu8_Addr;
/* config read mode */
EFUSE_PIPO->eFuse_Ctrl = EFUSE_PIPO_GO | EFUSE_PIPO_READ_MODE;
/* wait config done */
while(!(EFUSE_PIPO->eFuse_Ctrl & EFUSE_PIPO_CHECK_DONE));
EFUSE_PIPO->eFuse_Ctrl |= EFUSE_PIPO_WRITE_MODE;
EFUSE_PIPO->eFuse_Ctrl = 0x00;
fp_Data[0] = EFUSE_PIPO->eFuse_RData;
EFUSE_PIPO->eFuse_Ctrl &= ~EFUSE_PIPO_READ_MODE;
}
/************************************************************************************
* @fn eFuse_pipo_write
*
* @brief write eFuse data.
*
* @param fu8_Addr: efuse address, unit byte, range 0x00 ~ 0xFF;
* @param fp_Data: write data value.
*/
void eFuse_pipo_write(uint8_t fu8_Addr, uint8_t fu8_Data)
{
EFUSE_PIPO->eFuse_Ctrl = EFUSE_PIPO_AVDDEN;
EFUSE_PIPO->eFuse_Addr = fu8_Addr;
EFUSE_PIPO->eFuse_WData = fu8_Data;
/* config write mode */
EFUSE_PIPO->eFuse_Ctrl = EFUSE_PIPO_GO | EFUSE_PIPO_WRITE_MODE | EFUSE_PIPO_AVDDEN;
/* wait config done */
while(!(EFUSE_PIPO->eFuse_Ctrl & EFUSE_PIPO_CHECK_DONE));
EFUSE_PIPO->eFuse_Ctrl |= EFUSE_PIPO_WRITE_MODE;
EFUSE_PIPO->eFuse_Ctrl = 0x00;
}

View File

@ -0,0 +1,156 @@
/*
******************************************************************************
* @file driver_fft.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2022
* @brief FFT module driver.
* This file provides firmware functions to manage the
* FFT (Fast Fourier Transform) peripheral.
******************************************************************************
* @attention
*
* Copyright (c) 2022 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/************************************************************************************
* @fn fft_IRQHandler
*
* @brief fft interrupt handler
*
* @param hfft: FFT_HandleTypeDef.
*/
void fft_IRQHandler(FFT_HandleTypeDef *hfft)
{
int i;
/* clear int status */
__FFT_INT_STATUS_CLEAR();
/* Data OUT */
for (i = 0; i < hfft->BlockSize; i++)
hfft->DataOut[hfft->DataOutIndex++] = FFT->FFT_ACCESSRAM;
if (hfft->BlockCNT)
{
hfft->BlockCNT--;
/* Data IN */
for (i = 0; i < hfft->BlockSize; i++)
FFT->FFT_ACCESSRAM = hfft->DataIn[hfft->DataIndex++];
}
else
{
__FFT_INT_DISALE();
hfft->FFT_Busy = false;
}
}
/************************************************************************************
* @fn FFT_init
*
* @brief initialize the FFT module.
*
* @param hfft: FFT_HandleTypeDef.
*/
void fft_init(FFT_HandleTypeDef *hfft)
{
/* FFT calculate Mod */
FFT->FFT_CTRL.Bits.MODE_SEL = hfft->FFT_Init.FFT_Cal_Mode;
/* FFT Samples number */
FFT->FFT_CTRL.Bits.NP_SEL = hfft->FFT_Init.FFT_Samples;
/* default DMA enable */
__FFT_DMA_ENABLE();
}
/************************************************************************************
* @fn FFT_start
*
* @brief start fft calculate.
*
* @param hfft: FFT_HandleTypeDef.
* @param fp_Data_In: the pointer of input data.
* @param fp_Data_Out: the pointer of output data.
* @param fu32_BlockCNT: Number of blocks to calculate.
*/
void fft_start(FFT_HandleTypeDef *hfft, uint32_t *fp_Data_In, uint32_t *fp_Data_Out, uint32_t fu32_BlockCNT)
{
int i;
uint32_t BlockSize;
uint32_t DataIndex = 0;
uint32_t DataOutIndex = 0;
/* wait fft calculate idle */
while(!__FFT_IS_IDLE());
switch (hfft->FFT_Init.FFT_Samples)
{
case FFT_128: BlockSize = 128; break;
case FFT_256: BlockSize = 256; break;
case FFT_512: BlockSize = 512; break;
default:break;
}
while(fu32_BlockCNT--)
{
/* Data IN */
for (i = 0; i < BlockSize; i++)
FFT->FFT_ACCESSRAM = fp_Data_In[DataIndex++];
/* Wait calculate done */
while(!__FFT_CAL_IS_DONE());
/* Data OUT */
for (i = 0; i < BlockSize; i++)
fp_Data_Out[DataOutIndex++] = FFT->FFT_ACCESSRAM;
}
}
/************************************************************************************
* @fn FFT_start_IT
*
* @brief start fft calculate with isr.
*
* @param hfft: FFT_HandleTypeDef.
* @param fp_Data_In: the pointer of input data.
* @param fp_Data_Out: the pointer of output data.
* @param fu32_BlockCNT: Number of blocks to calculate.
*/
int fft_start_IT(FFT_HandleTypeDef *hfft, uint32_t *fp_Data_In, uint32_t *fp_Data_Out, uint32_t fu32_BlockCNT)
{
int i;
uint32_t BlockSize;
if (hfft->FFT_Busy)
return -1;
/* wait fft calculate idle */
while(!__FFT_IS_IDLE());
switch (hfft->FFT_Init.FFT_Samples)
{
case FFT_128: BlockSize = 128; break;
case FFT_256: BlockSize = 256; break;
case FFT_512: BlockSize = 512; break;
default:break;
}
__FFT_INT_ENALE();
hfft->FFT_Busy = true;
hfft->BlockCNT = fu32_BlockCNT;
hfft->BlockSize = BlockSize;
hfft->DataIndex = 0;
hfft->DataOutIndex = 0;
hfft->DataIn = fp_Data_In;
hfft->DataOut = fp_Data_Out;
hfft->BlockCNT--;
/* Data IN */
for (i = 0; i < hfft->BlockSize; i++)
FFT->FFT_ACCESSRAM = hfft->DataIn[hfft->DataIndex++];
return 0;
}

View File

@ -0,0 +1,979 @@
/*
******************************************************************************
* @file driver_flash.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief Internal XIP Flash module driver.
* This file provides firmware functions to manage the internal
* stacked xip flash
******************************************************************************
* @attention
*
* Copyright (c) 2022 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
#define FLASH_ID_PUYA_P25Q32 0x00166085
#define FLASH_ID_XMC_XM25LU32 0x00165020
#define FLASH_ID_GIANTEC_GT25Q16A 0x001560c4
#define FLASH_ID_PUYA_P25Q16 0x00156085
#define FLASH_ID_PUYA_P25Q80 0x00146085
#define FLASH_ID_GD_GD25WQ80E 0x001465c8
struct qspi_stig_reg_t sector_erase_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = QSPI_STIG_ADDR_BYTES_3,
.enable_mode = 0,
.enable_cmd_addr = 1,
.read_bytes = 0,
.enable_read = 0,
.opcode = FLASH_SECTORE_ERASE_OPCODE,
};
struct qspi_stig_reg_t read_id_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 3,
.enable_read = 1,
.opcode = FLASH_READ_IDENTIFICATION,
};
struct qspi_stig_reg_t read_status_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 1,
.enable_read = 1,
.opcode = 0x05,
};
struct qspi_stig_reg_t read_status_h_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 1,
.enable_read = 1,
.opcode = 0x35,
};
struct qspi_stig_reg_t write_enable_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 0,
.enable_read = 0,
.opcode = 0x06,
};
struct qspi_stig_reg_t write_volatile_enable_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 0,
.enable_read = 0,
.opcode = 0x50,
};
struct qspi_stig_reg_t write_status_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 1,
.enable_write = 1,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 0,
.enable_read = 0,
.opcode = 0x01,
};
struct qspi_stig_reg_t write_status_2_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 1,
.enable_write = 1,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 0,
.enable_read = 0,
.opcode = 0x31,
};
struct qspi_stig_reg_t write_status_3_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 1,
.enable_write = 1,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 0,
.enable_read = 0,
.opcode = 0x11,
};
struct qspi_stig_reg_t write_status_h_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 1,
.enable_write = 1,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 0,
.enable_read = 0,
.opcode = 0x31,
};
struct qspi_stig_reg_t block_erase_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = QSPI_STIG_ADDR_BYTES_3,
.enable_mode = 0,
.enable_cmd_addr = 1,
.read_bytes = 0,
.enable_read = 0,
.opcode = 0xD8,
};
struct qspi_stig_reg_t chip_erase_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 0,
.enable_read = 0,
.opcode = 0x60,
};
struct qspi_stig_reg_t write_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 1,
.addr_bytes = QSPI_STIG_ADDR_BYTES_3,
.enable_mode = 0,
.enable_cmd_addr = 1,
.read_bytes = 0,
.enable_read = 0,
.opcode = 0x02,
};
struct qspi_stig_reg_t write_disable_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 0,
.enable_read = 0,
.opcode = 0x04,
};
struct qspi_stig_reg_t read_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = QSPI_STIG_ADDR_BYTES_3,
.enable_mode = 0,
.enable_cmd_addr = 1,
.read_bytes = 0,
.enable_read = 1,
.opcode = 0x03,
};
struct qspi_stig_reg_t deep_sleep_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 0,
.enable_read = 0,
.opcode = 0xB9,
};
struct qspi_stig_reg_t wakeup_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 0,
.enable_read = 0,
.opcode = 0xAB,
};
struct qspi_stig_reg_t sec_sector_erase_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = QSPI_STIG_ADDR_BYTES_3,
.enable_mode = 0,
.enable_cmd_addr = 1,
.read_bytes = 0,
.enable_read = 0,
.opcode = FLASH_SEC_REG_ERASE_OPCODE,
};
struct qspi_stig_reg_t sec_sector_read_cmd = {
.enable_bank = 0,
.dummy_cycles = 1,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = QSPI_STIG_ADDR_BYTES_3,
.enable_mode = 0,
.enable_cmd_addr = 1,
.read_bytes = 0,
.enable_read = 1,
.opcode = FLASH_SEC_REG_READ_OPCODE,
};
struct qspi_stig_reg_t sec_sector_write_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 1,
.addr_bytes = QSPI_STIG_ADDR_BYTES_3,
.enable_mode = 0,
.enable_cmd_addr = 1,
.read_bytes = 0,
.enable_read = 0,
.opcode = FLASH_SEC_REG_PROGRAM_OPCODE,
};
__RAM_CODE void flash_wait_wip_clear(struct qspi_regs_t *qspi)
{
uint8_t status;
while(1) {
system_delay_us(100);
qspi_stig_cmd(qspi, read_status_cmd, QSPI_STIG_CMD_READ, 1, &status);
if((status & 0x01) == 0) {
break;
}
}
}
__RAM_CODE void flash_enable_quad(struct qspi_regs_t *qspi)
{
uint8_t status[2];
uint32_t flash_id;
qspi_stig_cmd(qspi, read_status_cmd, QSPI_STIG_CMD_READ, 1, &status[0]);
qspi_stig_cmd(qspi, read_status_h_cmd, QSPI_STIG_CMD_READ, 1, &status[1]);
if((status[1] & 0x02) == 0x02) {
return;
}
flash_id = flash_read_id(qspi);
if ((flash_id == FLASH_ID_PUYA_P25Q32)
|| (flash_id == FLASH_ID_XMC_XM25LU32)
|| (flash_id == FLASH_ID_GIANTEC_GT25Q16A )
|| (flash_id == FLASH_ID_PUYA_P25Q16)) {
status[1] |= 0x02; //enable quad mode
qspi_stig_cmd(qspi, write_enable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
qspi_stig_cmd(qspi, write_status_h_cmd, QSPI_STIG_CMD_WRITE, 1, &status[1]);
}
else if ((flash_id == FLASH_ID_GD_GD25WQ80E)
|| (flash_id == FLASH_ID_PUYA_P25Q80)) {
status[1] |= 0x02; //enable quad mode
qspi_stig_cmd(qspi, write_enable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
qspi_stig_cmd(qspi, write_status_cmd, QSPI_STIG_CMD_WRITE, 2, &status[0]);
}
else {
while(1);
}
flash_wait_wip_clear(qspi);
}
__RAM_CODE void flash_set_IO_DRV(struct qspi_regs_t *qspi, uint8_t drv)
{
uint8_t data;
data = (drv<<5);
qspi_stig_cmd(qspi, write_volatile_enable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
qspi_stig_cmd(qspi, write_status_3_cmd, QSPI_STIG_CMD_WRITE, 1, &data);
}
__RAM_CODE void flash_set_capture_delay(struct qspi_regs_t *qspi, uint8_t delay)
{
__QSPI_READ_CAPTURE_DELAY_SET(qspi, delay);
}
__RAM_CODE void flash_set_read_dtr_fast_quad(struct qspi_regs_t *qspi)
{
__QSPI_READ_OPCODE_SET(qspi, FLASH_PAGE_DTR_QUAL_READ_OPCODE);
__QSPI_READ_INSTRUCTION_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_ADDRESS_TYPE_SET(qspi, QSPI_WIRE_TYPE_QIO);
__QSPI_READ_DATA_TYPE_SET(qspi, QSPI_WIRE_TYPE_QIO);
__QSPI_READ_DUMMY_CYCLES_SET(qspi, 7);
__QSPI_READ_MODE_ENABLE_SET(qspi, 1);
__QSPI_MODE_BIT_SET(qspi, 0);
// __QSPI_CFG_DTR_ENABLE(qspi);
__QSPI_READ_DDR_ENABLE(qspi);
}
__RAM_CODE void flash_set_read_fast_quad(struct qspi_regs_t *qspi)
{
__QSPI_READ_OPCODE_SET(qspi, FLASH_PAGE_QUAL_READ_OPCODE);
__QSPI_READ_INSTRUCTION_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_ADDRESS_TYPE_SET(qspi, QSPI_WIRE_TYPE_QIO);
__QSPI_READ_DATA_TYPE_SET(qspi, QSPI_WIRE_TYPE_QIO);
__QSPI_READ_DUMMY_CYCLES_SET(qspi, 4);
__QSPI_READ_MODE_ENABLE_SET(qspi, 1);
__QSPI_MODE_BIT_SET(qspi, 0);
}
__RAM_CODE void flash_set_read_quad(struct qspi_regs_t *qspi)
{
__QSPI_READ_OPCODE_SET(qspi, FLASH_PAGE_QUAL_READ_OPCODE_2);
__QSPI_READ_INSTRUCTION_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_ADDRESS_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_DATA_TYPE_SET(qspi, QSPI_WIRE_TYPE_QIO);
__QSPI_READ_DUMMY_CYCLES_SET(qspi, 8);
__QSPI_READ_MODE_ENABLE_SET(qspi, 0);
__QSPI_MODE_BIT_SET(qspi, 0);
}
__RAM_CODE void flash_set_read_dtr_fast_dual(struct qspi_regs_t *qspi)
{
__QSPI_READ_OPCODE_SET(qspi, FLASH_READ_DTR_DUAL_OPCODE);
__QSPI_READ_INSTRUCTION_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_ADDRESS_TYPE_SET(qspi, QSPI_WIRE_TYPE_DIO);
__QSPI_READ_DATA_TYPE_SET(qspi, QSPI_WIRE_TYPE_DIO);
__QSPI_READ_DUMMY_CYCLES_SET(qspi, 0);
__QSPI_READ_MODE_ENABLE_SET(qspi, 0);
__QSPI_MODE_BIT_SET(qspi, 0);
// __QSPI_CFG_DTR_ENABLE(qspi);
__QSPI_READ_DDR_ENABLE(qspi);
}
__RAM_CODE void flash_set_read_fast_dual(struct qspi_regs_t *qspi)
{
__QSPI_READ_OPCODE_SET(qspi, FLASH_READ_DUAL_OPCODE);
__QSPI_READ_INSTRUCTION_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_ADDRESS_TYPE_SET(qspi, QSPI_WIRE_TYPE_DIO);
__QSPI_READ_DATA_TYPE_SET(qspi, QSPI_WIRE_TYPE_DIO);
__QSPI_READ_DUMMY_CYCLES_SET(qspi, 0);
__QSPI_READ_MODE_ENABLE_SET(qspi, 1);
__QSPI_MODE_BIT_SET(qspi, 0);
}
__RAM_CODE void flash_set_read_dual(struct qspi_regs_t *qspi)
{
__QSPI_READ_OPCODE_SET(qspi, FLASH_READ_DUAL_OPCODE_2);
__QSPI_READ_INSTRUCTION_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_ADDRESS_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_DATA_TYPE_SET(qspi, QSPI_WIRE_TYPE_DIO);
__QSPI_READ_DUMMY_CYCLES_SET(qspi, 8);
__QSPI_READ_MODE_ENABLE_SET(qspi, 0);
__QSPI_MODE_BIT_SET(qspi, 0);
}
__RAM_CODE void flash_set_read_dtr_fast_single(struct qspi_regs_t *qspi)
{
__QSPI_READ_OPCODE_SET(qspi, FLASH_FAST_DTR_READ_OPCODE);
__QSPI_READ_INSTRUCTION_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_ADDRESS_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_DATA_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_DUMMY_CYCLES_SET(qspi, 6);
__QSPI_READ_MODE_ENABLE_SET(qspi, 0);
__QSPI_MODE_BIT_SET(qspi, 0);
// __QSPI_CFG_DTR_ENABLE(qspi);
__QSPI_READ_DDR_ENABLE(qspi);
}
__RAM_CODE void flash_set_read_fast_single(struct qspi_regs_t *qspi)
{
__QSPI_READ_OPCODE_SET(qspi, FLASH_FAST_READ_OPCODE);
__QSPI_READ_INSTRUCTION_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_ADDRESS_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_DATA_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_DUMMY_CYCLES_SET(qspi, 8);
__QSPI_READ_MODE_ENABLE_SET(qspi, 0);
__QSPI_MODE_BIT_SET(qspi, 0);
}
__RAM_CODE void flash_set_read_single(struct qspi_regs_t *qspi)
{
__QSPI_READ_OPCODE_SET(qspi, FLASH_READ_OPCODE);
__QSPI_READ_INSTRUCTION_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_ADDRESS_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_DATA_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_DUMMY_CYCLES_SET(qspi, 0);
__QSPI_READ_MODE_ENABLE_SET(qspi, 0);
__QSPI_MODE_BIT_SET(qspi, 0);
}
__RAM_CODE void flash_set_write_quad(struct qspi_regs_t *qspi)
{
__QSPI_WRITE_OPCODE_SET(qspi, FLASH_PAGE_QUAL_PROGRAM_OPCODE);
__QSPI_WRITE_ADDRESS_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_WRITE_DATA_TYPE_SET(qspi, QSPI_WIRE_TYPE_QIO);
__QSPI_WRITE_DUMMY_CYCLES_SET(qspi, 0);
}
__RAM_CODE void flash_set_write_dual(struct qspi_regs_t *qspi)
{
__QSPI_WRITE_OPCODE_SET(qspi, FLASH_PAGE_DUAL_PROGRAM_OPCODE);
__QSPI_WRITE_ADDRESS_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_WRITE_DATA_TYPE_SET(qspi, QSPI_WIRE_TYPE_DIO);
__QSPI_WRITE_DUMMY_CYCLES_SET(qspi, 0);
}
__RAM_CODE void flash_set_write_single(struct qspi_regs_t *qspi)
{
__QSPI_WRITE_OPCODE_SET(qspi, FLASH_PAGE_PROGRAM_OPCODE);
__QSPI_WRITE_ADDRESS_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_WRITE_DATA_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_WRITE_DUMMY_CYCLES_SET(qspi, 0);
}
__RAM_CODE __USED void flash_set_read_type(struct qspi_regs_t *qspi, uint8_t rd_type)
{
switch(rd_type) {
case FLASH_RD_TYPE_SINGLE:
flash_set_read_single(qspi);
break;
case FLASH_RD_TYPE_SINGLE_FAST:
flash_set_read_fast_single(qspi);
break;
case FLASH_RD_TYPE_DUAL:
flash_set_read_dual(qspi);
break;
case FLASH_RD_TYPE_DUAL_FAST:
flash_set_read_fast_dual(qspi);
break;
case FLASH_RD_TYPE_QUAD:
flash_set_read_quad(qspi);
break;
case FLASH_RD_TYPE_QUAD_FAST:
flash_set_read_fast_quad(qspi);
break;
case FLASH_RD_TYPE_DTR_SINGLE_FAST:
flash_set_read_dtr_fast_single(qspi);
break;
case FLASH_RD_TYPE_DTR_DUAL_FAST:
flash_set_read_dtr_fast_dual(qspi);
break;
case FLASH_RD_TYPE_DTR_QUAD_FAST:
flash_set_read_dtr_fast_quad(qspi);
break;
default:
flash_set_read_single(qspi);
break;
}
}
__RAM_CODE __USED void flash_set_write_type(struct qspi_regs_t *qspi, uint8_t wr_type)
{
switch(wr_type) {
case FLASH_WR_TYPE_SINGLE:
flash_set_write_single(qspi);
break;
case FLASH_WR_TYPE_DUAL:
flash_set_write_dual(qspi);
break;
case FLASH_WR_TYPE_QUAD:
flash_set_write_quad(qspi);
break;
default:
flash_set_write_single(qspi);
break;
}
}
__RAM_CODE __USED void flash_init_controller(struct qspi_regs_t *qspi, enum flash_rd_type_t rd_type, enum flash_wr_type_t wr_type)
{
while(__QSPI_IS_BUSY(qspi));
flash_set_read_type(qspi, rd_type);
flash_set_write_type(qspi, wr_type);
__QSPI_POLL_OPCODE_SET(qspi, 0x05);
__QSPI_POLL_BIT_INDEX_SET(qspi, 0);
__QSPI_POLL_POLARITY_SET(qspi, 0);
__QSPI_POLL_EXPIRATION_SET(qspi, 0);
__QSPI_POLL_EXPIRE_DISABLE(qspi);
__QSPI_POLL_COUNT_SET(qspi, 2);
__QSPI_POLL_DELAY_SET(qspi, 16);
__QSPI_POLL_DISABLE(qspi);
//init configuration register
__QSPI_CFG_CPOL_SET(qspi, 1);
__QSPI_CFG_CPHA_SET(qspi, 1);
__QSPI_CFG_DAC_ENABLE(qspi);
__QSPI_CFG_LEGACY_DISABLE(qspi);
__QSPI_CFG_REMAP_ENABLE(qspi);
__QSPI_CFG_BAUDRATE_SET(qspi, QSPI_BAUDRATE_DIV_16);
__QSPI_CFG_AHB_DECODER_ENABLE(qspi);
__QSPI_DELAY_CS_START_SET(qspi, 2);
__QSPI_DELAY_CS_END_SET(qspi, 2);
__QSPI_REMAP_ADDRESS_SET(qspi, 0);
__QSPI_ENABLE(qspi);
}
uint32_t flash_read_id(struct qspi_regs_t *qspi)
{
uint32_t flash_id;
qspi_stig_cmd(qspi, read_id_cmd, QSPI_STIG_CMD_READ, 3, (uint8_t *)&flash_id);
return (flash_id&0xffffff);
}
__RAM_CODE void flash_set_baudrate(struct qspi_regs_t *qspi, uint8_t baudrate)
{
if (baudrate <= QSPI_BAUDRATE_DIV_32) {
GLOBAL_INT_DISABLE();
while(__QSPI_IS_BUSY(qspi));
__QSPI_CFG_BAUDRATE_SET(qspi, baudrate);
if ((baudrate == QSPI_BAUDRATE_DIV_2)
|| ((baudrate == QSPI_BAUDRATE_DIV_4) && (__QSPI_READ_DDR_GET(qspi) == 1))) {
__QSPI_READ_CAPTURE_DELAY_SET(qspi, 2);
}
GLOBAL_INT_RESTORE();
}
}
uint32_t flash_init(struct qspi_regs_t *qspi)
{
flash_exit_deep_sleep(qspi);
return flash_read_id(qspi);
}
uint16_t flash_read_status(struct qspi_regs_t *qspi, bool read_high)
{
uint8_t *status;
uint16_t status_entity;
status = (uint8_t *)&status_entity;
qspi_stig_cmd(qspi, read_status_cmd, QSPI_STIG_CMD_READ, 1, &status[0]);
if(read_high) {
qspi_stig_cmd(qspi, read_status_h_cmd, QSPI_STIG_CMD_READ, 1, &status[1]);
}
return status_entity;
}
__RAM_CODE void flash_write_status(struct qspi_regs_t *qspi, uint16_t status, bool write_high)
{
uint8_t count = 1;
if(write_high) {
count++;
}
qspi_stig_cmd(qspi, write_enable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
qspi_stig_cmd(qspi, write_status_cmd, QSPI_STIG_CMD_WRITE, count, (void *)&status);
flash_wait_wip_clear(qspi);
}
__RAM_CODE void flash_write_status_2(struct qspi_regs_t *qspi, uint8_t status)
{
qspi_stig_cmd(qspi, write_enable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
qspi_stig_cmd(qspi, write_status_2_cmd, QSPI_STIG_CMD_WRITE, 1, (void *)&status);
flash_wait_wip_clear(qspi);
}
__RAM_CODE void flash_write_status_volatile(struct qspi_regs_t *qspi, uint16_t status, bool write_high)
{
uint8_t count = 1;
uint8_t poll_status;
if(write_high) {
count++;
}
qspi_stig_cmd(qspi, write_volatile_enable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
qspi_stig_cmd(qspi, write_status_cmd, QSPI_STIG_CMD_WRITE, count, (void *)&status);
}
__RAM_CODE void flash_write_status_2_volatile(struct qspi_regs_t *qspi, uint8_t status)
{
qspi_stig_cmd(qspi, write_volatile_enable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
qspi_stig_cmd(qspi, write_status_2_cmd, QSPI_STIG_CMD_WRITE, 1, (void *)&status);
}
/************************************************************************************
* @fn flash_protect_bit_set
*
* @brief set flash protection relevant bits.
*
* @param qspi: qspi controller base address
* bits: flash protection bits in status 1, BIT4:0 is valid.
* cmp: flash protection compare bit in status 2.
* 0xff means this field should be ignored
* BIT7: clear or set CMP bit
* BIT0-2: CMP bit offset in status 2
* wr_volatile: write status registers in volatile mode or not
* status_2_separate: write status 2 together with status 1 or separately
*/
__RAM_CODE void flash_protect_bit_set(struct qspi_regs_t *qspi, uint8_t bits, uint8_t cmp, uint8_t wr_volatile, uint8_t status_2_separate)
{
uint8_t status[2];
uint16_t status_tmp;
uint8_t skip_status_1 = 0;
if(cmp != 0xff) {
status_tmp = flash_read_status(qspi, true);
status[0] = status_tmp & 0xff;
status[1] = (status_tmp>>8) & 0xff;
if(cmp & 0x80) {
// set cmp bit
if((status[1] & (1<<(cmp&0x07))) != 0) {
cmp = 0xff;
}
else {
status[1] |= (1<<(cmp&0x07));
}
}
else {
// clear cmp bit
if((status[1] & (1<<(cmp&0x07))) == 0) {
cmp = 0xff;
}
else {
status[1] &= (~(1<<(cmp&0x07)));
}
}
}
else {
status_tmp = flash_read_status(qspi, false);
status[0] = status_tmp & 0xff;
}
bits &= 0x1f;
if((status[0] & 0x7C) == (bits << 2)) {
skip_status_1 = 1;
if (cmp == 0xff) {
return;
}
}
status[0] &= 0x80;
status[0] |= (bits << 2);
GLOBAL_INT_DISABLE();
if(cmp != 0xff) {
if(status_2_separate) {
if(wr_volatile) {
if(skip_status_1 == 0) {
flash_write_status_volatile(qspi, status[0], false);
}
flash_write_status_2_volatile(qspi, status[1]);
}
else {
if(skip_status_1 == 0) {
flash_write_status(qspi, status[0], false);
}
flash_write_status_2(qspi, status[1]);
}
}
else {
status_tmp = status[0] | (status[1]<<8);
if(wr_volatile) {
flash_write_status_volatile(qspi, status_tmp, true);
}
else {
flash_write_status(qspi, status_tmp, true);
}
}
}
else {
if(wr_volatile) {
flash_write_status_volatile(qspi, status[0], false);
}
else {
flash_write_status(qspi, status[0], false);
}
}
GLOBAL_INT_RESTORE();
}
__RAM_CODE __attribute__((noinline)) uint8_t flash_write(struct qspi_regs_t *qspi, uint32_t offset, uint32_t length, const uint8_t *buffer)
{
uint32_t page_left;
uint32_t dac_addr_offset;
uint8_t *dst;
if(length == 0) {
return 0;
}
if ((uint32_t)qspi == FLASH_QSPI_BASE) {
dac_addr_offset = FLASH_DAC_BASE;
}
else if ((uint32_t)qspi == DSP_QSPI_BASE) {
dac_addr_offset = DSP_FLASH_DAC_BASE;
}
else {
return 0;
}
page_left = 0x100 - (offset & 0xff);
if(length < page_left) {
page_left = length;
}
dst = (void *)(offset | dac_addr_offset);
GLOBAL_INT_DISABLE();
if ((uint32_t)qspi == FLASH_QSPI_BASE) {
system_cache_disable();
}
while(length) {
for (int32_t i=0; i<page_left; i++) {
*dst++ = *buffer++;
}
flash_wait_wip_clear(qspi);
length -= page_left;
page_left = (length > 256) ? 256 : length;
}
if ((uint32_t)qspi == FLASH_QSPI_BASE) {
system_cache_enable(true);
}
GLOBAL_INT_RESTORE();
return 0;
}
__USED uint8_t flash_read(struct qspi_regs_t *qspi, uint32_t offset, uint32_t length, uint8_t *buffer)
{
if ((uint32_t)qspi == FLASH_QSPI_BASE) {
memcpy(buffer, (void *)(offset | FLASH_DAC_BASE), length);
}
else if((uint32_t)qspi == DSP_QSPI_BASE) {
memcpy(buffer, (void *)(offset | DSP_FLASH_DAC_BASE), length);
}
return 0;
}
__RAM_CODE __attribute__((noinline)) uint8_t flash_erase(struct qspi_regs_t *qspi, uint32_t offset, uint32_t size)
{
if(size == 0) {
size = 0x1000;
}
offset &= 0xFFFFF000;
GLOBAL_INT_DISABLE();
system_cache_disable();
while(size) {
qspi_stig_cmd(qspi, write_enable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
__QSPI_CMD_ADDRESS_SET(qspi, offset);
qspi_stig_cmd(qspi, sector_erase_cmd, QSPI_STIG_CMD_EXE, 0, 0);
flash_wait_wip_clear(qspi);
offset += 0x1000;
if(size > 0x1000)
size -= 0x1000;
else {
size = 0;
}
}
system_cache_enable(true);
GLOBAL_INT_RESTORE();
return 0;
}
__RAM_CODE void flash_chip_erase(struct qspi_regs_t *qspi)
{
qspi_stig_cmd(qspi, write_enable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
qspi_stig_cmd(qspi, chip_erase_cmd, QSPI_STIG_CMD_EXE, 0, 0);
system_delay_us(20);
flash_wait_wip_clear(qspi);
}
__RAM_CODE void flash_enter_deep_sleep(struct qspi_regs_t *qspi)
{
qspi_stig_cmd(qspi, deep_sleep_cmd, QSPI_STIG_CMD_EXE, 0, 0);
system_delay_us(20);
}
__RAM_CODE void flash_exit_deep_sleep(struct qspi_regs_t *qspi)
{
qspi_stig_cmd(qspi, wakeup_cmd, QSPI_STIG_CMD_EXE, 0, 0);
system_delay_us(20);
}
/*********************************************************************
* @fn flash_OTP_read
*
* @brief read data from OTP sections. otp section size: 512 = 0x200
*
* @param offset - Security flash section offset, only valid for 0x1000,0x2000,0x3000
* length - buffer length to be read from security flash section. rang[1,512]
* buffer - pointer to buffer which will store data
*
* @return None.
*/
__RAM_CODE void flash_OTP_read(struct qspi_regs_t *qspi,uint32_t offset, uint32_t length, uint8_t *buffer)
{
uint32_t i = 0;
offset &= 0x3000;
if(length > 512)
length = 512;
GLOBAL_INT_DISABLE();
for(; (i+8) <= length; )
{
__QSPI_CMD_ADDRESS_SET(qspi, offset);
qspi_stig_cmd(qspi,sec_sector_read_cmd, QSPI_STIG_CMD_READ, 8, buffer + i );
i+=8;
offset+=8;
}
if(i < length)
{
__QSPI_CMD_ADDRESS_SET(qspi, offset);
qspi_stig_cmd(qspi,sec_sector_read_cmd, QSPI_STIG_CMD_READ, (length-i), (buffer+i));
}
GLOBAL_INT_RESTORE();
}
/*********************************************************************
* @fn flash_OTP_write
*
* @brief write data to OTP sections. otp section size: 512 = 0x200
*
* @param offset - Security flash section offset, only valid for 0x1000,0x2000,0x3000
* length - buffer length to be written into security flash section. rang[1,512]
* buffer - pointer to buffer which will be written
*
* @return None.
*/
__RAM_CODE void flash_OTP_write(struct qspi_regs_t *qspi,uint32_t offset, uint32_t length, uint8_t *buffer)
{
uint8_t status[1];
uint32_t i = 0;
#define SINGLE_LENGTH 8
offset &= 0x3000;
if(length > 512)
length = 512;
GLOBAL_INT_DISABLE();
for(; (i+SINGLE_LENGTH) <= length; )
{
qspi_stig_cmd(qspi,write_enable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
__QSPI_CMD_ADDRESS_SET(qspi, offset);
qspi_stig_cmd(qspi,sec_sector_write_cmd, QSPI_STIG_CMD_WRITE, SINGLE_LENGTH, buffer+i);
while(1) {
system_delay_us(20);
qspi_stig_cmd(qspi,read_status_cmd, QSPI_STIG_CMD_READ, 1, &status[0]);
if((status[0] & 0x01) == 0) {
break;
}
}
qspi_stig_cmd(qspi,write_disable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
i+=SINGLE_LENGTH;
offset+=SINGLE_LENGTH;
}
if(i < length)
{
qspi_stig_cmd(qspi,write_enable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
__QSPI_CMD_ADDRESS_SET(qspi, offset);
qspi_stig_cmd(qspi,sec_sector_write_cmd, QSPI_STIG_CMD_WRITE, (length-i), (buffer+i));
while(1) {
system_delay_us(20);
qspi_stig_cmd(qspi,read_status_cmd, QSPI_STIG_CMD_READ, 1, &status[0]);
if((status[0] & 0x01) == 0) {
break;
}
}
qspi_stig_cmd(qspi,write_disable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
}
GLOBAL_INT_RESTORE();
}
/*********************************************************************
* @fn flash_OTP_erase
*
* @brief erase whole OTP section .
*
* @param offset - Security flash section offset, only valid for 0x1000,0x2000,0x3000
*
* @return None.
*/
__RAM_CODE void flash_OTP_erase(struct qspi_regs_t *qspi,uint32_t offset)
{
uint8_t status;
offset &= 0x3000;
GLOBAL_INT_DISABLE();
qspi_stig_cmd(qspi,write_enable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
__QSPI_CMD_ADDRESS_SET(qspi, offset);
qspi_stig_cmd(qspi,sec_sector_erase_cmd, QSPI_STIG_CMD_EXE, 0, 0);
while(1) {
system_delay_us(20);
qspi_stig_cmd(qspi,read_status_cmd, QSPI_STIG_CMD_READ, 1, &status);
if((status & 0x01) == 0) {
break;
}
}
qspi_stig_cmd(qspi,write_disable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
GLOBAL_INT_RESTORE();
}

View File

@ -0,0 +1,148 @@
/**
****************************************************************************************
*
* @file frspim.c
*
* @brief freqchip spi master initialization and specific functions
*
* Copyright (C) RivieraWaves 2009-2013
*
*
****************************************************************************************
*/
/**
****************************************************************************************
* @addtogroup RF_FR
* @ingroup RF
* @brief FREQCHIP Radio Driver
*
* This is the driver block for FR radio
* @{
****************************************************************************************
*/
/*
* INCLUDE FILES
****************************************************************************************
*/
#include "fr30xx.h"
/*
* DEFINES
****************************************************************************************
*/
volatile struct frspim_reg_t * const frspim_reg = (volatile struct frspim_reg_t * )FRSPIM_BASE;
/*
* FUNCTION DEFINITIONS
****************************************************************************************
*/
void frspim_init(uint8_t ratio)
{
frspim_reg->ctrl.ratio = ratio;
}
/*****************************************************************************************
* @brief SPI access
****************************************************************************************
*/
/*****************************************************************************************
* @brief Bluejay specific read access
*
* @param[in] addr register address
*
* @return uint32_t value
****************************************************************************************
*/
__RAM_CODE uint32_t frspim_rd (uint8_t chan_num, uint8_t addr, uint8_t len)
{
uint32_t data;
GLOBAL_INT_DISABLE();
frspim_reg->ctrl.len = len;
frspim_reg->ctrl.sel = chan_num;
frspim_reg->ctrl.op = 0;
frspim_reg->ctrl.addr = addr;
frspim_reg->ctrl.go = 1;
while(!frspim_reg->ctrl.done);
data = (*((uint32_t *)(&frspim_reg->rdat)));
GLOBAL_INT_RESTORE();
return data;
}
/*****************************************************************************************
* @brief Bluejay specific read access for ram
*
* @param[in] addr register address
*
* @return uint32_t value
****************************************************************************************
*/
__RAM_CODE uint32_t frspim_rd_ram (uint8_t chan_num, uint8_t addr, uint8_t len)
{
uint32_t data;
GLOBAL_INT_DISABLE();
*(volatile uint32_t *)(&frspim_reg->ctrl) = 0x00001011 | (addr<<16);
while(!frspim_reg->ctrl.done);
data = *(volatile uint32_t *)(&frspim_reg->rdat);
GLOBAL_INT_RESTORE();
return data;
}
/*****************************************************************************************
* @brief Freqchip specific write access
*
* @param[in] addr register address
* @param[in] value value to write
*
* @return uint32_t value
****************************************************************************************
*/
__RAM_CODE void frspim_wr (uint8_t chan_num, uint8_t addr, uint8_t len, uint32_t val)
{
GLOBAL_INT_DISABLE();
frspim_reg->ctrl.len = len;
frspim_reg->ctrl.sel = chan_num;
frspim_reg->ctrl.op = 1;
frspim_reg->ctrl.addr = addr;
(*((uint32_t *)(&frspim_reg->wdat))) = val;
frspim_reg->ctrl.go = 1;
while(!frspim_reg->ctrl.done);
GLOBAL_INT_RESTORE();
}
/*****************************************************************************************
* @brief Freqchip specific write access for ram
*
* @param[in] addr register address
* @param[in] value value to write
*
* @return uint32_t value
****************************************************************************************
*/
__RAM_CODE void frspim_wr_ram (uint8_t chan_num, uint8_t addr, uint8_t len, uint32_t val)
{
GLOBAL_INT_DISABLE();
*(volatile uint32_t *)(&frspim_reg->wdat) = val;
*(volatile uint32_t *)(&frspim_reg->ctrl) = 0x00001111 | (addr<<16);;
while(!frspim_reg->ctrl.done);
GLOBAL_INT_RESTORE();
}

View File

@ -0,0 +1,426 @@
/*
******************************************************************************
* @file driver_gpio.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief GPIO module driver.
* This file provides firmware functions to manage the
* General Purpose Input/Output (GPIO) peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/************************************************************************************
* @fn gpio_init
*
* @brief Initializes the GPIOx peripheral according to the specified
* parameters in the GPIO_Init
*
* @param fe_GPIO: to select the GPIO peripheral.
* GPIO_Init: pointer to a GPIO_InitTypeDef structure that contains the
* configuration information for the specified GPIO peripheral.
*/
__RAM_CODE void gpio_init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init)
{
uint32_t lu32_Position = 0;
uint32_t lu32_Current_Pin;
volatile uint32_t *GPIO_Pull_EN;
volatile uint32_t *GPIO_Pull_Select;
volatile uint32_t *GPIO_FuncMuxL;
volatile uint32_t *GPIO_FuncMuxH;
/* Select the group register */
if (GPIOx == GPIOA)
{
GPIO_Pull_EN = &(SYSTEM->PortA_PullEN);
GPIO_Pull_Select = &(SYSTEM->PortA_PullSelect);
GPIO_FuncMuxL = &(SYSTEM->PortA_L_FuncMux);
GPIO_FuncMuxH = &(SYSTEM->PortA_H_FuncMux);
}
else if (GPIOx == GPIOB)
{
GPIO_Pull_EN = &(SYSTEM->PortB_PullEN);
GPIO_Pull_Select = &(SYSTEM->PortB_PullSelect);
GPIO_FuncMuxL = &(SYSTEM->PortB_L_FuncMux);
GPIO_FuncMuxH = &(SYSTEM->PortB_H_FuncMux);
}
else if (GPIOx == GPIOC)
{
GPIO_Pull_EN = &(SYSTEM->PortC_PullEN);
GPIO_Pull_Select = &(SYSTEM->PortC_PullSelect);
GPIO_FuncMuxL = &(SYSTEM->PortC_L_FuncMux);
GPIO_FuncMuxH = &(SYSTEM->PortC_H_FuncMux);
}
else if (GPIOx == GPIOD)
{
GPIO_Pull_EN = &(SYSTEM->PortD_PullEN);
GPIO_Pull_Select = &(SYSTEM->PortD_PullSelect);
GPIO_FuncMuxL = &(SYSTEM->PortD_L_FuncMux);
GPIO_FuncMuxH = &(SYSTEM->PortD_H_FuncMux);
}
/* Configure Select pins */
while ((GPIO_Init->Pin) >> lu32_Position != 0)
{
/* Get current pin position */
lu32_Current_Pin = (GPIO_Init->Pin) & (1uL << lu32_Position);
if (lu32_Current_Pin)
{
switch (GPIO_Init->Mode)
{
case GPIO_MODE_INPUT:
{
GPIOx->GPIO_OutputEN |= lu32_Current_Pin;
GPIOx->EXTI_EN &= ~lu32_Current_Pin;
GPIOx->EXTI_INT_EN &= ~lu32_Current_Pin;
}break;
case GPIO_MODE_INPUT_HRS:
{
GPIOx->GPIO_OutputEN |= lu32_Current_Pin;
GPIOx->EXTI_EN &= ~lu32_Current_Pin;
GPIOx->EXTI_INT_EN &= ~lu32_Current_Pin;
/* High Resistance Mode does not pull up or down */
GPIO_Init->Pull = GPIO_NOPULL;
}break;
case GPIO_MODE_OUTPUT_PP:
{
GPIOx->GPIO_OutputEN &= ~lu32_Current_Pin;
GPIOx->EXTI_EN &= ~lu32_Current_Pin;
GPIOx->EXTI_INT_EN &= ~lu32_Current_Pin;
}break;
case GPIO_MODE_AF_PP:
{
/* Port 0 ~ 7 */
if (lu32_Position < 8)
{
*GPIO_FuncMuxL = (*GPIO_FuncMuxL & ~(0xF << (lu32_Position * 4))) | (GPIO_Init->Alternate << (lu32_Position * 4));
}
/* Port 8 ~ 15 */
else
{
*GPIO_FuncMuxH = (*GPIO_FuncMuxH & ~(0xF << ((lu32_Position - 8) * 4))) | (GPIO_Init->Alternate << ((lu32_Position - 8) * 4));
}
}break;
case GPIO_MODE_EXTI_IT_RISING:
case GPIO_MODE_EXTI_IT_FALLING:
case GPIO_MODE_EXTI_IT_HIGH_LEVEL:
case GPIO_MODE_EXTI_IT_LOW_LEVEL:
{
GPIOx->EXTI_TYPE = (GPIOx->EXTI_TYPE & ~(0x3 << (lu32_Position * 2))) | ((GPIO_Init->Mode & 0x3) << (lu32_Position * 2));
GPIOx->GPIO_OutputEN |= lu32_Current_Pin;
GPIOx->EXTI_EN |= lu32_Current_Pin;
GPIOx->EXTI_INT_EN &= ~lu32_Current_Pin;
}break;
default: break;
}
/* GPIO Function */
if (GPIO_Init->Mode & GPIO_MODE_IO_MASK)
{
/* Port 0 ~ 7 */
if (lu32_Position < 8)
{
*GPIO_FuncMuxL = *GPIO_FuncMuxL & ~(0xF << (lu32_Position * 4));
}
/* Port 8 ~ 15 */
else
{
*GPIO_FuncMuxH = *GPIO_FuncMuxH & ~(0xF << ((lu32_Position - 8) * 4));
}
}
/* Set Pull UP/DOWN or NO Pull */
if (GPIO_Init->Pull == GPIO_NOPULL)
{
*GPIO_Pull_EN &= ~lu32_Current_Pin;
}
else if (GPIO_Init->Pull == GPIO_PULLUP)
{
*GPIO_Pull_EN |= lu32_Current_Pin;
*GPIO_Pull_Select |= lu32_Current_Pin;
}
else if (GPIO_Init->Pull == GPIO_PULLDOWN)
{
*GPIO_Pull_EN |= lu32_Current_Pin;
*GPIO_Pull_Select &= ~lu32_Current_Pin;
}
}
lu32_Position++;
}
}
/************************************************************************************
* @fn gpio_set_portpull
*
* @brief set port pull
*
* @param GPIOx: where x can be (GPIOA ~ GPIOB) to select the GPIO peripheral.
* @param fu16_Pin: to select the Pin (1bit ~ 1Pin). @ref GPIO_pins
* @param fe_Pull: pull up/pull down/no pull @ref enum_Pull_t
* @return pin status.
*/
void gpio_set_portpull(GPIO_TypeDef *GPIOx, uint16_t fu16_Pin, enum_Pull_t fe_Pull)
{
uint32_t lu32_Position = 0;
uint32_t lu32_Current_Pin;
volatile uint32_t *GPIO_Pull_EN;
volatile uint32_t *GPIO_Pull_Select;
/* Select the group register */
if (GPIOx == GPIOA)
{
GPIO_Pull_EN = &(SYSTEM->PortA_PullEN);
GPIO_Pull_Select = &(SYSTEM->PortA_PullSelect);
}
else if (GPIOx == GPIOB)
{
GPIO_Pull_EN = &(SYSTEM->PortB_PullEN);
GPIO_Pull_Select = &(SYSTEM->PortB_PullSelect);
}
else if (GPIOx == GPIOC)
{
GPIO_Pull_EN = &(SYSTEM->PortC_PullEN);
GPIO_Pull_Select = &(SYSTEM->PortC_PullSelect);
}
else if (GPIOx == GPIOD)
{
GPIO_Pull_EN = &(SYSTEM->PortD_PullEN);
GPIO_Pull_Select = &(SYSTEM->PortD_PullSelect);
}
/* Configure Select pins */
while (fu16_Pin >> lu32_Position != 0)
{
/* Get current pin position */
lu32_Current_Pin = fu16_Pin & (1uL << lu32_Position);
if (lu32_Current_Pin)
{
/* Set Pull UP or DOWN or NO */
if (fe_Pull == GPIO_NOPULL)
{
*GPIO_Pull_EN &= ~lu32_Current_Pin;
}
else if (fe_Pull == GPIO_PULLUP)
{
*GPIO_Pull_EN |= lu32_Current_Pin;
*GPIO_Pull_Select |= lu32_Current_Pin;
}
else if (fe_Pull == GPIO_PULLDOWN)
{
*GPIO_Pull_EN |= lu32_Current_Pin;
*GPIO_Pull_Select &= ~lu32_Current_Pin;
}
}
lu32_Position++;
}
}
/************************************************************************************
* @fn gpio_write_group
*
* @brief write gpio status, The unit is group.
*
* @param GPIOx: where x can be (GPIOA ~ GPIOD) to select the GPIO peripheral.
* @param fu16_GroupStatus: Group Status.(1bit ~ 1Pin)
*/
void gpio_write_group(GPIO_TypeDef *GPIOx, uint16_t fu16_GroupStatus)
{
GPIOx->GPIO_OUT_DATA = fu16_GroupStatus;
}
/************************************************************************************
* @fn gpio_write_pin
*
* @brief write gpio status, The unit is pin.
*
* @param GPIOx: where x can be (GPIOA ~ GPIOD) to select the GPIO peripheral.
* @param fu16_Pin: to select the Pin (1bit ~ 1Pin). @ref GPIO_pins
* @param fe_PinStatus: pin Status. @ref enum_PinStatus_t
*/
void gpio_write_pin(GPIO_TypeDef *GPIOx, uint16_t fu16_Pin, enum_PinStatus_t fe_PinStatus)
{
if (fe_PinStatus)
{
GPIOx->GPIO_BIT_SET = fu16_Pin;
}
else
{
GPIOx->GPIO_BIT_CLEAR = fu16_Pin;
}
}
/************************************************************************************
* @fn gpio_read_group
*
* @brief read gpio status, The unit is group.
*
* @param GPIOx: where x can be (GPIOA ~ GPIOD) to select the GPIO peripheral.
* @return group status.(1bit ~ 1Pin)
*/
uint16_t gpio_read_group(GPIO_TypeDef *GPIOx)
{
return GPIOx->GPIO_IN_DATA;
}
/************************************************************************************
* @fn gpio_read_pin
*
* @brief read gpio status, The unit is pin.
*
* @param GPIOx: where x can be (GPIOA ~ GPIOD) to select the GPIO peripheral.
* @param fu16_Pin: to select the Pin (1bit ~ 1Pin). @ref GPIO_pins
* @return pin status.
*/
enum_PinStatus_t gpio_read_pin(GPIO_TypeDef *GPIOx, uint16_t fu16_Pin)
{
enum_PinStatus_t le_PinStatus;
le_PinStatus = (GPIOx->GPIO_IN_DATA & fu16_Pin) ? GPIO_PIN_SET : GPIO_PIN_CLEAR;
return le_PinStatus;
}
/************************************************************************************
* @fn gpio_drive_current_config
*
* @brief gpio drive current config.
*
* @param GPIOx: where x can be (GPIOA ~ GPIOD) to select the GPIO peripheral.
* @param fu16_Pin: to select the Pin (1bit ~ 1Pin). @ref GPIO_pins
* @param fe_GPIO_Drive: Drive Current. @ref enum_GPIO_Drive_Current_t
*/
void gpio_drive_current_config(GPIO_TypeDef *GPIOx, uint16_t fu16_Pin, enum_GPIO_Drive_Current_t fe_GPIO_Drive)
{
uint32_t lu32_Position = 0;
uint32_t lu32_Current_Pin;
/* Configure Select pins */
while (fu16_Pin >> lu32_Position != 0)
{
/* Get current pin position */
lu32_Current_Pin = fu16_Pin & (1uL << lu32_Position);
if (lu32_Current_Pin)
{
if (GPIOx == GPIOA)
SYSTEM->PortA_DriveCfg = (SYSTEM->PortA_DriveCfg & ~(0x3 << (lu32_Position * 2))) | (fe_GPIO_Drive << (lu32_Position * 2));
else if (GPIOx == GPIOB)
SYSTEM->PortB_DriveCfg = (SYSTEM->PortB_DriveCfg & ~(0x3 << (lu32_Position * 2))) | (fe_GPIO_Drive << (lu32_Position * 2));
else if (GPIOx == GPIOC)
SYSTEM->PortC_DriveCfg = (SYSTEM->PortC_DriveCfg & ~(0x3 << (lu32_Position * 2))) | (fe_GPIO_Drive << (lu32_Position * 2));
else if (GPIOx == GPIOD)
SYSTEM->PortD_DriveCfg = (SYSTEM->PortD_DriveCfg & ~(0x3 << (lu32_Position * 2))) | (fe_GPIO_Drive << (lu32_Position * 2));
}
lu32_Position++;
}
}
/************************************************************************************
* @fn exti_interrupt_enable
*
* @brief exti line interrupt enable.
*
* @param GPIOx: where x can be (GPIOA ~ GPIOD) to select the GPIO peripheral.
* @param fu16_EXTI_Line: to select the EXTI line.(1bit ~ 1Pin)
*/
void exti_interrupt_enable(GPIO_TypeDef *GPIOx, uint16_t fu16_EXTI_Line)
{
GPIOx->EXTI_INT_EN |= fu16_EXTI_Line;
}
/************************************************************************************
* @fn exti_interrupt_disable
*
* @brief exti line interrupt disable.
*
* @param GPIOx: where x can be (GPIOA ~ GPIOD) to select the GPIO peripheral.
* @param fu16_EXTI_Line: to select the EXTI line (1bit ~ 1Pin). @ref EXTI_line_index
*/
void exti_interrupt_disable(GPIO_TypeDef *GPIOx, uint16_t fu16_EXTI_Line)
{
GPIOx->EXTI_INT_EN &= ~fu16_EXTI_Line;
}
/************************************************************************************
* @fn exti_get_LineStatus
*
* @brief get exti line interrupt status.
*
* @param GPIOx: where x can be (GPIOA ~ GPIOD) to select the GPIO peripheral.
* @param fu8_EXTI_Line: to select the EXTI line (1bit ~ 1Pin). @ref EXTI_line_index
* @return true: interrupt activate
* false: interrupt inactivate
*/
bool exti_get_LineStatus(GPIO_TypeDef *GPIOx, uint16_t fu16_EXTI_Line)
{
bool lb_EXTIStatus;
lb_EXTIStatus = (GPIOx->EXTI_INT_STATUS & fu16_EXTI_Line) ? true : false;
return lb_EXTIStatus;
}
/************************************************************************************
* @fn exti_clear_LineStatus
*
* @brief clear exti line interrupt status.
*
* @param GPIOx: where x can be (GPIOA ~ GPIOD) to select the GPIO peripheral.
* @param fu8_EXTI_Line: to select the EXTI line (1bit ~ 1Pin). @ref EXTI_line_index
*/
void exti_clear_LineStatus(GPIO_TypeDef *GPIOx, uint16_t fu16_EXTI_Line)
{
GPIOx->EXTI_INT_STATUS |= fu16_EXTI_Line;
}
/************************************************************************************
* @fn exti_set_FilterCNT
*
* @brief set exti line filer.
*
* @param GPIOx: where x can be (GPIOA ~ GPIOD) to select the GPIO peripheral.
* @param fu16_EXTI_Line: to select the EXTI line (1bit ~ 1Pin). @ref EXTI_line_index
* @param fu8_DIV: filter clock divider. (can be a 4-bit value)
* @param fu16_CNT: filter count. (can be a 12-bit value)
*/
void exti_set_Filter(GPIO_TypeDef *GPIOx, uint16_t fu16_EXTI_Line, uint8_t fu8_DIV, uint16_t fu16_CNT)
{
uint32_t lu32_Position = 0;
uint32_t lu32_Current_Pin;
/* Init write value */
uint32_t lu32_WriteValue = fu8_DIV << 12 | fu16_CNT;
/* Configure Select pins */
while (fu16_EXTI_Line >> lu32_Position != 0)
{
/* Get current pin position */
lu32_Current_Pin = fu16_EXTI_Line & (1uL << lu32_Position);
if (lu32_Current_Pin)
{
GPIOx->EXTI_CNT[lu32_Position] = lu32_WriteValue;
}
lu32_Position++;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,513 @@
/*
******************************************************************************
* @file driver_i2s.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief I2S module driver.
* This file provides firmware functions to manage the
* Inter<65><72>IC Sound (I2S) peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/************************************************************************************
* @fn i2s_IRQHandler
*
* @brief Handle I2S interrupt request.
*
* @param huart: I2S handle.
*/
//void i2s_IRQHandler(I2S_HandleTypeDef *hi2s)
//{
// /* Format 20Bit/24Bit/32bit */
// if (hi2s->Init.DataFormat > I2S_DATA_FORMAT_16BIT)
// {
// /* TxFIFO half full interrupt enable */
// if (__I2S_INT_IS_ENANLE(hi2s->I2Sx, I2S_TX_FIFOS_HALF_FULL))
// {
// /* FIFO half full */
// if ((__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_TX_FIFOS_HALF_FULL))
// {
// while(!(__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_TX_FIFOS_FULL))
// {
// /* right channel*/
// if (hi2s->u32_TxCount % 2)
// {
// hi2s->I2Sx->DATA_R = hi2s->p_TxData[hi2s->u32_TxCount++];
// }
// /* left channel*/
// else
// {
// hi2s->I2Sx->DATA_L = hi2s->p_TxData[hi2s->u32_TxCount++];
// }
//
// if (hi2s->u32_TxCount >= hi2s->u32_TxSize)
// {
// __I2S_INT_DISABLE(hi2s->I2Sx, I2S_TX_FIFOS_HALF_FULL);
//
// hi2s->b_TxBusy = false;
//
// break;
// }
// }
// }
// }
// /* Rx FIFO full interrupt enable */
// if(__I2S_INT_IS_ENANLE(hi2s->I2Sx, I2S_RX_FIFOS_HALF_FULL))
// {
// /* FIFO half full */
// if ((__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_RX_FIFOS_HALF_FULL))
// {
// while(!(__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_RX_FIFOS_EMPTY))
// {
// /* right channel*/
// if (hi2s->u32_RxCount % 2)
// {
// hi2s->p_RxData[hi2s->u32_RxCount++] = hi2s->I2Sx->DATA_R;
// }
// /* left channel*/
// else
// {
// hi2s->p_RxData[hi2s->u32_RxCount++] = hi2s->I2Sx->DATA_L;
// }
//
// if(hi2s->u32_RxCount >= hi2s->u32_RxSize)
// {
// __I2S_INT_DISABLE(hi2s->I2Sx, I2S_RX_FIFOS_HALF_FULL);
//
// hi2s->b_RxBusy = false;
// break;
// }
// }
// }
// }
// }
// /* Format 8Bit/16Bit */
// else
// {
// /* TxFIFO half full interrupt enable */
// if (__I2S_INT_IS_ENANLE(hi2s->I2Sx, I2S_TX_L_FIFO_HALF_FULL))
// {
// /* FIFO half full */
// if ((__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_TX_L_FIFO_HALF_FULL))
// {
// while(!(__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_TX_L_FIFO_FULL))
// {
// hi2s->I2Sx->DATA_L = hi2s->p_TxData[hi2s->u32_TxCount++];
//
// if (hi2s->u32_TxCount >= hi2s->u32_TxSize)
// {
// __I2S_INT_DISABLE(hi2s->I2Sx, I2S_TX_L_FIFO_HALF_FULL);
//
// hi2s->b_TxBusy = false;
//
// break;
// }
// }
// }
// }
// /* Rx FIFO full interrupt enable */
// if(__I2S_INT_IS_ENANLE(hi2s->I2Sx, I2S_RX_L_FIFO_HALF_FULL))
// {
// /* FIFO half full */
// if ((__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_RX_L_FIFO_HALF_FULL))
// {
// while(!(__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_RX_L_FIFO_EMPTY))
// {
// hi2s->p_RxData[hi2s->u32_RxCount++] = hi2s->I2Sx->DATA_L;
//
// if(hi2s->u32_RxCount >= hi2s->u32_RxSize)
// {
// __I2S_INT_DISABLE(hi2s->I2Sx, I2S_RX_L_FIFO_HALF_FULL);
//
// hi2s->b_RxBusy = false;
// break;
// }
// }
// }
// }
// }
//}
void i2s_IRQHandler(I2S_HandleTypeDef *hi2s)
{
/* Format 20Bit/24Bit/32bit */
if (hi2s->Init.DataFormat > I2S_DATA_FORMAT_16BIT)
{
/* TxFIFO half full interrupt enable */
if (__I2S_INT_IS_ENANLE(hi2s->I2Sx, I2S_TX_FIFOS_ALMOST_EMPTY))
{
/* FIFO half full */
if ((__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_TX_FIFOS_ALMOST_EMPTY))
{
if (hi2s->TxIntCallback)
{
hi2s->TxIntCallback(hi2s);
}
else
{
for (uint32_t i=0; i<I2S_FIFO_HALF_DEPTH; i++)
{
hi2s->I2Sx->DATA_L = 0;
hi2s->I2Sx->DATA_R = 0;
}
}
}
}
/* Rx FIFO full interrupt enable */
if(__I2S_INT_IS_ENANLE(hi2s->I2Sx, I2S_RX_FIFOS_HALF_FULL))
{
/* FIFO half full */
if ((__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_RX_FIFOS_HALF_FULL))
{
if (hi2s->RxIntCallback)
{
hi2s->RxIntCallback(hi2s);
}
else
{
for (uint32_t i=0; i<I2S_FIFO_HALF_DEPTH; i++)
{
volatile uint32_t l_data = hi2s->I2Sx->DATA_L;
volatile uint32_t r_data = hi2s->I2Sx->DATA_R;
}
}
}
}
}
/* Format 8Bit/16Bit */
else
{
/* TxFIFO half full interrupt enable */
if (__I2S_INT_IS_ENANLE(hi2s->I2Sx, I2S_TX_L_FIFO_ALMOST_EMPTY))
{
/* FIFO half full */
if ((__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_TX_L_FIFO_ALMOST_EMPTY))
{
if (hi2s->TxIntCallback)
{
hi2s->TxIntCallback(hi2s);
}
else
{
for (uint32_t i=0; i<I2S_FIFO_HALF_DEPTH; i++)
{
hi2s->I2Sx->DATA_L = 0;
}
}
}
}
/* Rx FIFO full interrupt enable */
if(__I2S_INT_IS_ENANLE(hi2s->I2Sx, I2S_RX_L_FIFO_HALF_FULL))
{
/* FIFO half full */
if ((__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_RX_L_FIFO_HALF_FULL))
{
if (hi2s->RxIntCallback)
{
hi2s->RxIntCallback(hi2s);
}
else
{
for (uint32_t i=0; i<I2S_FIFO_HALF_DEPTH; i++)
{
volatile uint32_t l_data = hi2s->I2Sx->DATA_L;
}
}
}
}
}
}
/************************************************************************************
* @fn i2s_init
*
* @brief Initialize the I2S peripheral according to the specified
* parameters in the struct_I2SInit_t
*
* @param hi2s: I2S handle.
*/
void i2s_init(I2S_HandleTypeDef *hi2s)
{
hi2s->b_TxBusy = false;
hi2s->b_RxBusy = false;
/* disable all interrupt */
__I2S_INT_DISABLE(hi2s->I2Sx, I2S_ALL_FIFO_STATUS);
/* Enable Rx/Tx FIFO */
__I2S_RxFIFO_EN(hi2s->I2Sx);
__I2S_TxFIFO_EN(hi2s->I2Sx);
/* Clear Rx/Tx FIFO */
__I2S_RxFIFO_CLR(hi2s->I2Sx);
__I2S_TxFIFO_CLR(hi2s->I2Sx);
/* left and right channels operate simultaneously */
__I2S_WD_SWAP_HIGH16SIZE_RIGHT(hi2s->I2Sx);
/* config mode */
hi2s->I2Sx->CTRL0.MSTSLV = hi2s->Init.Mode;
/* Calculate audio frequency */
hi2s->I2Sx->FrmDiv.BCLKDIV = hi2s->Init.BCLKDIV - 1;
/* Calculate channel length */
hi2s->I2Sx->FrmDiv.FRMDIV = hi2s->Init.ChannelLength - 1;
/* Data length */
hi2s->I2Sx->CTRL1.I2S_DATA_LENGTH = hi2s->Init.DataFormat;
switch (hi2s->Init.Standard)
{
/* philips */
case I2S_STANDARD_PHILIPS:
{
hi2s->I2Sx->CTRL1.I2S_NORMAL = 1;
__I2S_ENABLE(hi2s->I2Sx);
}break;
/* MSB */
case I2S_STANDARD_MSB:
{
hi2s->I2Sx->CTRL1.I2S_NORMAL = 0;
hi2s->I2Sx->CTRL1.I2S_ADJUST = 0;
__I2S_FRAME_INV_ENABLE(hi2s->I2Sx);
__I2S_ENABLE(hi2s->I2Sx);
}break;
/* LSB */
case I2S_STANDARD_LSB:
{
uint32_t data_length[5] = {8,16,20,24,32};
hi2s->I2Sx->CTRL1.I2S_NORMAL = 0;
hi2s->I2Sx->CTRL1.I2S_ADJUST = 1;
hi2s->I2Sx->CTRL1.I2SFBOFF = hi2s->Init.ChannelLength - data_length[hi2s->Init.DataFormat];
__I2S_FRAME_INV_ENABLE(hi2s->I2Sx);
__I2S_ENABLE(hi2s->I2Sx);
}break;
/* PCM */
case I2S_STANDARD_PCM:
{
/* Mono or Stereo select*/
hi2s->I2Sx->PCM_RHYCTRL.PCM_SAMPTYPE = 0;
hi2s->I2Sx->PCM_GENCTRL.PCM_MONO_STEREO = 0;
/* Frame Synchronization signal */
hi2s->I2Sx->PCM_RHYCTRL.PCM_FSYNCSHP = 0;
/* Sample size and slots */
__I2S_PCM_SLOTS_SET(hi2s->I2Sx, 1);
__I2S_PCM_SAMPLESIZE_16BIT(hi2s->I2Sx);
/* ENABLE PCM */
hi2s->I2Sx->PCM_RHYCTRL.PCM_DOUTCFG = 1;
__I2S_PCM_ENABLE(hi2s->I2Sx);
}break;
default: break;
}
}
/************************************************************************************
* @fn i2s_deinit
*
* @brief deinit an ongoing i2s.
*
* @param hi2s: I2S handle.
*/
void i2s_deinit(I2S_HandleTypeDef *hi2s)
{
__I2S_PCM_DISABLE(hi2s->I2Sx);
__I2S_DISABLE(hi2s->I2Sx);
hi2s->b_TxBusy = false;
hi2s->b_RxBusy = false;
}
/************************************************************************************
* @fn i2s_transmit_IT
*
* @brief Transmit an I2S data in interrupt mode, user should send data in TxCallback with
* i2s_send_data function.
*
* @param huart: I2S handle.
*/
bool i2s_transmit_IT(I2S_HandleTypeDef *hi2s)
{
if (hi2s->b_TxBusy) return false;
hi2s->b_TxBusy = true;
__I2S_L_TxFIFO_EMPTY_LEVEL(hi2s->I2Sx, I2S_FIFO_HALF_DEPTH);
__I2S_R_TxFIFO_EMPTY_LEVEL(hi2s->I2Sx, I2S_FIFO_HALF_DEPTH);
/* Format 20Bit/24Bit/32bit */
if (hi2s->Init.DataFormat > I2S_DATA_FORMAT_16BIT)
{
__I2S_LR_WD_DISABLE(hi2s->I2Sx);
__I2S_INT_ENABLE(hi2s->I2Sx, I2S_TX_FIFOS_ALMOST_EMPTY);
}
/* Format 8Bit/16Bit */
else
{
__I2S_LR_WD_ENABLE(hi2s->I2Sx);
__I2S_INT_ENABLE(hi2s->I2Sx, I2S_TX_L_FIFO_ALMOST_EMPTY);
}
return true;
}
/************************************************************************************
* @fn i2s_receive_IT
*
* @brief Receive an I2S data in interrupt mode. User read received data with function
* i2s_read_data in RxCallback.
*
* @param huart: I2S handle.
*/
bool i2s_receive_IT(I2S_HandleTypeDef *hi2s)
{
if (hi2s->b_RxBusy) return false;
hi2s->b_RxBusy = true;
__I2S_L_RxFIFO_FULL_LEVEL(hi2s->I2Sx, 16);
__I2S_R_RxFIFO_FULL_LEVEL(hi2s->I2Sx, 16);
/* Format 20Bit/24Bit/32bit */
if (hi2s->Init.DataFormat > I2S_DATA_FORMAT_16BIT)
{
__I2S_LR_WD_DISABLE(hi2s->I2Sx);
__I2S_INT_ENABLE(hi2s->I2Sx, I2S_RX_FIFOS_HALF_FULL);
}
/* Format 8Bit/16Bit */
else
{
__I2S_LR_WD_ENABLE(hi2s->I2Sx);
__I2S_INT_ENABLE(hi2s->I2Sx, I2S_RX_L_FIFO_HALF_FULL);
}
return true;
}
/************************************************************************************
* @fn i2s_read_data
*
* @brief Read data from RX FIFO. One sample contains left and right channel data. When
* DataFormat is not more than 16-bits, one sample takes 32-bits, left channel data
* is stored in high 16-bits and right channel data is stored in low 16-bits. When
* DataFormat is more than 16-bits, one sample takes 2 words.
*
* @param huart: I2S handle.
* buffer: buffer used to store received data.
* samples: How many samples expected to receive.
*
* @return How many samples read from RX FIFO
*/
uint32_t i2s_read_data(I2S_HandleTypeDef *hi2s, uint32_t *buffer, uint32_t samples)
{
uint32_t count = 0;
if (hi2s->Init.DataFormat > I2S_DATA_FORMAT_16BIT)
{
while ((!(__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_RX_FIFOS_EMPTY))
&& (count < samples))
{
buffer[count] = hi2s->I2Sx->DATA_L;
buffer[count] = hi2s->I2Sx->DATA_R;
count++;
}
}
else
{
__I2S_LR_WD_ENABLE(hi2s->I2Sx);
while ((!(__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_RX_L_FIFO_EMPTY))
&& (count < samples))
{
buffer[count] = hi2s->I2Sx->DATA_L;
count++;
}
}
return count;
}
/************************************************************************************
* @fn i2s_send_data
*
* @brief write data to TX FIFO. One sample contains left and right channel data. When
* DataFormat is not more than 16-bits, one sample takes 32-bits, left channel data
* is stored in high 16-bits and right channel data is stored in low 16-bits. When
* DataFormat is more than 16-bits, one sample takes 2 words.
*
* @param huart: I2S handle.
* buffer: buffer used to store sending data.
* samples: How many samples expected to send.
*
* @return How many samples sent to TX FIFO
*/
uint32_t i2s_send_data(I2S_HandleTypeDef *hi2s, uint32_t *buffer, uint32_t samples)
{
uint32_t count = 0;
if (hi2s->Init.DataFormat > I2S_DATA_FORMAT_16BIT)
{
while ((!(__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_TX_FIFOS_FULL))
&& (count < samples))
{
hi2s->I2Sx->DATA_L = buffer[count];
hi2s->I2Sx->DATA_R = buffer[count];
count++;
}
}
else
{
__I2S_LR_WD_ENABLE(hi2s->I2Sx);
while ((!(__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_TX_L_FIFO_FULL))
&& (count < samples))
{
hi2s->I2Sx->DATA_L = buffer[count];
count++;
}
}
return count;
}
/************************************************************************************
* @fn i2s_transmit_DMA
*
* @brief Transmit an amount of data in DMA mode.
*/
void i2s_transmit_DMA(I2S_HandleTypeDef *hi2s)
{
hi2s->I2Sx->DMA_CFG.DMACR_L_TX = 1;
hi2s->I2Sx->DMA_CFG.DMACR_R_TX = 1;
/* Tx empty dma level */
__I2S_TX_DMA_EMPTY_LEVEL(hi2s->I2Sx, 16);
}
/************************************************************************************
* @fn i2s_receive_DMA
*
* @brief Receive an amount of data in DMA mode.
*/
void i2s_receive_DMA(I2S_HandleTypeDef *hi2s)
{
hi2s->I2Sx->DMA_CFG.DMACR_L_RX = 1;
hi2s->I2Sx->DMA_CFG.DMACR_R_RX = 1;
/* Rx empty dma level */
__I2S_RX_DMA_EMPTY_LEVEL(hi2s->I2Sx, 16);
}

View File

@ -0,0 +1,74 @@
/*
******************************************************************************
* @file driver_iir.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2023
* @brief IIR module driver.
* This file provides firmware functions to manage the
* IIR filter peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2023 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/******************************************************************************
* @fn iir_init
*
* @brief Initialize the IIR according to the specified parameters
* in the IIR_HandleTypeDef
*
* @param hiir : IIR Handle.
*/
void iir_init(IIR_InitTypeDef *hiir)
{
__IIR_SOFTRST_SET();
__IIR_SOFTRST_CLEAR();
for(int i = 0; i < 20; i++)
{
IIR_FILTER->IIR_COEF[i] = hiir->IIRCoef[i];
}
IIR_FILTER->IIR_CTRL.N_DIV = hiir->N_Div;
IIR_FILTER->IIR_CTRL.ORDER_SEL = hiir->Order_Sel;
IIR_FILTER->IIR_CTRL.NODE_SEL = hiir->Node_Sel;
IIR_FILTER->IIR_CTRL.NBYTE_SEL = hiir->Nbytes_Sel;
__IIR_RxFIFO_THRESHOLD_LEVEL(0x20);
__IIR_TxFIFO_THRESHOLD_LEVEL(0x20);
}
/******************************************************************************
* @fn iir_filter_start
*
* @brief Start iir filter
*
* @param fp_Data_In : the data need to handle
* fp_Data_Out : the output data
* fu32_Size : the size of data which is need to handle
*/
void iir_filter_start(uint32_t *fp_Data_In, uint32_t *fp_Data_Out, uint32_t fu32_Size)
{
while(fu32_Size)
{
if(!__IIR_GET_FIFO_STATUS(TX_FIFO_FULL))
{
IIR_FILTER->IIR_FIFO = *fp_Data_In++;
fu32_Size--;
}
while(!__IIR_GET_FIFO_STATUS(RX_FIFO_EMPTY))
{
*fp_Data_Out++ = IIR_FILTER->IIR_FIFO;
}
}
__IIR_SOFTRST_SET();
__IIR_SOFTRST_CLEAR();
}

View File

@ -0,0 +1,155 @@
/*
******************************************************************************
* @file driver_ipc.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief ipc module driver.
* This file provides firmware functions to manage the
* IPC peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/************************************************************************************
* @fn ipc_IRQHandler
*
* @brief Handle IPC interrupt request.
*
* @param hipc: IPC handle.
*/
void ipc_IRQHandler(IPC_HandleTypeDef *hipc)
{
uint32_t status;
volatile uint32_t msg;
status = hipc->IPCx->IPC_ISR_STA.Word;
if (status & IPC_INT_STATUS_CH0_IN) {
msg = hipc->IPCx->IPC_MSG_IN0;
if (hipc->RxCallback) {
hipc->RxCallback(hipc, IPC_CH_0, msg);
}
hipc->IPCx->IPC_ISR_STA.Word = IPC_INT_STATUS_CH0_IN;
hipc->IPCx->IPC_MSG_CLR.CH0_IN = 1;
}
if (status & IPC_INT_STATUS_CH1_IN) {
msg = hipc->IPCx->IPC_MSG_IN1;
if (hipc->RxCallback) {
hipc->RxCallback(hipc, IPC_CH_1, msg);
}
hipc->IPCx->IPC_ISR_STA.Word = IPC_INT_STATUS_CH1_IN;
hipc->IPCx->IPC_MSG_CLR.CH1_IN = 1;
}
if (status & IPC_INT_STATUS_CH2_IN) {
msg = hipc->IPCx->IPC_MSG_IN2;
if (hipc->RxCallback) {
hipc->RxCallback(hipc, IPC_CH_2, msg);
}
hipc->IPCx->IPC_ISR_STA.Word = IPC_INT_STATUS_CH2_IN;
hipc->IPCx->IPC_MSG_CLR.CH2_IN = 1;
}
if (status & IPC_INT_STATUS_CH3_IN) {
msg = hipc->IPCx->IPC_MSG_IN3;
if (hipc->RxCallback) {
hipc->RxCallback(hipc, IPC_CH_3, msg);
}
hipc->IPCx->IPC_ISR_STA.Word = IPC_INT_STATUS_CH3_IN;
hipc->IPCx->IPC_MSG_CLR.CH3_IN = 1;
}
status = hipc->IPCx->IPC_ISR_STA.Word;
if ((status & IPC_INT_STATUS_CH0_OUT)) {
hipc->IPCx->IPC_ISR_STA.Word = IPC_INT_STATUS_CH0_OUT;
if (hipc->TxCallback) {
hipc->TxCallback(hipc, IPC_CH_0);
}
}
if ((status & IPC_INT_STATUS_CH1_OUT)) {
hipc->IPCx->IPC_ISR_STA.Word = IPC_INT_STATUS_CH1_OUT;
if (hipc->TxCallback) {
hipc->TxCallback(hipc, IPC_CH_1);
}
}
if ((status & IPC_INT_STATUS_CH2_OUT)) {
hipc->IPCx->IPC_ISR_STA.Word = IPC_INT_STATUS_CH2_OUT;
if (hipc->TxCallback) {
hipc->TxCallback(hipc, IPC_CH_2);
}
}
if ((status & IPC_INT_STATUS_CH3_OUT)) {
hipc->IPCx->IPC_ISR_STA.Word = IPC_INT_STATUS_CH3_OUT;
if (hipc->TxCallback) {
hipc->TxCallback(hipc, IPC_CH_3);
}
}
}
void ipc_init(IPC_HandleTypeDef *hipc)
{
if (hipc->RxEnableChannels & IPC_CH_0) {
hipc->IPCx->IPC_CTRL.Bits.CH0_IN_EN = 1;
hipc->IPCx->IPC_ISR_EN.Bits.CH0_IN = 1;
}
if (hipc->RxEnableChannels & IPC_CH_1) {
hipc->IPCx->IPC_CTRL.Bits.CH1_IN_EN = 1;
hipc->IPCx->IPC_ISR_EN.Bits.CH1_IN = 1;
}
if (hipc->RxEnableChannels & IPC_CH_2) {
hipc->IPCx->IPC_CTRL.Bits.CH2_IN_EN = 1;
hipc->IPCx->IPC_ISR_EN.Bits.CH2_IN = 1;
}
if (hipc->RxEnableChannels & IPC_CH_3) {
hipc->IPCx->IPC_CTRL.Bits.CH3_IN_EN = 1;
hipc->IPCx->IPC_ISR_EN.Bits.CH3_IN = 1;
}
if (hipc->TxEnableChannels & IPC_CH_0) {
hipc->IPCx->IPC_CTRL.Bits.CH0_OUT_EN = 1;
hipc->IPCx->IPC_ISR_EN.Bits.CH0_OUT = 1;
}
if (hipc->TxEnableChannels & IPC_CH_1) {
hipc->IPCx->IPC_CTRL.Bits.CH1_OUT_EN = 1;
hipc->IPCx->IPC_ISR_EN.Bits.CH1_OUT = 1;
}
if (hipc->TxEnableChannels & IPC_CH_2) {
hipc->IPCx->IPC_CTRL.Bits.CH2_OUT_EN = 1;
hipc->IPCx->IPC_ISR_EN.Bits.CH2_OUT = 1;
}
if (hipc->TxEnableChannels & IPC_CH_3) {
hipc->IPCx->IPC_CTRL.Bits.CH3_OUT_EN = 1;
hipc->IPCx->IPC_ISR_EN.Bits.CH3_OUT = 1;
}
hipc->TxOngoingChannels = 0;
}
void ipc_msg_send(IPC_HandleTypeDef *hipc, enum_IPC_Chl_Sel_t ch, uint32_t msg)
{
switch (ch) {
case IPC_CH_0:
while (hipc->IPCx->IPC_PENDING.Bits.CH0_OUT);
hipc->IPCx->IPC_MSG_OUT0 = msg;
break;
case IPC_CH_1:
while (hipc->IPCx->IPC_PENDING.Bits.CH1_OUT);
hipc->IPCx->IPC_MSG_OUT1 = msg;
break;
case IPC_CH_2:
while (hipc->IPCx->IPC_PENDING.Bits.CH2_OUT);
hipc->IPCx->IPC_MSG_OUT2 = msg;
break;
case IPC_CH_3:
while (hipc->IPCx->IPC_PENDING.Bits.CH3_OUT);
hipc->IPCx->IPC_MSG_OUT3 = msg;
break;
default:
return;
}
hipc->TxOngoingChannels |= ch;
}

View File

@ -0,0 +1,204 @@
/*
******************************************************************************
* @file driver_mp3_dec.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief MP3 decoder module driver.
* This file provides firmware functions to manage the
* MP3 DECODEER peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/******************************************************************************
* @fn mp3_decoder_init
*
* @brief Initialize the mp3 decoder according to the specified parameters
* in the MP3_DEC_HandleTypeDef
*
* @param hmp3dec : MP3_DEC_HandleTypeDef structure that contains the
* configuration information for MP3DEC module.
* pcm_buff : mp3 decoder paddr
* pcm_buf_size : pcm buffer size
*/
void mp3_dec_init(MP3_DEC_HandleTypeDef *hmp3dec, uint32_t *pcm_buff, uint32_t pcm_buf_size)
{
__MP3D_SOFTRST();//softreset
__MP3D_PCM_FIFO_RESET();
__MP3D_ISSUE_NEW_FILE();
MP3D->MP3D_CTRL.Bits.DAI_EN = hmp3dec->mp3dec_ctrl_Init.Bits.DAI_EN;
__MP3D_OPERA_ENABLE();
MP3D->MP3D_CTRL.Bits.ISR_EN = hmp3dec->mp3dec_ctrl_Init.Bits.ISR_EN;
MP3D->MP3D_PADDR = (uint32_t)pcm_buff;
MP3D->MP3D_PSIZE.Word = pcm_buf_size;
memset(pcm_buff,0,pcm_buf_size);
}
/******************************************************************************
* @fn mp3_decoder_start
*
* @brief Start the mp3 decoder
*
* @param src_buff : src data pointer
* src_size : src data size
*/
static void mp3_dec_start(uint8_t *src_buff, uint32_t src_size)
{
MP3D->MP3D_SADDR = (uint32_t)src_buff;
MP3D->MP3D_SSIZE.Word = src_size;
MP3D->MP3D_INTSTA.Bits.SOURCE_CMPLETION_ISR = 1;
MP3D->MP3D_CTRL.Bits.OPERA_START = 1;
}
/******************************************************************************
* @fn mp3_decoder_stop
*
* @brief Stop the mp3 decoder
*
* @param void
*/
static void mp3d_stop(void)
{
__MP3D_PCM_FIFO_RESET();
__MP3D_ISSUE_NEW_FILE();
}
/******************************************************************************
* @fn mp3_clear_isr
*
* @brief Clear the mp3 decoder isr flag
*
* @param isr : enum_mp3d_isr_t contains info
*/
static void mp3d_clear_isr(enum_mp3d_isr_t isr)
{
MP3D->MP3D_INTSTA.Word = (1 << isr);
}
/******************************************************************************
* @fn mp3_dec_playdata
*
* @brief Mp3 decoder play data
*
* @param hmp3dec : mp3 decoder handler
* fp_Data : the data which is needed to decoder
* fu32_Size : the decoded data's size
*/
void mp3_dec_playdata(MP3_DEC_HandleTypeDef *hmp3dec, uint8_t *fp_Data, uint32_t fu32_Size)
{
uint32_t length = 0;
uint32_t CurrentIndex = 0;
uint32_t DataSize = fu32_Size;
while(DataSize != 0)
{
length = fu32_Size > 512 ? 512 : fu32_Size;
mp3_dec_start((uint8_t *)&fp_Data[CurrentIndex], length);
DataSize -= length;
while(1)
{
if(__MP3D_CHECK_NEED_SEC())
{
mp3d_clear_isr(SOURCE_COMPLETE_ISR);
CurrentIndex += length;
break;
}
}
}
mp3d_stop();
}
/******************************************************************************
* @fn mp3_dec_playdata_IT
*
* @brief Mp3 decoder play data with isr
*
* @param hmp3dec : mp3 decoder handler
* fp_Data : the data which is needed to decoder
* fu32_Size : the decoded data's size
*/
void mp3_dec_playdata_IT(MP3_DEC_HandleTypeDef *hmp3dec, uint8_t *fp_Data, uint32_t fu32_Size)
{
__MP3D_COMPLETE_ISR_ENABLE();
hmp3dec->MP3Enced_Data = fp_Data;
hmp3dec->MP3Enced_Index = 0;
hmp3dec->LeftLen = fu32_Size;
hmp3dec->FrameLen = hmp3dec->LeftLen > 512 ? 512 : hmp3dec->LeftLen;
mp3_dec_start((uint8_t *)&hmp3dec->MP3Enced_Data[hmp3dec->MP3Enced_Index], hmp3dec->FrameLen);
hmp3dec->MP3Enced_Index += hmp3dec->FrameLen;
hmp3dec->LeftLen -= hmp3dec->FrameLen;
}
/******************************************************************************
* @fn mp3d_get_stream_info
*
* @brief Mp3 decoder get the decoded frame info
*
* @param info : struct_MP3D_stream_info_t structure contains
*/
void mp3d_get_stream_info(struct_MP3D_stream_info_t *info)
{
info->audio_ver = MP3D->MP3D_INFO.Bits.MP3_STREAM_AUDIO_VER;
info->audio_emphasis = MP3D->MP3D_INFO.Bits.MP3_STREAM_AUDIO_EMPHASIS;
info->audio_mode = MP3D->MP3D_INFO.Bits.MP3_STREAM_AUDIO_MODE;
info->bit_rate = MP3D->MP3D_INFO.Bits.MP3_STREAM_BIT_RATE;
info->copyright = MP3D->MP3D_INFO.Bits.MP3_STREAM_COPYRIGHT;
info->error_protection = MP3D->MP3D_INFO.Bits.MP3_STREAM_ERROR_PROTECT;
info->frame_locked = MP3D->MP3D_INFO.Bits.MP3_FRAME_LOCKED;
info->main_done = MP3D->MP3D_INFO.Bits.MP3_MAIN_DONE;
info->main_exhaust = MP3D->MP3D_INFO.Bits.MP3_MAIN_EXHAUST;
info->mode_extension = MP3D->MP3D_INFO.Bits.MP3_STREAM_AUDIO_MODE_EXTEN;
info->original = MP3D->MP3D_INFO.Bits.MP3_STREAM_ORIGINAL;
info->sample_rate = MP3D->MP3D_INFO.Bits.MP3_STREAM_SAMPLE_RATE;
}
/******************************************************************************
* @fn mp3d_check_dec_failed
*
* @brief check whether the mp3dec is failed or successful
*
* @param void
*/
int mp3d_check_dec_failed(void)
{
if((MP3D->MP3D_INTSTA.Bits.MP3_FRAME_LOCKED_ISR == 1) ||
(MP3D->MP3D_INFO.Bits.MP3_FRAME_LOCKED == 0))
{
MP3D->MP3D_INTSTA.Word = (1 << MP3_FRAME_LOCKED_ISR);
return 1;
}
return 0;
}
/******************************************************************************
* @fn mp3dec_IRQHandler
*
* @brief mp3 decoder handle function in mo3 dec isr
*
* @param hmp3dec : MP3 decoder handle
*/
void mp3dec_IRQHandler(MP3_DEC_HandleTypeDef *hmp3dec)
{
if(__MP3D_SRC_COMPLETE_ISR_IS_SET())
{
if(hmp3dec->LeftLen != 0)
{
hmp3dec->FrameLen = hmp3dec->LeftLen > 512 ? 512 : hmp3dec->LeftLen;
mp3_dec_start((uint8_t *)&hmp3dec->MP3Enced_Data[hmp3dec->MP3Enced_Index], hmp3dec->FrameLen);
hmp3dec->MP3Enced_Index += hmp3dec->FrameLen;
hmp3dec->LeftLen -= hmp3dec->FrameLen;
}
else
{
__MP3D_COMPLETE_ISR_DISABLE();
mp3d_stop();
}
}
}

View File

@ -0,0 +1,202 @@
/*
******************************************************************************
* @file driver_parallel_interface.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief parallel module driver.
* This file provides firmware functions to manage the
* parallel interface 8080/6800 peripheral.
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/*********************************************************************
* @fn parallel_init
*
* @brief Initialize the parallel_nterface according to the specified parameters
* in the str_ParallelParam_t
*
* @param ParalleInit : pointer to a str_ParallelParam_t structure that contains
* the configuration information for LCD module
*
* @return None.
*/
void parallel_init(PARALLEL_HandTypeDef *hparallel)
{
/* FIFO_RST */
__PARALLEL_TX_FIFO_RESET(hparallel->PARALLELx);
/* DMA Config */
hparallel->PARALLELx->DMA.DMA_TX_LEVEL = 16;
hparallel->PARALLELx->DMA.DMA_ENABLE = 1;
/* select 8080 or 6800 */
hparallel->PARALLELx->INTF_CFG.MODE = hparallel->Init.ParallelMode;
/* select 8bit or 16bit */
hparallel->PARALLELx->INTF_CFG.PARA_WIDTH = hparallel->Init.DataBusSelect;
/* Write Clock DIV */
hparallel->PARALLELx->CRM.WRITE_CLK_CFG = hparallel->Init.WriteClock;
/* Read Clock DIV */
hparallel->PARALLELx->CRM.READ_CLK_CFG = hparallel->Init.ReadClock;
/* FIFO_RELEASE */
__PARALLEL_TX_FIFO_RELEASE(hparallel->PARALLELx);
}
/*********************************************************************
* @fn Parallel_write_cmd
*
* @brief Sending command
*
* @param fp8_CMD : command data
*
* @return None.
*/
void Parallel_write_cmd(PARALLEL_HandTypeDef *hparallel, uint8_t fp8_CMD)
{
/* Write, CMD */
__PARALLEL_WR_CMD(hparallel->PARALLELx, fp8_CMD);
/* wait bus idle */
while(__PARALLEL_IS_BUS_BUSY(hparallel->PARALLELx));
}
/*********************************************************************
* @fn Parallel_write_param
*
* @brief Sending parameter.
*
* @param fu16_Data : parameter. Can be 8 bit or 16 bit, depend on BUS bit.
*
* @return None.
*/
void Parallel_write_param(PARALLEL_HandTypeDef *hparallel, uint16_t fu16_Data)
{
/* Write, param */
__PARALLEL_WR_PARAM(hparallel->PARALLELx, fu16_Data);
/* wait bus idle */
while(__PARALLEL_IS_BUS_BUSY(hparallel->PARALLELx));
}
/*********************************************************************
* @fn Parallel_write_data
*
* @brief Sending data or parameters
*
* @param fp32_WriteBuffer : Write data buffer
* fu32_WriteNum : transmit number.
* 1. select DATA_BUS_8_BIT, 1 count sent 1 byte
* 2. select DATA_BUS_16_BIT, 1 count sent 2 byte
* @return None.
*/
void Parallel_write_data(PARALLEL_HandTypeDef *hparallel, uint32_t *fp32_WriteBuffer, uint32_t fu32_WriteNum)
{
uint32_t i;
uint32_t lu32_Num;
hparallel->PARALLELx->DATA_WR_LEN = fu32_WriteNum;
/* 8 bit bus */
if (hparallel->PARALLELx->INTF_CFG.PARA_WIDTH == DATA_BUS_8_BIT)
{
lu32_Num = fu32_WriteNum / 4;
if (fu32_WriteNum % 4)
{
lu32_Num++;
}
}
/* 16 bit bus */
else
{
lu32_Num = fu32_WriteNum / 2;
if (fu32_WriteNum % 2)
{
lu32_Num++;
}
}
while(lu32_Num >= PARALLEL_FIFO_DEPTH)
{
uint32_t u32_l = PARALLEL_FIFO_DEPTH;
while(u32_l--)
{
hparallel->PARALLELx->TX_FIFO = *fp32_WriteBuffer++;
}
lu32_Num -= PARALLEL_FIFO_DEPTH;
while(!(__PARALLEL_INT_STATUS(hparallel->PARALLELx)&INT_TXFIFO_EMPTY));
}
while(lu32_Num--)
{
hparallel->PARALLELx->TX_FIFO = *fp32_WriteBuffer++;
}
/* wait bus idle */
while(__PARALLEL_IS_BUS_BUSY(hparallel->PARALLELx));
}
/*********************************************************************
* @fn Parallel_read_data_8bit
*
* @brief read data. select DATA_BUS_8_BIT, 1 count receive 1 byte.
*
* @param fu8_Param : read Param
* fp8_ReadBuffer : read data buffer.
* fu32_ReadNum : receive number.
*
* @return None.
*/
void Parallel_read_data_8bit(PARALLEL_HandTypeDef *hparallel, uint8_t fu8_Param, uint8_t *fp8_ReadBuffer, uint32_t fu32_ReadNum)
{
uint32_t i;
__PARALLEL_WR_PARAM(hparallel->PARALLELx, fu8_Param);
/* wait bus idle */
while(__PARALLEL_IS_BUS_BUSY(hparallel->PARALLELx));
for (i = 0; i < fu32_ReadNum; i++)
{
/* Read REQ*/
__PARALLEL_RD_REQ(hparallel->PARALLELx);
/* wait bus idle */
while(__PARALLEL_IS_BUS_BUSY(hparallel->PARALLELx));
fp8_ReadBuffer[i] = hparallel->PARALLELx->DAT_RD;
}
}
/*********************************************************************
* @fn Parallel_read_data_16bit
*
* @brief read data. select DATA_BUS_16_BIT, 1 count receive 2 byte.
*
* @param fu8_Param : read Param
fp16_ReadBuffer : read data buffer.
* fu32_ReadNum : receive number.
*
* @return None.
*/
void Parallel_read_data_16bit(PARALLEL_HandTypeDef *hparallel, uint8_t fu8_Param, uint16_t *fp16_ReadBuffer, uint32_t fu32_ReadNum)
{
uint32_t i;
__PARALLEL_WR_PARAM(hparallel->PARALLELx, fu8_Param);
/* wait bus idle */
while(__PARALLEL_IS_BUS_BUSY(hparallel->PARALLELx));
for (i = 0; i < fu32_ReadNum; i++)
{
/* Read REQ*/
__PARALLEL_RD_REQ(hparallel->PARALLELx);
/* wait bus idle */
while(__PARALLEL_IS_BUS_BUSY(hparallel->PARALLELx));
fp16_ReadBuffer[i] = hparallel->PARALLELx->DAT_RD;
}
}

View File

@ -0,0 +1,176 @@
/*
******************************************************************************
* @file driver_pdm.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2023
* @brief pdm module driver.
* This file provides firmware functions to manage the
* pulse-duration modulation (PDM) peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2023 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/************************************************************************************
* @fn pdm_IRQHandler
*
* @brief Handle PDM interrupt request.
*
* @param hpdm: PDM handle.
*/
__WEAK void pdm_IRQHandler(PDM_HandleTypeDef *hpdm)
{
if (__PDM_IS_FIFO_ALMOST_FULL(hpdm->PDMx))
{
if (hpdm->p_RxData) {
pdm_read_data(hpdm, hpdm->p_RxData);
}
if (hpdm->RxCallback) {
hpdm->RxCallback(hpdm);
}
}
}
/************************************************************************************
* @fn pdm_init
*
* @brief Initialize the PDM according to the specified parameters in the struct_PDMInit_t
*
* @param hpdm: PDM handle.
*/
void pdm_init(PDM_HandleTypeDef *hpdm)
{
/* Clock default use 24M */
hpdm->PDMx->Config.USB_MODE = 1;
/* Sample Rate */
hpdm->PDMx->Config.SAMPLE_RATE = hpdm->Init.SampleRate;
/* Over Samplek Mode */
hpdm->PDMx->Config.OSR_MODE = hpdm->Init.OverSampleMode;
/* channel config */
if (hpdm->Init.ChannelMode == PDM_STEREO) {
hpdm->PDMx->Config.MONO = 0;
hpdm->PDMx->Config.CH_SEL = 0;
}
else{
hpdm->PDMx->Config.MONO = 1;
hpdm->PDMx->Config.CH_SEL = hpdm->Init.ChannelMode;
}
/* fifo almost Full Threshold */
hpdm->PDMx->FF_AFLL_LVL = hpdm->Init.FIFO_FullThreshold;
pdm_vol_set(hpdm, hpdm->Init.Volume);
hpdm->PDMx->Config.RST = 1;
hpdm->PDMx->Config.RST = 0;
hpdm->PDMx->FF_RST.rst = 0x07;
hpdm->PDMx->FF_RST.rst = 0x00;
}
/************************************************************************************
* @fn pdm_start_IT
*
* @brief PDM read start in interrupt mode.
*
* @param hpdm: PDM handle.
* @param fp_Data: buffer used to store received data, If fp_Data is NULL, application layer
* should take charge of reading data from fifo.
*/
void pdm_start_IT(PDM_HandleTypeDef *hpdm, void *fp_Data)
{
if (hpdm->b_RxBusy)
return;
__PDM_CLK_ENABLE(hpdm->PDMx);
__PDM_ENABLE(hpdm->PDMx);
__PDM_FIFO_ALMOST_FULL_INT_ENABLE(hpdm->PDMx);
hpdm->b_RxBusy = true;
hpdm->p_RxData = fp_Data;
}
/************************************************************************************
* @fn pdm_init
*
* @brief Initialize the PDM according to the specified parameters in the struct_PDMInit_t
*
* @param hpdm: PDM handle.
* @param vol: target volume, unit is dB
*/
void pdm_vol_set(PDM_HandleTypeDef *hpdm, int8_t vol)
{
uint32_t vol_cfg;
if(vol <= 18) {
vol_cfg = PDM_VOL_dB(vol);
hpdm->Init.Volume = vol;
}
else {
return;
}
hpdm->PDMx->VOL_L = vol_cfg;
hpdm->PDMx->VOL_R = vol_cfg;
}
/************************************************************************************
* @fn pdm_read_data
*
* @brief read data from PDM fifo, read size is FIFO_FullThreshold
*
* @param hpdm: PDM handle.
* @param pcm: buffer used to store received data.
*/
void pdm_read_data(PDM_HandleTypeDef *hpdm, void *fp_Data)
{
uint8_t thd = hpdm->Init.FIFO_FullThreshold;
if (hpdm->Init.ChannelMode == PDM_STEREO)
{
uint32_t *p_u32 = (void *)fp_Data;
while (thd--) {
*p_u32++ = hpdm->PDMx->DATA;
}
}
else
{
uint16_t *p_u16 = (void *)fp_Data;
while (thd--) {
*p_u16++ = hpdm->PDMx->DATA;
}
}
}
/************************************************************************************
* @fn pdm_start
*
* @brief PDM sampling start.
*
* @param hpdm: PDM handle.
*/
void pdm_start(PDM_HandleTypeDef *hpdm)
{
__PDM_CLK_ENABLE(hpdm->PDMx);
__PDM_ENABLE(hpdm->PDMx);
}
/************************************************************************************
* @fn pdm_stop
*
* @brief PDM sampling stop.
*
* @param hpdm: PDM handle.
*/
void pdm_stop(PDM_HandleTypeDef *hpdm)
{
__PDM_DISABLE(hpdm->PDMx);
__PDM_CLK_DISABLE(hpdm->PDMx);
hpdm->b_RxBusy = false;
}

View File

@ -0,0 +1,591 @@
#include "fr30xx.h"
#define PMU_FSM_ON_DIV 0x04 //the follow tcnt based <((DIV+1))*40K_CLK(rc)>
#define PMU_PMU_ON_CNT (0x18<<0)
//the follow tcnt should <= PMU_PMU_ON_CNT
#define PMU_BBG_ON_CNT (0x01<<0)
#define PMU_SYSBUCK_ON_CNT (0x03<<0)
#define PMU_IOBUCK_ON_CNT (0x03<<0)
#define PMU_IOLDO1_ON_CNT (0x03<<0)
#define PMU_IOLDO2_ON_CNT (0x03<<0)
#define PMU_APPDLDO_ON_CNT (0x06<<0)
#define PMU_DSPDLDO_ON_CNT (0x06<<0)
#define PMU_PKSTPD_ON_CNT (0x0c<<0)
#define PMU_MEMPK_ON_CNT (0x10<<0)
#define PMU_MEMPD_ON_CNT (0x10<<0)
#define PMU_OSCLDO_ON_CNT (0x06<<0)
#define PMU_OSC_ON_CNT (0x08<<0)
#define PMU_RC24PD_ON_CNT (0x10<<0)
#define PMU_RAMPK_ON_CNT (0x18<<0)
#define PMU_PMUISO_ON_CNT (0x17<<0)
#define PMU_IOISO_ON_CNT (0x17<<0)
#define PMU_IORTON_ON_CNT (0x17<<0)
#define PMU_IOSNS_ON_CNT (0x17<<0)
#define PMU_RSTN_ON_CNT (0x18<<0)
#define PMU_FSM_OFF_DIV (0x00<<5) //the follow tcnt based <((DIV+1))*40K_CLK(rc)>
#define PMU_PMU_OFF_CNT (0x06<<5)
//the follow tcnt should <= PMU_PMU_OFF_CNT
#define PMU_BBG_OFF_CNT (0x05<<5)
#define PMU_SYSBUCK_OFF_CNT (0x04<<5)
#define PMU_IOBUCK_OFF_CNT (0x01<<5)
#define PMU_IOLDO1_OFF_CNT (0x01<<5)
#define PMU_IOLDO2_OFF_CNT (0x01<<5)
#define PMU_APPDLDO_OFF_CNT (0x03<<5)
#define PMU_DSPDLDO_OFF_CNT (0x03<<5)
#define PMU_PKSTPD_OFF_CNT (0x01<<5)
#define PMU_MEMPK_OFF_CNT (0x01<<5)
#define PMU_MEMPD_OFF_CNT (0x03<<5)
#define PMU_OSCLDO_OFF_CNT (0x03<<5)
#define PMU_OSC_OFF_CNT (0x01<<5)
#define PMU_RC24PD_OFF_CNT (0x03<<5)
#define PMU_RAMPK_OFF_CNT (0x01<<5)
#define PMU_PMUISO_OFF_CNT (0x01<<5)
#define PMU_IOISO_OFF_CNT (0x02<<5)
#define PMU_IORTON_OFF_CNT (0x02<<5)
#define PMU_IOSNS_OFF_CNT (0x02<<5)
#define PMU_RSTN_OFF_CNT (0x01<<5)
void pmu_init(void)
{
/* setup sleep and wakeup counters */
ool_write(PMU_REG_FSM_TIMER , PMU_FSM_ON_DIV | PMU_FSM_OFF_DIV );
ool_write(PMU_REG_PMU_ONOFF_CNT , PMU_PMU_ON_CNT | PMU_PMU_OFF_CNT );
ool_write(PMU_REG_BBG_ONOFF_CNT , PMU_BBG_ON_CNT | PMU_BBG_OFF_CNT );
ool_write(PMU_REG_SYSBUCK_ONOFF_CNT , PMU_SYSBUCK_ON_CNT | PMU_SYSBUCK_OFF_CNT);
ool_write(PMU_REG_IOBUCK_ONOFF_CNT , PMU_IOBUCK_ON_CNT | PMU_IOBUCK_OFF_CNT );
ool_write(PMU_REG_IOLDO1_ONOFF_CNT , PMU_IOLDO1_ON_CNT | PMU_IOLDO1_OFF_CNT );
ool_write(PMU_REG_IOLDO2_ONOFF_CNT , PMU_IOLDO2_ON_CNT | PMU_IOLDO2_OFF_CNT );
ool_write(PMU_REG_APPDLDO_ONOFF_CNT , PMU_APPDLDO_ON_CNT | PMU_APPDLDO_OFF_CNT);
ool_write(PMU_REG_DSPDLDO_ONOFF_CNT , PMU_DSPDLDO_ON_CNT | PMU_DSPDLDO_OFF_CNT);
ool_write(PMU_REG_PKSTPD_ONOFF_CNT , PMU_PKSTPD_ON_CNT | PMU_PKSTPD_OFF_CNT );
ool_write(PMU_REG_MEMPK_ONOFF_CNT , PMU_MEMPK_ON_CNT | PMU_MEMPK_OFF_CNT );
ool_write(PMU_REG_MEMPD_ONOFF_CNT , PMU_MEMPD_ON_CNT | PMU_MEMPD_OFF_CNT );
ool_write(PMU_REG_OSCLDO_ONOFF_CNT , PMU_OSCLDO_ON_CNT | PMU_OSCLDO_OFF_CNT );
ool_write(PMU_REG_OSC_ONOFF_CNT , PMU_OSC_ON_CNT | PMU_OSC_OFF_CNT );
ool_write(PMU_REG_RC24PD_ONOFF_CNT , PMU_RC24PD_ON_CNT | PMU_RC24PD_OFF_CNT );
ool_write(PMU_REG_RAMPK_ONOFF_CNT , PMU_RAMPK_ON_CNT | PMU_RAMPK_OFF_CNT );
ool_write(PMU_REG_PMUISO_ONOFF_CNT , PMU_PMUISO_ON_CNT | PMU_PMUISO_OFF_CNT );
ool_write(PMU_REG_IOISO_ONOFF_CNT , PMU_IOISO_ON_CNT | PMU_IOISO_OFF_CNT );
ool_write(PMU_REG_IORTON_ONOFF_CNT , PMU_IORTON_ON_CNT | PMU_IORTON_OFF_CNT );
ool_write(PMU_REG_IOSNS_ONOFF_CNT , PMU_IOSNS_ON_CNT | PMU_IOSNS_OFF_CNT );
ool_write(PMU_REG_RSTN_ONOFF_CNT , PMU_RSTN_ON_CNT | PMU_RSTN_OFF_CNT );
/* splite PKVDDH and PKVDD */
ool_write(PMU_REG_PKVDDH_CTRL_0, 0x60);
ool_write(PMU_REG_PKVDDH_CTRL_0, 0x70);
/* shut down OSC buffer */
ool_write(PMU_REG_OSC_CTRL_1, ool_read(PMU_REG_OSC_CTRL_1) & (~0x04));
/* PLL analog clock enable */
ool_write(PMU_REG_OSC_CTRL_1, ool_read(PMU_REG_OSC_CTRL_1)|0x0B);
/* set PKVDD to 0.85v */
ool_write(PMU_REG_PKVDD_CTRL, 0x7a);
/* set PKVDDH to 1.1v, set RAMPKVDD to 0.7v */
ool_write(PMU_REG_PKVDDH_CTRL_1, 0x34);
/* buck load inductor will not be shorted */
ool_write(PMU_REG_SYSBUCK_CTRL_1, 0x43);
/* disable internal load of sys-buck and io-buck */
ool_write(PMU_REG_IOBUCK_CTRL_4, 0x73);
ool_write(PMU_REG_SYSBUCK_CTRL_4, 0x73);
/*
* IOLDO dynamic bias, used to avoid unexpect leakage when IOLDO
* output configuration is large than VBAT input voltage
*/
ool_write(PMU_REG_IOLDO1_CTRL_1, ool_read(PMU_REG_IOLDO1_CTRL_1) | (1<<4));
ool_write(PMU_REG_IOLDO2_CTRL_1, ool_read(PMU_REG_IOLDO2_CTRL_1) | (1<<4));
/* enable BT sleep timer clock */
ool_write(PMU_REG_CLK_EN, PMU_LP_TICK_CLK_EN_BIT);
#if 0
/* sleep and wake up is controlled by TICK */
ool_write(PMU_REG_SLP_WK_SRC, PMU_SLP_TICK_EN_BIT | PMU_WK_TICK_EN_BIT);
/*
* BIT0: BB generate sleep signal en
* BIT1: external interrupt wakeup BT timer enable
*/
ool_write(PMU_REG_TICK_CTRL, PMU_TICK_SLP_PMU_EN_BIT | PMU_EXT_WK_TICK_EN_BIT | PMU_IRQ_WK_TICK_EN_BIT);
/* reset lp tick */
ool_write(PMU_REG_RST, PMU_LP_TICK_SFT_RST_BIT);
while (ool_read(PMU_REG_RST) & PMU_LP_TICK_SFT_RST_BIT);
#else
/* sleep and wake up is controlled by TICK */
ool_write(PMU_REG_SLP_WK_SRC, PMU_SLP_CPU_EN_BIT | PMU_WK_IRQ_EN_BIT);
/* release RTC clock */
ool_write(PMU_REG_CLK_EN, ool_read(PMU_REG_CLK_EN) | PMU_RTC_CLK_EN_BIT);
/* release interrupt mask of RTC alarm B */
ool_write16(PMU_REG_INT_MASK, ool_read16(PMU_REG_INT_MASK) | PMU_RTC_B_INT_MSK_BIT);
#endif
/* disable power fsm */
ool_write(0x85, 0xff);
/* IO33 and IO18 always on */
ool_write(0x63, 0x18);
/* set mask of GPIO SNS & ISO */
ool_write(0x64, ool_read(0x64) | 0x80 | 0x20); //bit7 : GPIO_SNS; bit5 : GPIO_ISO
// /* configure PMU_PIN_8 output BBG_EN signal */
// ool_write(PMU_REG_DIAG_CTRL, 0x82);
//// ool_write16(PMU_REG_PIN_IOMUX_L, 0xffff);
// ool_write(PMU_REG_PIN_IOMUX_H, 0x03);
// /* disable input as default setting */
// ool_write16(PMU_REG_PIN_INPUT_EN, 0x0000);
/* remove internal cap of osc */
ool_write(PMU_REG_OSC_CTRL_4, 0x20);
}
/******************************************************************************
* @fn pmu_adc_power_ctrl
*
* @brief ADC power control. true: enable.
* false: disable.
*/
void pmu_adc_power_ctrl(bool enable)
{
if (enable)
ool_write(PMU_REG_ADC_CTL, ool_read(PMU_REG_ADC_CTL) | PMU_ADC_CTL_POWER_BIT);
else
ool_write(PMU_REG_ADC_CTL, ool_read(PMU_REG_ADC_CTL) & ~PMU_ADC_CTL_POWER_BIT);
}
/******************************************************************************
* @fn pmu_vbe_power_ctrl
*
* @brief VBE(For temperature detection) power control. true: enable.
* false: disable.
*/
void pmu_vbe_power_ctrl(bool enable)
{
if (enable)
ool_write(PMU_REG_BBG_CTL, ool_read(PMU_REG_BBG_CTL) | PMU_BBG_CTL_VBE_EN_BIT);
else
ool_write(PMU_REG_BBG_CTL, ool_read(PMU_REG_BBG_CTL) & ~PMU_BBG_CTL_VBE_EN_BIT);
}
/******************************************************************************
* @fn pmu_auldo_power_ctrl
*
* @brief audio ldo power control. true: enable.
* false: disable.
*/
void pmu_auldo_power_ctrl(bool enable)
{
if (enable)
ool_write(PMU_REG_AULDO_CTL, ool_read(PMU_REG_AULDO_CTL) & ~PMU_AULDO_CTL_PD_BIT);
else
ool_write(PMU_REG_AULDO_CTL, ool_read(PMU_REG_AULDO_CTL) | PMU_AULDO_CTL_PD_BIT);
}
/*********************************************************************
* @fn pmu_enable_charge
*
* @brief enable charge function, and set charge current & voltage.
*
* @param cur - charge current, @ref enum_PMU_charge_current_t
* @param vol - charge terminal voltage, @ref enum_PMU_charge_end_vol_t
*
* @return None.
*/
void pmu_charge_enable(enum_PMU_charge_current_t cur, enum_PMU_charge_end_vol_t vol)
{
/* charge reference select BBG */
ool_write(PMU_REG_CHG_CFG_CD, ool_read(PMU_REG_CHG_CFG_CD) | PMU_CHG_CFG_REF_SEL_BIT);
/* config charge voltage */
ool_write(PMU_REG_CHG_CFG_CB, (ool_read(PMU_REG_CHG_CFG_CB)&0x8F) | (vol << PMU_CHG_CFG_END_VOL_POS));
/* config charge current */
ool_write(PMU_REG_CHG_CFG_C8, (ool_read(PMU_REG_CHG_CFG_C8)&0xC0) | (cur));
/* enable charge */
ool_write(PMU_REG_CHG_CFG_CD, ool_read(PMU_REG_CHG_CFG_CD) | PMU_CHG_CFG_ENABLE_BIT);
}
/*********************************************************************
* @fn pmu_charge_disable
*
* @brief disable charge function.
*/
void pmu_charge_disable(void)
{
/* disable charge */
ool_write(PMU_REG_CHG_CFG_CD, ool_read(PMU_REG_CHG_CFG_CD) & ~PMU_CHG_CFG_ENABLE_BIT);
}
/*********************************************************************
* @fn pmu_charge_monitor_en
*
* @brief Charging in/out monitor interrupt enable.
*/
void pmu_charge_monitor_en(enum_PMU_charge_type_t charge_type)
{
if (charge_type == PMU_CHARGING_IN)
ool_write(PMU_REG_ANA_LEVEL, ool_read(PMU_REG_ANA_LEVEL) & ~PMU_CHG_ACOK_LEVEL_BIT);
else
ool_write(PMU_REG_ANA_LEVEL, ool_read(PMU_REG_ANA_LEVEL) | PMU_CHG_ACOK_LEVEL_BIT);
ool_write(PMU_REG_CLK_EN, ool_read(PMU_REG_CLK_EN) | PMU_FILTER_CLK_EN_BIT);
ool_write(PMU_REG_CHG_ACOK_FILTER, 100);
ool_write(PMU_REG_ANA_INT_EN, ool_read(PMU_REG_ANA_INT_EN) | PMU_CHG_ACOK_INT_EN_BIT);
pmu_enable_isr(PMU_CHG_ACOK_INT_MASK_BIT);
}
/*********************************************************************
* @fn pmu_battery_full_monitor_en
*
* @brief battery_full monitor interrupt enable
*/
void pmu_battery_full_monitor_en(enum_PMU_battery_type_t battery_type)
{
if (battery_type == PMU_BATTERY_FULL)
ool_write(PMU_REG_ANA_LEVEL, ool_read(PMU_REG_ANA_LEVEL) & ~PMU_BATFULL_LEVEL_BIT);
else
ool_write(PMU_REG_ANA_LEVEL, ool_read(PMU_REG_ANA_LEVEL) | PMU_BATFULL_LEVEL_BIT);
ool_write(PMU_REG_CLK_EN, ool_read(PMU_REG_CLK_EN) | PMU_FILTER_CLK_EN_BIT);
ool_write(PMU_REG_BAT_FULL_FILTER, 200);
ool_write(PMU_REG_ANA_INT_EN, ool_read(PMU_REG_ANA_INT_EN) | PMU_BATFULL_INT_EN_BIT);
pmu_enable_isr(PMU_BATFULL_INT_MASK_BIT);
}
void pmu_set_pin_pull(enum_PMU_PINx_t bits, enum_PMU_GPIO_PULL_t type)
{
uint8_t en_reg = PMU_REG_PIN_PULL_EN;
uint8_t pull_reg = PMU_REG_PIN_PULL_SEL;
if(type == PMU_GPIO_NO_PULL) {
ool_write16(en_reg, (ool_read16(en_reg) & (~bits)));
}
else {
if(type == PMU_GPIO_PULL_UP) {
ool_write16(pull_reg, (ool_read16(pull_reg) | bits));
}
else if(type == PMU_GPIO_PULL_DOWN) {
ool_write16(pull_reg, (ool_read16(pull_reg) & (~bits)));
}
else {
return;
}
ool_write16(en_reg, (ool_read16(en_reg) | bits));
}
}
void pmu_set_pin_dir(enum_PMU_PINx_t bits, enum_PMU_GPIO_MODE_t dir)
{
uint8_t oe_reg = PMU_REG_PIN_OUTPUT_EN;
uint8_t ie_reg = PMU_REG_PIN_INPUT_EN;
if(dir == PMU_GPIO_MODE_INPUT) {
ool_write16(oe_reg, ool_read16(oe_reg) | bits);
ool_write16(ie_reg, ool_read16(ie_reg) | (bits << 2));
}
else {
ool_write16(oe_reg, ool_read16(oe_reg) & (~bits));
ool_write16(ie_reg, ool_read16(ie_reg) & (~bits << 2));
}
}
void pmu_set_pin_value(enum_PMU_PINx_t bits, uint8_t value)
{
uint8_t data_reg = PMU_REG_PIN_DATA;
if (value == 0)
ool_write16(data_reg, (ool_read16(data_reg) & (~bits)));
else
ool_write16(data_reg, (ool_read16(data_reg) | bits));
}
uint8_t pmu_get_pin_value(enum_PMU_PINx_t bit)
{
uint8_t data_reg = PMU_REG_PIN_DATA;
return ( (ool_read16(data_reg) & (1<<bit))>>bit );
}
void pmu_set_pin_xor_en(enum_PMU_PINx_t bits, bool en)
{
uint8_t xor_reg = PMU_REG_PIN_XOR_EN;
if(en) {
ool_write16(xor_reg, ool_read16(xor_reg) | (bits));
}
else {
ool_write16(xor_reg, ool_read16(xor_reg) & (~bits));
}
}
/*********************************************************************
* @fn pmu_port_wakeup_func_set
*
* @brief PortPin wakeup function congfig
*
* @param bits: Select Pin. 0x01--PIN0 0x80--PIN7
*/
void pmu_port_wakeup_func_set(enum_PMU_PINx_t bits)
{
uint8_t last_status_reg = PMU_REG_PIN_LAST_V;
uint8_t data_reg = PMU_REG_PIN_DATA;
/* Config input Pull up */
pmu_set_pin_pull(bits, PMU_GPIO_PULL_UP);
pmu_set_pin_dir(bits, PMU_GPIO_MODE_INPUT);
/* Read the current value and write */
ool_write16(last_status_reg, ool_read16(data_reg));
/* XOR Enable */
pmu_set_pin_xor_en(bits, true);
/* XOR interrupt enable */
ool_write(PMU_REG_PIN_INT_EN, 0x01);
}
/*********************************************************************
* @fn pmu_gpio_int_init
*
* @brief pmu pin wakeup function config. Compare with pmu_port_wakeup_func_set, this
* function provides two parameter to set pull mode and initial value
*
* @param bits: Select Pin. 0x01--PIN0 0x80--PIN7
* pull: pull mode selection, @ref enum_PMU_GPIO_PULL_t
* init_value: initial value. Once the level of corresponding pin changes to opposite
* level with initial value, PMU_GPIO_PMU_INT will be generated.
*/
void pmu_gpio_int_init(enum_PMU_PINx_t bits, enum_PMU_GPIO_PULL_t pull, uint8_t init_value)
{
uint8_t last_status_reg = PMU_REG_PIN_LAST_V;
uint8_t data_reg = PMU_REG_PIN_DATA;
/* Config input Pull up */
pmu_set_pin_pull(bits, pull);
pmu_set_pin_dir(bits, PMU_GPIO_MODE_INPUT);
/* Read the current value and write */
if (init_value) {
ool_write16(last_status_reg, ool_read16(last_status_reg) | bits);
}
else {
ool_write16(last_status_reg, ool_read16(last_status_reg) & (~bits));
}
/* XOR Enable */
pmu_set_pin_xor_en(bits, true);
/* XOR interrupt enable */
ool_write(PMU_REG_PIN_INT_EN, 0x01);
}
/*********************************************************************
* @fn pmu_port_wakeup_func_clear
*
* @brief Get rtc current counter value
*
* @param bits: Select Pin. 0x01--PIN0 0x80--PIN7
*/
void pmu_port_wakeup_func_clear(enum_PMU_PINx_t bits)
{
/* XOR Disable */
pmu_set_pin_xor_en(bits, false);
}
void pmu_enable_isr(uint16_t isr_map)
{
ool_write16(PMU_REG_INT_MASK, ool_read16(PMU_REG_INT_MASK) | isr_map);
}
void pmu_disable_isr(uint16_t isr_map)
{
ool_write16(PMU_REG_INT_MASK, ool_read16(PMU_REG_INT_MASK) & (~isr_map));
}
uint16_t pmu_get_isr_state(void)
{
return ool_read16(PMU_REG_INT_STATUS);
}
void pmu_clear_isr_state(uint16_t state_map)
{
if (state_map & PMU_BATFULL_INT_STATUS_BIT) {
ool_write(PMU_REG_ANA_INT_CLR, ool_read(PMU_REG_ANA_INT_CLR) | PMU_BATFULL_INT_CLR_BIT);
}
if (state_map & PMU_CHG_ACOK_INT_STATUS_BIT) {
ool_write(PMU_REG_ANA_INT_CLR, ool_read(PMU_REG_ANA_INT_CLR) | PMU_CHG_ACOK_INT_CLR_BIT);
}
if (state_map & PMU_LVD_INT_STATUS_BIT) {
ool_write(PMU_REG_ANA_INT_CLR, ool_read(PMU_REG_ANA_INT_CLR) | PMU_LVD_INT_CLR_BIT);
}
if (state_map & PMU_WDT_INT_STATUS_BIT) {
ool_write(PMU_REG_RTC_CTRL, ool_read(PMU_REG_RTC_CTRL) | PMU_WDT_CLR_BIT);
}
if (state_map & PMU_RTC_A_INT_STATUS_BIT) {
ool_write(PMU_REG_RTC_CTRL, ool_read(PMU_REG_RTC_CTRL) | PMU_RTC_ALARM_A_CLR_BIT);
}
if (state_map & PMU_GPIO_PMU_INT_STATUS_BIT) {
// ool_write16(PMU_REG_PIN_XOR_CLR, ool_read16(PMU_REG_PIN_XOR_RESULT));
}
if (state_map & PMU_GPIO_GROUPH_INT_STATUS_BIT) {
ool_write(PMU_REG_WKUP_INT_CLR, ool_read(PMU_REG_WKUP_INT_CLR) | 0x01);
}
if (state_map & PMU_GPIO_GROUPL_INT_STATUS_BIT) {
ool_write(PMU_REG_WKUP_INT_CLR, ool_read(PMU_REG_WKUP_INT_CLR) | 0x02);
}
}
#if 0
void pmu_lvd_enable(enum_PMU_LVD_THD_t thd)
{
uint8_t value;
value = ool_read(0xa3);
value &= 0x1f;
value |= (thd << 5);
ool_write(0xa3, value);
ool_write(PMU_REG_ANA_LAST_V, ool_read(PMU_REG_ANA_LAST_V) & (~PMU_ANA_LAST_LVD_V_BIT));
ool_write(PMU_REG_ANA_XOR_EN, ool_read(PMU_REG_ANA_XOR_EN) | PMU_ANA_XOR_LVD_EN_BIT);
ool_write(PMU_REG_ANA_INT_EN, ool_read(PMU_REG_ANA_INT_EN) | PMU_LVD_INT_EN_BIT);
pmu_enable_isr(PMU_LVD_INT_MSK_BIT);
}
void pmu_lvd_disable(void)
{
pmu_disable_isr(PMU_LVD_INT_MSK_BIT);
}
void pmu_adkey0_start(void)
{
/*adkey0 interrupt enable*/
ool_write(PMU_REG_ANA_INT_EN, PMU_KEY0_INT_EN_BIT);
/*adkey0 xor enable*/
ool_write16(PMU_REG_ANA_XOR_EN, ool_read(PMU_REG_ANA_XOR_EN) | 0x04);
/*enable adkey0*/
pmu_enable_isr(PMU_ADKEY0_INT_MSK_BIT);
ool_write(PMU_REG_ADKEY_CFG, 0xdb);
NVIC_EnableIRQ(PMU_IRQn);
}
void pmu_adkey1_start(void)
{
/*adkey1 interrupt enable*/
ool_write(PMU_REG_ANA_INT_EN, PMU_KEY1_INT_EN_BIT);
/*adkey1 xor enable*/
ool_write16(PMU_REG_ANA_XOR_EN, ool_read(PMU_REG_ANA_XOR_EN) | 0x08);
/*enable adkey1*/
pmu_enable_isr(PMU_ADKEY1_INT_MSK_BIT);
ool_write(PMU_REG_ADKEY_CFG, 0xdb);
NVIC_EnableIRQ(PMU_IRQn);
}
#endif
__WEAK void PMU_Battery_Full_IRQHandler(void)
{
}
__WEAK void PMU_Charge_Monitor_IRQHandler(void)
{
}
__WEAK void RTC_ALARMA_IRQHandler(void)
{
}
__WEAK void RTC_ALARMB_IRQHandler(void)
{
}
__WEAK void PMU_GPIO_PMU_IRQHandler(void)
{
}
__WEAK void PMU_GPIO_GROUPH_IRQHandler(void)
{
}
__WEAK void PMU_GPIO_GROUPL_IRQHandler(void)
{
}
__WEAK void PMU_LVD_IRQHandler(void)
{
}
__WEAK void PMU_ADKEY0_IRQHandler(void)
{
}
__WEAK void PMU_ADKEY1_IRQHandler(void)
{
}
__WEAK void PMU_IWDT_IRQhandler(void)
{
}
void pmu_irq(void)
{
uint16_t state_map = pmu_get_isr_state();
// printf("%s state%d \r\n",__func__,state_map);
// pmu_clear_isr_state(state_map);
if (state_map & PMU_BATFULL_INT_STATUS_BIT) {
PMU_Battery_Full_IRQHandler();
}
if (state_map & PMU_CHG_ACOK_INT_STATUS_BIT) {
PMU_Charge_Monitor_IRQHandler();
}
if (state_map & PMU_LVD_INT_STATUS_BIT) {
PMU_LVD_IRQHandler();
}
if (state_map & PMU_RTC_A_INT_STATUS_BIT) {
RTC_ALARMA_IRQHandler();
}
if (state_map & PMU_RTC_B_INT_STATUS_BIT) {
RTC_ALARMB_IRQHandler();
}
if (state_map & PMU_GPIO_PMU_INT_STATUS_BIT) {
PMU_GPIO_PMU_IRQHandler();
}
if (state_map & PMU_GPIO_GROUPH_INT_STATUS_BIT) {
PMU_GPIO_GROUPH_IRQHandler();
}
if (state_map & PMU_GPIO_GROUPL_INT_STATUS_BIT) {
PMU_GPIO_GROUPL_IRQHandler();
}
if (state_map & PMU_ADKEY0_INT_STATUS_BIT) {
PMU_ADKEY0_IRQHandler();
}
if (state_map & PMU_ADKEY1_INT_STATUS_BIT) {
PMU_ADKEY1_IRQHandler();
}
if (state_map & PMU_WDT_INT_STATUS_BIT) {
PMU_IWDT_IRQhandler();
}
pmu_clear_isr_state(state_map);
}

View File

@ -0,0 +1,127 @@
/*
******************************************************************************
* @file driver_pmu_iwdt.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2023
* @brief pmu iwdt module driver.
* This file provides firmware functions to manage the
* PMU Independent watchdog (IWDT) peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2023 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/*********************************************************************
* @fn iwdt_init
*
* @brief init the Watchdog.
*/
void iwdt_init(iwdt_Init_t Init)
{
/* enable pmu wdt clock */
ool_write(PMU_REG_CLK_EN, ool_read(PMU_REG_CLK_EN) | PMU_WDT_CLK_EN_BIT);
/* Set iwdt_Count and iwdt_Timeout */
iwdt_Set_Count(Init.iwdt_Count);
iwdt_Set_Timeout(Init.iwdt_Timeout);
/* Set iwdt control */
ool_write(PMU_REG_WDT_CTRL, Init.iwdt_int_Enable | PMU_WDT_RST_CHIP_BIT);
/* iwdt interrupt enable */
if (Init.iwdt_int_Enable)
{
pmu_enable_isr(PMU_WDT_INT_MSK_BIT);
}
else
{
pmu_disable_isr(PMU_WDT_INT_MSK_BIT);
}
}
/*********************************************************************
* @fn iwdt_Enable
*
* @brief Watchdog count Enable.
*/
void iwdt_Enable(void)
{
/* enable iwdt count */
ool_write(PMU_REG_WDT_CTRL, ool_read(PMU_REG_WDT_CTRL) | PMU_WDT_EN_BIT);
}
/*********************************************************************
* @fn iwdt_Disable
*
* @brief Watchdog count Disable.
*/
void iwdt_Disable(void)
{
/* disable iwdt count */
ool_write(PMU_REG_WDT_CTRL, ool_read(PMU_REG_WDT_CTRL) & ~PMU_WDT_EN_BIT);
}
/*********************************************************************
* @fn iwdt_Refresh
*
* @brief Refresh the Watchdog.
*/
void iwdt_Refresh(void)
{
ool_write(PMU_REG_WDT_CTRL, ool_read(PMU_REG_WDT_CTRL) | PMU_WDT_CLR_BIT);
}
/*********************************************************************
* @fn iwdt_Interrupt_Enable
*
* @brief Watchdog Interrupt Enable.
*/
void iwdt_Interrupt_Enable(void)
{
/* enable iwdt interrupt */
ool_write(PMU_REG_WDT_CTRL, ool_read(PMU_REG_WDT_CTRL) | PMU_WDT_IRQ_EN_BIT);
}
/*********************************************************************
* @fn iwdt_Interrupt_Disable
*
* @brief Watchdog Interrupt Disable.
*/
void iwdt_Interrupt_Disable(void)
{
/* enable iwdt interrupt */
ool_write(PMU_REG_WDT_CTRL, ool_read(PMU_REG_WDT_CTRL) & ~PMU_WDT_IRQ_EN_BIT);
}
/*********************************************************************
* @fn iwdt_Set_Count
*
* @brief Set watchdog count.
*
* @param iwdtCount: watchdog count (0x00000000 ~ 0xFFFFFFFF).
*/
void iwdt_Set_Count(uint32_t iwdtCount)
{
/* set iwdt Count value */
ool_write32(PMU_REG_WDT_LEN_0, iwdtCount);
}
/*********************************************************************
* @fn iwdt_Set_Timeout
*
* @brief Set watchdog Timeout. Timeout trigger the system reset.
* Attention: Timeout Set to 0 the system will not reset.
*
* @param WdtCount: watchdog Timeout value (0x0000 ~ 0xFFFF).
*/
void iwdt_Set_Timeout(uint16_t iwdtTimeout)
{
/* set iwdt timeout value */
ool_write16(PMU_REG_WDT_TOUT_COUNTER_0, iwdtTimeout);
}

View File

@ -0,0 +1,272 @@
/*
******************************************************************************
* @file driver_pmu_rtc.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2023
* @brief rtc module driver.
* This file provides firmware functions to manage the
* Real Time Clock (RTC) peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2023 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
static str_Time_t AlarmTime_A;
static str_Time_t AlarmTime_B;
/*********************************************************************
* @fn rtc_AlarmA_Handler
*
* @brief Alarm interrupt handler
*/
__WEAK void rtc_AlarmA_Handler(void)
{
/* Update according to the periodic period in the rtc_AlarmConfig function. */
rtc_AlarmUpdate(AlARM_A);
}
/*********************************************************************
* @fn rtc_AlarmB_Handler
*
* @brief Alarm interrupt handler
*/
__WEAK void rtc_AlarmB_Handler(void)
{
/* Update according to the periodic period in the rtc_AlarmConfig function. */
rtc_AlarmUpdate(AlARM_B);
}
/*********************************************************************
* @fn rtc_init
*
* @brief rtc init
*
* @param InitValue: RTC init value.
*/
void rtc_init(uint32_t InitValue)
{
/* RTC clock enable */
ool_write(PMU_REG_CLK_EN, ool_read(PMU_REG_CLK_EN) | PMU_RTC_CLK_EN_BIT);
/* config init value */
ool_write32(PMU_REG_RTC_COUNTER_0, InitValue);
/* load init into cnt register */
ool_write(PMU_REG_RTC_CTRL, ool_read(PMU_REG_RTC_CTRL) | PMU_RTC_UPD_EN_BIT);
AlarmTime_A.UnitBackup = 0;
AlarmTime_B.UnitBackup = 0;
}
/*********************************************************************
* @fn rtc_CountEnable
*
* @brief RTC count enable
*/
void rtc_CountEnable(void)
{
ool_write(PMU_REG_CLK_EN, ool_read(PMU_REG_CLK_EN) | PMU_RTC_CLK_EN_BIT);
}
/*********************************************************************
* @fn rtc_CountDisable
*
* @brief RTC count disable
*/
void rtc_CountDisable(void)
{
ool_write(PMU_REG_CLK_EN, ool_read(PMU_REG_CLK_EN) & ~PMU_RTC_CLK_EN_BIT);
}
/*********************************************************************
* @fn rtc_AlarmConfig
*
* @brief rtc alarm config
*
* @param fe_Alarm: alarm select.
* @param lu8_hour: hour
* @param lu8_Minute: minute
* @param lu8_Second: second
*/
void rtc_AlarmConfig(enum_Alarm_t fe_Alarm, uint32_t fu32_hour, uint32_t fu32_Minute, uint32_t fu32_Second)
{
uint32_t lu32_Second;
lu32_Second = fu32_hour * 3600;
lu32_Second += fu32_Minute * 60;
lu32_Second += fu32_Second;
switch (fe_Alarm)
{
case AlARM_A:
{
/* Timing unit backup */
AlarmTime_A.UnitBackup = lu32_Second;
/* Convert to count value */
lu32_Second *= pmu_lp_rc_get();
lu32_Second += rtc_GetCount();
rtc_AlarmSet(AlARM_A, lu32_Second);
rtc_AlarmEnable(AlARM_A);
pmu_enable_isr(PMU_RTC_A_INT_MSK_BIT);
}break;
case AlARM_B:
{
/* Timing backup */
AlarmTime_B.UnitBackup = lu32_Second;
/* Convert to count value */
lu32_Second *= pmu_lp_rc_get();
lu32_Second += rtc_GetCount();
rtc_AlarmSet(AlARM_B, lu32_Second);
rtc_AlarmEnable(AlARM_B);
pmu_enable_isr(PMU_RTC_B_INT_MSK_BIT);
}break;
default: break;
}
}
/*********************************************************************
* @fn rtc_GetCount
*
* @brief Get rtc current counter value
*
* @param None.
* @return lu32_CountValue: rtc current counter value.
*/
uint32_t rtc_GetCount(void)
{
uint32_t lu32_CountValue;
/* get current RTC counter */
ool_write(PMU_REG_RTC_CTRL, ool_read(PMU_REG_RTC_CTRL) | PMU_RTC_SAMPLE_BIT);
while ( ool_read(PMU_REG_RTC_CTRL) & PMU_RTC_SAMPLE_BIT);
lu32_CountValue = ool_read32(PMU_REG_RTC_COUNTER_0);
return lu32_CountValue;
}
/*********************************************************************
* @fn rtc_CountUpdate
*
* @brief Update RTC counter
*
* @param fu32_CountValue: update value.
* @return None.
*/
void rtc_CountUpdate(uint32_t fu32_CountValue)
{
/* config init value */
ool_write32(PMU_REG_RTC_COUNTER_0, fu32_CountValue);
/* load init into cnt register */
ool_write(PMU_REG_RTC_CTRL, ool_read(PMU_REG_RTC_CTRL) | PMU_RTC_UPD_EN_BIT);
}
/*********************************************************************
* @fn rtc_AlarmUpdate
*
* @brief rtc alarm Update.
* Update according to the periodic period in the rtc_AlarmConfig function.
*
* @param fe_Alarm: alarm select.
*/
void rtc_AlarmUpdate(enum_Alarm_t fe_Alarm)
{
uint32_t lu32_AddValue;
uint32_t lu32_AlarmValue;
/* Convert to count value */
if (fe_Alarm == AlARM_A)
lu32_AddValue = AlarmTime_A.UnitBackup * pmu_lp_rc_get();
else
lu32_AddValue = AlarmTime_B.UnitBackup * pmu_lp_rc_get();
lu32_AlarmValue = rtc_AlarmRead(fe_Alarm);
lu32_AlarmValue += lu32_AddValue;
rtc_AlarmSet(fe_Alarm, lu32_AlarmValue);
}
/*********************************************************************
* @fn rtc_AlarmEnable
*
* @brief Alarm Enable
*/
void rtc_AlarmEnable(enum_Alarm_t fe_Alarm)
{
ool_write(PMU_REG_RTC_CTRL, ool_read(PMU_REG_RTC_CTRL) | fe_Alarm);
}
/*********************************************************************
* @fn rtc_ALarmDisable
*
* @brief Alarm Disable
*/
void rtc_AlarmDisable(enum_Alarm_t fe_Alarm)
{
ool_write(PMU_REG_RTC_CTRL, ool_read(PMU_REG_RTC_CTRL) & ~fe_Alarm);
}
/*********************************************************************
* @fn rtc_AlarmRead
*
* @brief read rtc alarm config value
*
* @return lu32_ConfigValue: alarm config value.
*/
uint32_t rtc_AlarmRead(enum_Alarm_t fe_Alarm)
{
uint32_t fu32_AlarmValue;
switch (fe_Alarm)
{
case AlARM_A:
{
fu32_AlarmValue = ool_read32(PMU_REG_ALARM_A_COUNTER_0);
}break;
case AlARM_B:
{
fu32_AlarmValue = ool_read32(PMU_REG_ALARM_B_COUNTER_0);
}break;
default: break;
}
return fu32_AlarmValue;
}
/*********************************************************************
* @fn rtc_AlarmSet
*
* @brief Set rtc alarm config value
*
* @param fu32_AlarmValue: alarm config value.
*/
void rtc_AlarmSet(enum_Alarm_t fe_Alarm, uint32_t fu32_AlarmValue)
{
switch (fe_Alarm)
{
case AlARM_A:
{
ool_write32(PMU_REG_ALARM_A_COUNTER_0, fu32_AlarmValue);
}break;
case AlARM_B:
{
ool_write32(PMU_REG_ALARM_B_COUNTER_0, fu32_AlarmValue);
}break;
}
}

View File

@ -0,0 +1,306 @@
/*
******************************************************************************
* @file driver_pwm.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief SPI module driver.
* This file provides firmware functions to manage the
* Pulse-Width Modulatio (PWM) peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/************************************************************************************
* @fn pwm_config
*
* @brief PWM mode. Config channel paramter.
*
* @param PWMx: PWM0<4D><30>PWM1.
* fu16_channel: Select output channel.(1bit ~ 1channel)
* fstr_Config: Config paramter.
*/
void pwm_config(struct_PWM_t *PWMx, uint16_t fu16_channel, struct_PWM_Config_t fstr_Config)
{
uint32_t lu32_Position = 0;
uint32_t lu32_Current_Channel;
PWMx->OutputSelect &= ~fu16_channel;
/* Configure Select channel */
while (fu16_channel >> lu32_Position != 0)
{
/* Get current pin position */
lu32_Current_Channel = fu16_channel & (1uL << lu32_Position);
if (lu32_Current_Channel)
{
/* stop sync update */
PWMx->Update.PWM_Update &= ~lu32_Current_Channel;
PWMx->Edge[lu32_Position].Posedge = fstr_Config.Posedge;
PWMx->Edge[lu32_Position].Negedeg = fstr_Config.Negedge;
PWMx->Frequency[lu32_Position].Prescale = fstr_Config.Prescale - 1;
PWMx->Frequency[lu32_Position].Period = fstr_Config.Period - 1;
}
lu32_Position++;
}
}
/************************************************************************************
* @fn pwm_complementary_config
*
* @brief Complementary outputs with dead-time insertion
*
* @param PWMx: PWM0<4D><30>PWM1.
* fu16_MainChannel: Select main output channel.(1bit ~ 1channel)
* @param ComplementaryChannel: Select complementary output channel.(1bit ~ 1channel)
* fstr_Config: Config paramter.
*/
bool pwm_complementary_config(struct_PWM_t *PWMx, uint16_t fu16_MainChannel, uint16_t ComplementaryChannel, struct_PWM_Complementary_Config_t fstr_Config)
{
struct_PWM_Config_t PWM_Config;
PWM_Config.Prescale = fstr_Config.Prescale;
PWM_Config.Period = fstr_Config.Period;
if (fstr_Config.MianDeadTime != 0)
{
if (fstr_Config.MianDeadTime - 1 >= PWM_Config.Period - 1 - fstr_Config.DutyCycle - fstr_Config.MianDeadTime)
return false;
PWM_Config.Posedge = fstr_Config.MianDeadTime - 1;
PWM_Config.Negedge = PWM_Config.Period - 1 - fstr_Config.DutyCycle - fstr_Config.MianDeadTime;
}
else
{
/* Error check */
if (fstr_Config.DutyCycle >= PWM_Config.Period)
return false;
if (fstr_Config.DutyCycle == 0)
return false;
PWM_Config.Posedge = PWM_Config.Period - 1;
PWM_Config.Negedge = PWM_Config.Period - 1 - fstr_Config.DutyCycle;
}
pwm_config(PWMx, fu16_MainChannel, PWM_Config);
if (fstr_Config.CompDeadTime != 0)
{
if (PWM_Config.Period - 1 - fstr_Config.DutyCycle + fstr_Config.MianDeadTime >= PWM_Config.Period - 1 - fstr_Config.CompDeadTime)
return false;
PWM_Config.Posedge = PWM_Config.Period - 1 - fstr_Config.DutyCycle + fstr_Config.MianDeadTime;
PWM_Config.Negedge = PWM_Config.Period - 1 - fstr_Config.CompDeadTime;
}
else
{
/* Error check */
if (fstr_Config.DutyCycle >= PWM_Config.Period)
return false;
if (fstr_Config.DutyCycle == 0)
return false;
PWM_Config.Posedge = PWM_Config.Period - 1 - fstr_Config.DutyCycle;
PWM_Config.Negedge = PWM_Config.Period - 1;
}
pwm_config(PWMx, ComplementaryChannel, PWM_Config);
return true;
}
/************************************************************************************
* @fn pwm_output_enable
*
* @brief PWM_DAC mode. output enable.
*
* @param PWMx: PWM0<4D><30>PWM1.
* fu16_channel: Select output channel.(1bit ~ 1channel)
*/
void pwm_output_enable(struct_PWM_t *PWMx, uint16_t fu16_channel)
{
PWMx->Update.PWM_Update |= fu16_channel;
PWMx->CNT_EN |= fu16_channel;
PWMx->ChannelEN |= fu16_channel;
}
/************************************************************************************
* @fn pwm_output_disable
*
* @brief PWM_DAC mode. output disable.
*
* @param PWMx: PWM0<4D><30>PWM1.
* fu8_channel: Select output channel.(1bit ~ 1channel)
*/
void pwm_output_disable(struct_PWM_t *PWMx, uint16_t fu16_channel)
{
/* stop sync update */
PWMx->Update.PWM_Update &= ~fu16_channel;
PWMx->ChannelEN &= ~fu16_channel;
PWMx->CNT_EN &= ~fu16_channel;
}
/************************************************************************************
* @fn pwm_output_status
*
* @brief PWM_DAC mode. output inverter disable.
*
* @param PWMx: PWM0<4D><30>PWM1.
* fe_channel: Select output channel.(1bit ~ 1channel)
*
* @return true : PWM runing.
* false: PWM stop.
*/
bool pwm_output_status(struct_PWM_t *PWMx, enum_PWMChannel_t fe_channel)
{
if (PWMx->Update.PWM_Status & fe_channel)
{
return true;
}
else
{
return false;
}
}
/************************************************************************************
* @fn pwm_output_updata
*
* @brief channel Posedge/Negedeg/Prescale/Period updata
*
* @param PWMx: PWM0<4D><30>PWM1.
* fu16_channel: Select output channel.(1bit ~ 1channel)
*/
void pwm_output_updata(struct_PWM_t *PWMx, uint16_t fu16_channel)
{
/* start sync update */
PWMx->Update.PWM_Update |= fu16_channel;
}
/************************************************************************************
* @fn pwm_capture_config
*
* @brief Capture mode. Config channel paramter.
*
* @param PWMx: PWM0<4D><30>PWM1.
* fu16_channel: Select capture channel(1bit ~ 1channel).
* fstr_Config: Config paramter.
*/
void pwm_capture_config(struct_PWM_t *PWMx, uint16_t fu16_channel, struct_Capture_Config_t fstr_Config)
{
uint32_t lu32_Position = 0;
uint32_t lu32_Current_Channel;
/* Set Capture Prescale */
PWMx->CapturePrescale = 0x10 | fstr_Config.CapturePrescale;
/* Configure Select channel */
while (fu16_channel >> lu32_Position != 0)
{
/* Get current pin position */
lu32_Current_Channel = fu16_channel & (1uL << lu32_Position);
if (lu32_Current_Channel)
{
/* Set Capture mode */
if (fstr_Config.CaptureMode == MODE_LOOP)
{
PWMx->CaptureCtrl.Capture_Mode &= ~lu32_Current_Channel;
}
else
{
PWMx->CaptureCtrl.Capture_Mode |= lu32_Current_Channel;
}
}
lu32_Position++;
}
}
/************************************************************************************
* @fn pwm_capture_enable
*
* @brief capture enable.
*
* @param PWMx: PWM0<4D><30>PWM1.
* fu16_channel: Select capture channel.(1bit ~ 1channel)
*/
void pwm_capture_enable(struct_PWM_t *PWMx, uint16_t fu16_channel)
{
PWMx->CaptureCtrl.Capture_EN |= fu16_channel;
}
/************************************************************************************
* @fn pwm_capture_disable
*
* @brief pwm_capture_disable.
*
* @param PWMx: PWM0<4D><30>PWM1.
* fu16_channel: Select capture channel.(1bit ~ 1channel)
*/
void pwm_capture_disable(struct_PWM_t *PWMx, uint16_t fu16_channel)
{
PWMx->CaptureCtrl.Capture_EN &= ~fu16_channel;
}
/************************************************************************************
* @fn pwm_capture_status
*
* @brief get pwm_capture_status.
*
* @param PWMx: PWM0<4D><30>PWM1.
* fe_channel: Select capture channel.(1bit ~ 1channel)
* @return true : capture result value ready.
* false: capture result value not ready.
*/
bool pwm_capture_status(struct_PWM_t *PWMx, enum_PWMChannel_t fe_channel)
{
return (PWMx->CaptureStatus & fe_channel) ? true : false;
}
/************************************************************************************
* @fn pwm_capture_status_clear
*
* @brief capture status claear.
*
* @param PWMx: PWM0<4D><30>PWM1.
* fe_channel: Select capture channel.(1bit ~ 1channel)
*/
void pwm_capture_status_clear(struct_PWM_t *PWMx,enum_PWMChannel_t fe_channel)
{
PWMx->CaptureStatus |= fe_channel;
}
/************************************************************************************
* @fn pwm_capture_value
*
* @brief get pwm_capture_value.
*
* @param PWMx: PWM0<4D><30>PWM1.
* fe_channel: Select capture channel.(1bit ~ 1channel)
*/
uint32_t pwm_capture_value(struct_PWM_t *PWMx, enum_PWMChannel_t fe_channel)
{
uint8_t i;
for (i = 0; i < 16; i++)
{
if (fe_channel & 1 << i)
break;
}
return PWMx->CaptureValue[i];
}

View File

@ -0,0 +1,80 @@
/*
******************************************************************************
* @file driver_qspi.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief QSPI module driver.
* This file provides firmware functions to manage the
* Quad Serial Peripheral Interface (QSPI) peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
#define QSPI_STIG_MAX_SINGLE_LEN 8
#define QSPI_STIG_BANK_DEPTH 128
__RAM_CODE int qspi_stig_cmd(struct qspi_regs_t *QSPI, struct qspi_stig_reg_t cmd, enum qspi_stig_cmd_type_t type, int len, uint8_t *buffer)
{
uint32_t tmp_u32[2];
uint8_t *tmp_u8 = (uint8_t *)tmp_u32;
if(type == QSPI_STIG_CMD_BANK_READ) {
if(QSPI_STIG_BANK_DEPTH < len) {
return -1;
}
}
else {
if(QSPI_STIG_MAX_SINGLE_LEN < len) {
return -1;
}
}
while(__QSPI_IS_BUSY(QSPI));
if(type == QSPI_STIG_CMD_EXE) {
__QSPI_STIG_CMD_SET(QSPI, cmd);
__QSPI_STIG_EXECUTE(QSPI);
while(__QSPI_STIG_ON_GOING(QSPI));
}
else {
if(type == QSPI_STIG_CMD_WRITE) {
for (volatile int32_t i=0; i<len; i++) {
*tmp_u8++ = *buffer++;
}
__QSPI_STIG_DATA_L_SET(QSPI, tmp_u32[0]);
__QSPI_STIG_DATA_H_SET(QSPI, tmp_u32[1]);
__QSPI_STIG_CMD_SET(QSPI, cmd);
__QSPI_STIG_WRITE_BYTES_SET(QSPI, len);
__QSPI_STIG_EXECUTE(QSPI);
while(__QSPI_STIG_ON_GOING(QSPI));
}
else {
__QSPI_STIG_CMD_SET(QSPI, cmd);
__QSPI_STIG_READ_BYTES_SET(QSPI, len);
__QSPI_STIG_EXECUTE(QSPI);
while(__QSPI_STIG_ON_GOING(QSPI));
if(type == QSPI_STIG_CMD_READ) {
tmp_u32[0] = __QSPI_STIG_DATA_L_GET(QSPI);
tmp_u32[1] = __QSPI_STIG_DATA_H_GET(QSPI);
for (volatile int32_t i=0; i<len; i++) {
*buffer++ = *tmp_u8++;
}
}
else {
//TBD, BANK READ
}
}
}
return 0;
}

View File

@ -0,0 +1,196 @@
/*
******************************************************************************
* @file driver_sbc_codec.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief IIR module driver.
* This file provides firmware functions to manage the
* SBC CODEC peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
#define SBC_SYNCWORD 0x9c
/******************************************************************************
* @fn sbc_dec_get_packed_frame_info
*
* @brief sbc decoder get sbc packed frame info
*
* @param data : sbc packed frame
* frame_info : struct_frame_info_t structure contains
*/
int sbc_dec_get_packed_frame_info(uint8_t *data, struct_frame_info_t frame_info)
{
if (data[0] != SBC_SYNCWORD)
{
return -2;
}
frame_info.frequency = (data[1] >> 6) & 0x03;
frame_info.block_mode = (data[1] >> 4) & 0x03;
switch (frame_info.block_mode) {
case 0:
frame_info.block_len = 4;
break;
case 1:
frame_info.block_len = 8;
break;
case 2:
frame_info.block_len = 12;
break;
case 3:
frame_info.block_len = 16;
break;
default:
frame_info.block_len = 4;
break;
}
frame_info.mode = (data[1] >> 2) & 0x03;
switch(frame_info.mode)
{
case 0:
frame_info.channels = 1;
break;
case 3:
frame_info.channels = 2;
break;
default:
break;
}
frame_info.allocation = (data[1] >> 1) & 0x01;
frame_info.subband_mode = (data[1] & 0x01);
frame_info.subbands = frame_info.subband_mode ? 8 : 4;
frame_info.bit_pool = data[2];
if((frame_info.mode == 0 || frame_info.mode == 1) &&
frame_info.bit_pool > 16 * frame_info.subbands)
return -4;
if((frame_info.mode == 3 || frame_info.mode == 2) &&
frame_info.bit_pool > 32 * frame_info.subbands)
return -4;
return 0;
}
/******************************************************************************
* @fn sbc_dec_init
*
* @brief sbc decoder initialize
*
* @param hSbcDec : sbc decoder handler
*/
void sbc_dec_init(SBC_DEC_HandleTypeDef *hSbcDec)
{
/*sbc decoder fifo init*/
SBC_DEC->SBCD_CTRL.Bits.DEC_IN_FIFO_RESET = 1;
SBC_DEC->SBCD_CTRL.Bits.DEC_OUTL_FIFO_RESET = 1;
SBC_DEC->SBCD_CTRL.Bits.DEC_OUTR_FIFO_RESET = 1;
SBC_DEC->SBCD_CTRL.Bits.DEC_RESET = 1;
/* sbc dma config initialize*/
SBC_DEC->SBCD_CTRL.Bits.IN_DMA_EN = hSbcDec->sbc_init.Bits.input_dma_en;
SBC_DEC->SBCD_CTRL.Bits.OUT_DMA_EN = hSbcDec->sbc_init.Bits.output_dma_en;
if(SBC_DEC->SBCD_CTRL.Bits.OUT_DMA_EN == 1)
{
if(hSbcDec->sbc_init.Bits.ch_mode == 1)
{
SBC_DEC->SBCD_CTRL.Bits.OUTR_FIFO_EN = 1;
}
else
{
SBC_DEC->SBCD_CTRL.Bits.OUTL_FIFO_EN = 1;
}
}
/*sbc fifo level intialize*/
SBC_DEC->SBCD_FIFO_LEVEL.Bits.INFIFO_ALEMPTY_LEVEL = hSbcDec->sbc_init.Bits.infifo_alempty_lvl;
SBC_DEC->SBCD_FIFO_LEVEL.Bits.OUTLFIFO_ALFULL_LEVEL = hSbcDec->sbc_init.Bits.outlfifo_alfull_lvl;
SBC_DEC->SBCD_FIFO_LEVEL.Bits.OUTRFIFO_ALFULL_LEVEL = hSbcDec->sbc_init.Bits.outrlfifo_alfull_lvl;
SBC_DEC->SBCD_CTRL.Bits.DEC_EN = 1;
}
/******************************************************************************
* @fn sbc_dec_playdata_IT
*
* @brief sbc decoder play data with isr
*
* @param hSbcDec : sbc decoder handler
* fp_Data : sbc packed frame data
* fu32_Size : sbc packed frame data size
* fp_Data_Out : after sbc decoder pcm data
*/
void sbc_dec_playdata_IT(SBC_DEC_HandleTypeDef *hSbcDec, uint8_t *fp_Data, uint32_t fu32_Size, uint16_t *fp_Data_Out)
{
hSbcDec->OrignData = fp_Data_Out;
hSbcDec->EncodeData = fp_Data;
hSbcDec->DataSize = fu32_Size;
hSbcDec->InputIndex = 0;
hSbcDec->OutIndex = 0;
if(hSbcDec->sbc_init.Bits.ch_mode == SBCD_MONO)
{
SBC_DEC->SBCD_INTEN.Bits.CRC_ERR_INT_EN = 1;
SBC_DEC->SBCD_INTEN.Bits.OUTLFF_ALFULL_INT_EN = 1;
SBC_DEC->SBCD_INTEN.Bits.INFF_EMPTY_INT_EN = 1;
}
else
{
SBC_DEC->SBCD_INTEN.Bits.CRC_ERR_INT_EN = 1;
SBC_DEC->SBCD_INTEN.Bits.OUTRFF_ALFULL_INT_EN = 1;
SBC_DEC->SBCD_INTEN.Bits.INFF_EMPTY_INT_EN = 1;
}
}
/******************************************************************************
* @fn sbcdec_IRQHandler
*
* @brief sbc decoder handle function in sbc decoder isr
*
* @param hSbcDec : sbc decoder handler
*/
void sbcdec_IRQHandler(SBC_DEC_HandleTypeDef *hSbcDec)
{
uint32_t status = __SBCD_GET_ISR_STS();
if(status & OUTLF_ALFULL_INT)
{
while(!__SBCD_OUTLFIFO_IS_EMPTY())
{
hSbcDec->OrignData[hSbcDec->OutIndex++] = SBC_DEC->SBCD_OUTFIFO.Bits.PCM_LEFT_DATA;
}
}
if(status & OUTRF_ALFULL_INT)
{
/*outfifo almost full need to do*/
while(!__SBCD_OUTRFIFO_IS_EMPTY())
{
hSbcDec->OrignData[hSbcDec->OutIndex++] = SBC_DEC->SBCD_OUTFIFO.Bits.PCM_LEFT_DATA;
hSbcDec->OrignData[hSbcDec->OutIndex++] = SBC_DEC->SBCD_OUTFIFO.Bits.PCM_RIGHT_DATA;
}
}
if(status & INFF_EMPTY_INT)
{
while(!__SBCD_INFIFO_IS_FULL())
{
SBC_DEC->SBCD_INFIFO.Bits.SBC_IN = hSbcDec->EncodeData[hSbcDec->InputIndex++];
if(hSbcDec->InputIndex >= hSbcDec->DataSize)
{
__SBCD_INFIFO_EMPTY_DISABLE();
if(hSbcDec->Callback)
{
hSbcDec->Callback(hSbcDec);
}
break;
}
}
}
}

View File

@ -0,0 +1,150 @@
/*
******************************************************************************
* @file driver_sbc_enc.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief SBC ENCODER module driver.
* This file provides firmware functions to manage the
* SBC ENCODER peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/******************************************************************************
* @fn sbc_enc_init
*
* @brief Initialize the SBC encoder according to the specified parameters
* in the SBC_ENC_HandleTypeDef
*
* @param hSbcEnc : SBC_ENC_HandleTypeDef structure that contains the
* configuration information for SBC encoder module.
*/
void sbc_enc_init(SBC_ENC_HandleTypeDef *hSbcEnc)
{
/*sbc encoder init*/
SBC_ENC->SBCE_CTRL.Bits.ENC_INL_FIFO_RESET = 1;
SBC_ENC->SBCE_CTRL.Bits.ENC_INR_FIFO_RESET = 1;
SBC_ENC->SBCE_CTRL.Bits.ENC_OUT_FIFO_RESET = 1;
SBC_ENC->SBCE_CTRL.Bits.ENC_RESET = 1;
/*encode config*/
SBC_ENC->SBCE_CFG.Bits.CH_MODE = hSbcEnc->SbcEncInit.Bits.ch_mode;
if(hSbcEnc->SbcEncInit.Bits.ch_mode == SBCE_MONO)
{
SBC_ENC->SBCE_CTRL.Bits.ENC_INR_FLOW_CTRL = 1;
}
SBC_ENC->SBCE_CFG.Bits.BLK_LEN = hSbcEnc->SbcEncInit.Bits.blk_len;
SBC_ENC->SBCE_CFG.Bits.SMP_FRQ = hSbcEnc->SbcEncInit.Bits.sample_freq;
/*encode fifo level config*/
SBC_ENC->SBCE_INFIFO_LVL.Bits.INLFIFO_ALEMPTY_LEVEL = hSbcEnc->SbcEncInit.Bits.inlfifo_alempty_lvl;
SBC_ENC->SBCE_INFIFO_LVL.Bits.INRFIFO_ALEMPTY_LEVEL = hSbcEnc->SbcEncInit.Bits.inrfifo_alempty_lvl;
SBC_ENC->SBCE_OUTFF_LVL.Bits.OUTFIFO_ALFULL_LEVEL = hSbcEnc->SbcEncInit.Bits.outlfifo_alfull_lvl;
/*dma config*/
if(hSbcEnc->SbcEncInit.Bits.input_dma_en == 1)
{
SBC_ENC->SBCE_CTRL.Bits.IN_DMA_EN = 1;
SBC_ENC->SBCE_CTRL.Bits.INL_FIFO_EN = 1;
SBC_ENC->SBCE_CTRL.Bits.INR_FIFO_EN = 1;
}
if(hSbcEnc->SbcEncInit.Bits.output_dma_en == 1)
{
SBC_ENC->SBCE_CTRL.Bits.OUT_DMA_EN = 1;
}
/*sbc encoder start*/
SBC_ENC->SBCE_CTRL.Bits.ENC_EN = 1;
}
/******************************************************************************
* @fn sbc_encoder_enc_IT
*
* @brief start sbc encoder with isr
*
* @param hSbcEnc : sbc encoder handle.
* fp_Data_In : pcm data in
* fu32_size : pcm data size
* fp_Data_Out : sbc encoder packed frame out
*/
void sbc_encoder_enc_IT(SBC_ENC_HandleTypeDef *hSbcEnc, uint16_t *fp_Data_In, uint32_t fu32_size, uint8_t *fp_Data_Out)
{
hSbcEnc->OrignlData = fp_Data_In;
hSbcEnc->EncodedData = fp_Data_Out;
hSbcEnc->OrignlDataSize = fu32_size;
hSbcEnc->gDataInIndex = 0;
hSbcEnc->gDataOutIndex = 0;
SBC_ENC->SBCE_INTEN.Word |= 0x24;
return;
}
/******************************************************************************
* @fn sbcenc_IRQHandler
*
* @brief sbc encoder handle function in sbc encoder isr
*
* @param hSbcEnc : sbc encoder handle.
*
*/
void sbcenc_IRQHandler(SBC_ENC_HandleTypeDef *hSbcEnc)
{
uint32_t isr = __SBCE_GET_ISR_STS();
if(isr & OUTFF_ALFULL_INT)
{
while(!__SBCE_OUTFIFO_IS_EMPTY())
{
hSbcEnc->EncodedData[hSbcEnc->gDataOutIndex++] = (uint8_t)__SBCE_GET_OUT_RESULT_WORD();
}
}
if(isr & INLF_EMPTY_INT)
{
uint32_t read_size = 0;
if(SBC_ENC->SBCE_CFG.Bits.CH_MODE == SBCE_STEREO)/*2 channels*/
{
read_size = (hSbcEnc->OrignlDataSize - hSbcEnc->gDataInIndex) >= 256 ? 256 : (hSbcEnc->OrignlDataSize - hSbcEnc->gDataInIndex);
for(uint32_t i = 0; i< read_size/2; i++)
{
SBC_ENC->SBCE_INFIFO.Word = *((int32_t *)&hSbcEnc->OrignlData[hSbcEnc->gDataInIndex]);
hSbcEnc->gDataInIndex += 2;
}
}
else/*1 channel*/
{
read_size = (hSbcEnc->OrignlDataSize - hSbcEnc->gDataInIndex) >= 128 ? 128 : (hSbcEnc->OrignlDataSize - hSbcEnc->gDataInIndex);
for(uint32_t i = 0; i< read_size; i++)
{
SBC_ENC->SBCE_INFIFO.Bits.ENC_FFL = hSbcEnc->OrignlData[hSbcEnc->gDataInIndex++];
}
}
if(hSbcEnc->gDataInIndex >= hSbcEnc->OrignlDataSize)
{
__SBCE_INLFF_EMPTY_INT_DISABLE();
}
// while(!__SBCE_INLFIFO_IS_FULL())
// {
// if(SBC_ENC->SBCE_CFG.Bits.CH_MODE == SBCE_STEREO)/*2 channels*/
// {
// SBC_ENC->SBCE_INFIFO.Word = *((int32_t *)&hSbcEnc->OrignlData[hSbcEnc->gDataInIndex]);
// hSbcEnc->gDataInIndex += 2;
// }
// else/*1 channel*/
// {
// SBC_ENC->SBCE_INFIFO.Bits.ENC_FFL = hSbcEnc->OrignlData[hSbcEnc->gDataInIndex++];
// }
// if(hSbcEnc->gDataInIndex >= hSbcEnc->OrignlDataSize)
// {
// __SBCE_INLFF_EMPTY_INT_DISABLE();
// break;
// }
// }
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,888 @@
/*
******************************************************************************
* @file driver_sd_card.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2022
* @brief SD card application HAL module driver.
******************************************************************************
* @attention
*
* Copyright (c) 2022 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/* Private function prototypes -----------------------------------------------*/
static uint32_t __SDCard_PowerON(SD_HandleTypeDef *hsd);
static uint32_t __SDCard_InitCard(SD_HandleTypeDef *hsd);
static void __SDCard_GetCardCSD(SD_HandleTypeDef *hsd);
static void __SDCard_GetCardCID(SD_HandleTypeDef *hsd);
/************************************************************************************
* @fn SDCard_IRQHandler
*
* @brief SDCard interrupt handler.
*
* @param hsd: Pointer to SD handle
*/
void SDCard_IRQHandler(SD_HandleTypeDef *hsd)
{
switch (hsd->CardStatus)
{
/* card read, write */
case CARD_STATUS_READ_BUSY:
case CARD_STATUS_WIRTE_BUSY:
{
/* DMA interrupt */
if (__SD_GET_INT_STATUS(hsd->SDx) & INT_DMA_INT)
{
__SD_CLR_INT_STATUS(hsd->SDx, INT_DMA_INT);
/* SDMA system Address alignment increases */
hsd->AddrAlign += SDMA_ADDR_UNIT;
/* Update SDMA system Address */
__SD_SET_SDMA_SYSTEM_ADDR(hsd->SDx, (uint32_t)hsd->AddrAlign);
}
/* error */
if (__SD_GET_INT_STATUS(hsd->SDx) & INT_ERR_MASK)
{
/* clear interrupt status */
__SD_CLR_ALL_INT_STATUS(hsd->SDx);
hsd->CardStatus = CARD_STATUS_ERR;
}
/* transfer complete */
if (__SD_GET_INT_STATUS(hsd->SDx) & INT_TRANSFER_COMPLETE)
{
/* clear transfer complete statsu */
__SD_CLR_INT_STATUS(hsd->SDx, INT_TRANSFER_COMPLETE);
hsd->CardStatus = CARD_STATUS_IDLE;
}
}break;
default: break;
}
}
/************************************************************************************
* @fn SDCard_Init
*
* @brief Initializes the SD Card.
*
* @param hsd: Pointer to SD handle
*/
uint32_t SDCard_Init(SD_HandleTypeDef *hsd)
{
uint32_t lu32_ErrState = INT_NO_ERR;
/* SD Crad class initialization */
SD_SDCardClass_Init(hsd->SDx);
for(volatile uint32_t i=0; i<10000; i++);
/* Identify card operating voltage */
lu32_ErrState = __SDCard_PowerON(hsd);
if (lu32_ErrState)
{
return lu32_ErrState;
}
/* Card initialization */
lu32_ErrState = __SDCard_InitCard(hsd);
if (lu32_ErrState)
{
return lu32_ErrState;
}
/* Get the card information from the CID register */
__SDCard_GetCardCID(hsd);
/* Get the card information from the CSD register */
__SDCard_GetCardCSD(hsd);
return lu32_ErrState;
}
/************************************************************************************
* @fn SDCard_BusWidth_Select
*
* @brief SDCard 1bit/4bit bus width select.
*
* @param hsd: Pointer to SD handle.
* fu32_BusWidth: bus width. can select SDIO_BUS_WIDTH_1BIT.
* SDIO_BUS_WIDTH_4BIT.
*/
uint32_t SDCard_BusWidth_Select(SD_HandleTypeDef *hsd, uint32_t fu32_BusWidth)
{
uint32_t lu32_ErrState = INT_NO_ERR;
/* SEND CMD55 APP_CMD with RCA as 0 */
lu32_ErrState = SD_CMD_AppCommand(hsd->SDx, hsd->RCA);
if (lu32_ErrState)
{
return lu32_ErrState;
}
/* Send ACMD6 SET_BUS_WIDTH */
lu32_ErrState = SD_ACMD_SetBusWidth(hsd->SDx, fu32_BusWidth);
if (lu32_ErrState)
{
return lu32_ErrState;
}
else
{
if (fu32_BusWidth)
__SD_DATA_WIDTH_4BIT(hsd->SDx);
else
__SD_DATA_WIDTH_1BIT(hsd->SDx);
}
return lu32_ErrState;
}
/************************************************************************************
* @fn SDCard_ReadBolcks
*
* @brief Reads block(s) from a specified address in a card.
* The Data transfer by polling mode.
*
* @param hsd: Pointer to SD handle.
* fp_Data: pointer to the received dat buffer.
* fu32_BlockAddr: Block Start Address.
* fu16_BlockNum: Number of SD blocks to read.
*/
uint32_t SDCard_ReadBolcks(SD_HandleTypeDef *hsd, uint32_t *fp_Data, uint32_t fu32_BlockAddr, uint16_t fu16_BlockNum)
{
int i;
uint32_t lu32_ErrState = INT_NO_ERR;
if (fu16_BlockNum == 0)
return E1_NUM_ERR;
if (fu16_BlockNum == 1)
{
/* SEND CMD17 READ_SINGLI_BLOCK */
lu32_ErrState = SD_CMD_ReadSingleBlock(hsd->SDx, fu32_BlockAddr);
if (lu32_ErrState)
return lu32_ErrState;
/* Wait for Buffer Read Ready Int */
while(!(__SD_GET_INT_STATUS(hsd->SDx) & INT_BUFFER_READ_READY));
/* Clear Buffer_Read_Ready */
__SD_CLR_INT_STATUS(hsd->SDx, INT_BUFFER_READ_READY);
/* Read one block */
for (i = 0; i < BLOCKSIZE / 4; i++)
{
*fp_Data++ = __SD_GET_BUFFERDATA(hsd->SDx);
}
}
else
{
/* SEND CMD23 SET_BLOCK_COUNT */
lu32_ErrState = SD_CMD_SetBlockCount(hsd->SDx, fu16_BlockNum);
if (lu32_ErrState)
return lu32_ErrState;
/* Set block count */
__SD_SET_BLOCK_COUNT(hsd->SDx, fu16_BlockNum);
/* SEND CMD18 READ_MULTIPLE_BLOCK */
lu32_ErrState = SD_CMD_ReadMultiBlock(hsd->SDx, fu32_BlockAddr);
if (lu32_ErrState)
return lu32_ErrState;
while (fu16_BlockNum--)
{
/* Wait for Buffer_Read_Ready */
while(!(__SD_GET_INT_STATUS(hsd->SDx) & INT_BUFFER_READ_READY));
/* Clear Buffer_Read_Ready */
__SD_CLR_INT_STATUS(hsd->SDx, INT_BUFFER_READ_READY);
/* Read one block */
for (i = 0; i < BLOCKSIZE / 4; i++)
{
*fp_Data++ = __SD_GET_BUFFERDATA(hsd->SDx);
}
}
}
/* wait for transfer complete or any errors occur */
while(!(__SD_GET_INT_STATUS(hsd->SDx) & (INT_TRANSFER_COMPLETE | INT_ERR_MASK)));
/* Any errors occur */
if (__SD_GET_INT_STATUS(hsd->SDx) & INT_ERR_MASK)
{
lu32_ErrState = __SD_GET_INT_STATUS(hsd->SDx) & INT_ERR_MASK;
}
/* clear interrupt status */
__SD_CLR_ALL_INT_STATUS(hsd->SDx);
return lu32_ErrState;
}
/************************************************************************************
* @fn SDCard_WriteBolcks
*
* @brief Write block(s) from a specified address in a card.
* The Data transfer by polling mode.
*
* @param hsd: Pointer to SD handle.
* fp_Data: pointer to the received dat buffer.
* fu32_BlockAddr: Block Address.
* fu16_BlockNum: Number of SD blocks to write.
*/
uint32_t SDCard_WriteBolcks(SD_HandleTypeDef *hsd, uint32_t *fp_Data, uint32_t fu32_BlockAddr, uint16_t fu16_BlockNum)
{
int i;
uint32_t lu32_ErrState = INT_NO_ERR;
if (fu16_BlockNum == 0)
return E1_NUM_ERR;
if (fu16_BlockNum == 1)
{
/* SEND CMD24 WRITE_BLOCK */
lu32_ErrState = SD_CMD_WriteSingleBlock(hsd->SDx, fu32_BlockAddr);
if (lu32_ErrState)
return lu32_ErrState;
/* Wait for buffer write enable Int */
while(!(__SD_GET_PRESENT_STATE(hsd->SDx) & PreState_BUFFER_WRITE_EN_MASK));
/* write one block */
for (i = 0; i < BLOCKSIZE / 4; i++)
{
__SD_SET_BUFFERDATA(hsd->SDx, *fp_Data++);
}
}
else
{
/* SEND CMD23 SET_BLOCK_COUNT */
lu32_ErrState = SD_CMD_SetBlockCount(hsd->SDx, fu16_BlockNum);
if (lu32_ErrState)
return lu32_ErrState;
/* Set block count */
__SD_SET_BLOCK_COUNT(hsd->SDx, fu16_BlockNum);
/* SEND CMD25 WRITE_MULTIPLE_BLOCK */
lu32_ErrState = SD_CMD_WriteMultiBlock(hsd->SDx, fu32_BlockAddr);
if (lu32_ErrState)
return lu32_ErrState;
/* First block transfer check the PresentState register */
/* Wait for Buffer_Write_Enable */
while(!(__SD_GET_PRESENT_STATE(hsd->SDx) & PreState_BUFFER_WRITE_EN_MASK));
/* write one block */
for (i = 0; i < BLOCKSIZE / 4; i++)
{
__SD_SET_BUFFERDATA(hsd->SDx, *fp_Data++);
}
fu16_BlockNum--;
/* Other block transfer check the StatusInt register */
while(fu16_BlockNum--)
{
/* Wait for Buffer_Write_Ready */
while(!(__SD_GET_INT_STATUS(hsd->SDx) & INT_BUFFER_WRITE_READY));
/* Clear Buffer_Write_Ready */
__SD_CLR_INT_STATUS(hsd->SDx, INT_BUFFER_WRITE_READY);
/* write one block */
for (i = 0; i < BLOCKSIZE / 4; i++)
{
__SD_SET_BUFFERDATA(hsd->SDx, *fp_Data++);
}
}
}
/* wait for transfer complete or any errors occur */
while(!(__SD_GET_INT_STATUS(hsd->SDx) & (INT_TRANSFER_COMPLETE | INT_ERR_MASK)));
/* Any errors occur */
if (__SD_GET_INT_STATUS(hsd->SDx) & INT_ERR_MASK)
{
lu32_ErrState = __SD_GET_INT_STATUS(hsd->SDx) & INT_ERR_MASK;
}
/* clear interrupt status */
__SD_CLR_ALL_INT_STATUS(hsd->SDx);
return lu32_ErrState;
}
/************************************************************************************
* @fn SDCard_ReadBolcks_SDMA
*
* @brief Reads block(s) from a specified address in a card.
* The Data transfer by SDMA(Simple DMA) mode.
*
* @param hsd: Pointer to SD handle.
* fp_Data: pointer to the received dat buffer.
* fu32_BlockAddr: Block Start Address.
* fu16_BlockNum: Number of SD blocks to read.
*/
uint32_t SDCard_ReadBolcks_SDMA(SD_HandleTypeDef *hsd, uint32_t *fp_Data, uint32_t fu32_BlockAddr, uint16_t fu16_BlockNum)
{
int i;
uint32_t lu32_ErrState = INT_NO_ERR;
bool lb_TrfComplete = true;
uint32_t lu32_Addr = (uint32_t)fp_Data;
if (fu16_BlockNum == 0)
return E1_NUM_ERR;
/* SEND CMD23 SET_BLOCK_COUNT */
lu32_ErrState = SD_CMD_SetBlockCount(hsd->SDx, fu16_BlockNum);
if (lu32_ErrState)
return lu32_ErrState;
/* set SDMA system Address */
__SD_SET_SDMA_SYSTEM_ADDR(hsd->SDx, (uint32_t)fp_Data);
/* Set block count */
__SD_SET_BLOCK_COUNT(hsd->SDx, fu16_BlockNum);
/* SEND CMD18 READ_MULTIPLE_BLOCK */
lu32_ErrState = SD_CMD_ReadBlock_SDMA(hsd->SDx, fu32_BlockAddr);
if (lu32_ErrState)
return lu32_ErrState;
/* Address alignment */
lu32_Addr &= SDMA_ADDR_ALIGN_MASK;
/* wait for transfer complete or any errors occur */
while (lb_TrfComplete)
{
if (__SD_GET_INT_STATUS(hsd->SDx) & (INT_TRANSFER_COMPLETE | INT_ERR_MASK))
{
lb_TrfComplete = false;
}
if (__SD_GET_INT_STATUS(hsd->SDx) & INT_DMA_INT)
{
__SD_CLR_INT_STATUS(hsd->SDx, INT_DMA_INT);
/* SDMA system Address alignment increases */
lu32_Addr += SDMA_ADDR_UNIT;
/* Update SDMA system Address */
__SD_SET_SDMA_SYSTEM_ADDR(hsd->SDx, (uint32_t)lu32_Addr);
}
}
/* Any errors occur */
if (__SD_GET_INT_STATUS(hsd->SDx) & INT_ERR_MASK)
{
lu32_ErrState = __SD_GET_INT_STATUS(hsd->SDx) & INT_ERR_MASK;
}
/* clear interrupt status */
__SD_CLR_ALL_INT_STATUS(hsd->SDx);
return lu32_ErrState;
}
/************************************************************************************
* @fn SDCard_WriteBolcks_SDMA
*
* @brief Write block(s) from a specified address in a card.
* The Data transfer by SDMA(Simple DMA) mode.
*
* @param hsd: Pointer to SD handle.
* fp_Data: pointer to the received dat buffer.
* fu32_BlockAddr: Block Address.
* fu16_BlockNum: Number of SD blocks to write.
*/
uint32_t SDCard_WriteBolcks_SDMA(SD_HandleTypeDef *hsd, uint32_t *fp_Data, uint32_t fu32_BlockAddr, uint16_t fu16_BlockNum)
{
int i;
uint32_t lu32_ErrState = INT_NO_ERR;
bool lb_TrfComplete = true;
uint32_t lu32_Addr = (uint32_t)fp_Data;
if (fu16_BlockNum == 0)
return E1_NUM_ERR;
/* SEND CMD23 SET_BLOCK_COUNT */
lu32_ErrState = SD_CMD_SetBlockCount(hsd->SDx, fu16_BlockNum);
if (lu32_ErrState)
return lu32_ErrState;
/* set SDMA system Address */
__SD_SET_SDMA_SYSTEM_ADDR(hsd->SDx, (uint32_t)fp_Data);
/* Set block count */
__SD_SET_BLOCK_COUNT(hsd->SDx, fu16_BlockNum);
/* SEND CMD25 WRITE_MULTIPLE_BLOCK */
lu32_ErrState = SD_CMD_WriteBlock_SDMA(hsd->SDx, fu32_BlockAddr);
if (lu32_ErrState)
return lu32_ErrState;
/* Address alignment */
lu32_Addr &= SDMA_ADDR_ALIGN_MASK;
/* wait for transfer complete or any errors occur */
while (lb_TrfComplete)
{
if (__SD_GET_INT_STATUS(hsd->SDx) & (INT_TRANSFER_COMPLETE | INT_ERR_MASK))
{
lb_TrfComplete = false;
}
if (__SD_GET_INT_STATUS(hsd->SDx) & INT_DMA_INT)
{
__SD_CLR_INT_STATUS(hsd->SDx, INT_DMA_INT);
/* SDMA system Address alignment increases */
lu32_Addr += SDMA_ADDR_UNIT;
/* Update SDMA system Address */
__SD_SET_SDMA_SYSTEM_ADDR(hsd->SDx, (uint32_t)lu32_Addr);
}
}
/* Any errors occur */
if (__SD_GET_INT_STATUS(hsd->SDx) & INT_ERR_MASK)
{
lu32_ErrState = __SD_GET_INT_STATUS(hsd->SDx) & INT_ERR_MASK;
}
/* clear interrupt status */
__SD_CLR_ALL_INT_STATUS(hsd->SDx);
return lu32_ErrState;
}
/************************************************************************************
* @fn SDCard_ReadBolcks_SDMA_IT
*
* @brief Reads block(s) from a specified address in a card.
* The Data transfer by SDMA(Simple DMA) mode with interrupt.
*
* @param hsd: Pointer to SD handle.
* fp_Data: pointer to the received dat buffer.
* fu32_BlockAddr: Block Start Address.
* fu16_BlockNum: Number of SD blocks to read.
*/
uint32_t SDCard_ReadBolcks_SDMA_IT(SD_HandleTypeDef *hsd, uint32_t *fp_Data, uint32_t fu32_BlockAddr, uint16_t fu16_BlockNum)
{
int i;
uint32_t lu32_ErrState = INT_NO_ERR;
if (hsd->CardStatus != CARD_STATUS_IDLE)
return E4_CARD_BUSY;
if (fu16_BlockNum == 0)
return E1_NUM_ERR;
/* SEND CMD23 SET_BLOCK_COUNT */
lu32_ErrState = SD_CMD_SetBlockCount(hsd->SDx, fu16_BlockNum);
if (lu32_ErrState)
return lu32_ErrState;
/* set SDMA system Address */
__SD_SET_SDMA_SYSTEM_ADDR(hsd->SDx, (uint32_t)fp_Data);
/* Set block count */
__SD_SET_BLOCK_COUNT(hsd->SDx, fu16_BlockNum);
/* Address alignment */
hsd->AddrAlign = (uint32_t)fp_Data & SDMA_ADDR_ALIGN_MASK;
/* Enable error/transfer complete/dma */
__SD_INT_ENABLE(hsd->SDx, INT_DMA_INT | INT_TRANSFER_COMPLETE | INT_ERR_MASK);
/* SEND CMD18 READ_MULTIPLE_BLOCK */
lu32_ErrState = SD_CMD_ReadBlock_SDMA(hsd->SDx, fu32_BlockAddr);
if (lu32_ErrState)
return lu32_ErrState;
else
hsd->CardStatus = CARD_STATUS_READ_BUSY;
return lu32_ErrState;
}
/************************************************************************************
* @fn SDCard_WriteBolcks_SDMA_IT
*
* @brief Write block(s) from a specified address in a card.
* The Data transfer by SDMA(Simple DMA) mode with interrupt.
*
* @param hsd: Pointer to SD handle.
* fp_Data: pointer to the received dat buffer.
* fu32_BlockAddr: Block Address.
* fu16_BlockNum: Number of SD blocks to write.
*/
uint32_t SDCard_WriteBolcks_SDMA_IT(SD_HandleTypeDef *hsd, uint32_t *fp_Data, uint32_t fu32_BlockAddr, uint16_t fu16_BlockNum)
{
int i;
uint32_t lu32_ErrState = INT_NO_ERR;
if (hsd->CardStatus != CARD_STATUS_IDLE)
return E4_CARD_BUSY;
if (fu16_BlockNum == 0)
return E1_NUM_ERR;
/* SEND CMD23 SET_BLOCK_COUNT */
lu32_ErrState = SD_CMD_SetBlockCount(hsd->SDx, fu16_BlockNum);
if (lu32_ErrState)
return lu32_ErrState;
/* set SDMA system Address */
__SD_SET_SDMA_SYSTEM_ADDR(hsd->SDx, (uint32_t)fp_Data);
/* Set block count */
__SD_SET_BLOCK_COUNT(hsd->SDx, fu16_BlockNum);
/* Address alignment */
hsd->AddrAlign = (uint32_t)fp_Data & SDMA_ADDR_ALIGN_MASK;
/* Enable error/transfer complete/dma */
__SD_INT_ENABLE(hsd->SDx, INT_DMA_INT | INT_TRANSFER_COMPLETE | INT_ERR_MASK);
/* SEND CMD25 WRITE_MULTIPLE_BLOCK */
lu32_ErrState = SD_CMD_WriteBlock_SDMA(hsd->SDx, fu32_BlockAddr);
if (lu32_ErrState)
return lu32_ErrState;
else
hsd->CardStatus = CARD_STATUS_WIRTE_BUSY;
return lu32_ErrState;
}
/************************************************************************************
* @fn SDCard_Erase
*
* @brief Write block(s) from a specified address in a card.
* The Data transfer by polling mode.
*
* @param hsd: Pointer to SD handle.
* BlockStartAdd: Start Block address
* BlockEndAdd: End Block address
*/
uint32_t SDCard_Erase(SD_HandleTypeDef *hsd, uint32_t BlockStartAddr, uint32_t BlockEndAddr)
{
uint32_t lu32_ErrState = INT_NO_ERR;
/* CMD32: ERASE_WR_BLK_START */
lu32_ErrState = SD_CMD_EraseStartAddr(hsd->SDx, BlockStartAddr);
if (lu32_ErrState)
{
return lu32_ErrState;
}
/* CMD33: ERASE_WR_BLK_END */
lu32_ErrState = SD_CMD_EraseEndAddr(hsd->SDx, BlockEndAddr);
if (lu32_ErrState)
{
return lu32_ErrState;
}
/* CMD38: ERASE */
lu32_ErrState = SD_CMD_Erase(hsd->SDx);
if (lu32_ErrState)
{
return lu32_ErrState;
}
return lu32_ErrState;
}
/************************************************************************************
* @fn SDCard_Get_Block_count
*
* @brief Get block counter of mounted SD Card.
*
* @param hsd: Pointer to SD handle.
*
* @return Block count.
*/
uint32_t SDCard_Get_Block_count(SD_HandleTypeDef *hsd)
{
if (hsd) {
return hsd->CardInfo.MemoryCapacity / 512;
}
else {
return 0;
}
}
/************************************************************************************
* @fn SDCard_GetCardCSD
*
* @brief Get the card information from the CSD register.
*/
static void __SDCard_GetCardCSD(SD_HandleTypeDef *hsd)
{
hsd->CSDInfo = (SD_CardCSDTypeDef *)hsd->CSD;
/* Card memory capacity, unit KByte */
hsd->CardInfo.MemoryCapacity = (hsd->CSDInfo->C_SIZE + 1) * 512;
/* Card command class */
hsd->CardInfo.Class = hsd->CSDInfo->CCC;
}
/************************************************************************************
* @fn SDCard_GetCardCID
*
* @brief Get the card information from the CID register.
*/
static void __SDCard_GetCardCID(SD_HandleTypeDef *hsd)
{
hsd->CIDInfo = (SD_CardCIDTypeDef *)hsd->CID;
}
/************************************************************************************
* @fn SD_PowerON
*
* @brief Enquires cards about their operating voltage and configures clock ontrols.
*/
static uint32_t __SDCard_PowerON(SD_HandleTypeDef *hsd)
{
uint32_t lu32_ErrState = INT_NO_ERR;
uint32_t lu32_Response;
bool lb_BusyStatus = false;
/* CMD0: GO_IDLE_STATE */
lu32_ErrState = SD_CMD_GoIdleState(hsd->SDx);
if (lu32_ErrState)
{
return lu32_ErrState;
}
/* CMD8: SEND_IF_COND: Command available only on V2.0 cards */
lu32_ErrState = SD_CMD_SendInterfaceCondition(hsd->SDx);
if (lu32_ErrState)
{
hsd->CardInfo.CardVersion = CARD_VER_1_X;
return lu32_ErrState;
}
else
{
hsd->CardInfo.CardVersion = CARD_VER_2_X;
/* signaling 3.3V */
if (hsd->Init.SpeedMode & SIGNALING_3_3V_MASK)
{
while (lb_BusyStatus == false)
{
/* Send CMD55 APP_CMD with RCA as 0 */
lu32_ErrState = SD_CMD_AppCommand(hsd->SDx, 0);
if (lu32_ErrState)
{
return lu32_ErrState;
}
/* Send ACMD41 SD_SEND_OP_COND */
lu32_ErrState = SD_ACMD_SendOperCondition(hsd->SDx, ACMD41_ARG_HCS|ACMD41_ARG_VOLTAGE_WINDOW_32_33, &hsd->OCR);
if (lu32_ErrState)
{
return lu32_ErrState;
}
lb_BusyStatus = hsd->OCR & OCR_BUSY ? true : false;
}
if (hsd->OCR & OCR_CCS)
{
hsd->CardInfo.CardType = CARD_TYPE_SDHC_SDXC;
}
else
{
hsd->CardInfo.CardType = CARD_TYPE_SDSC;
}
}
/* signaling 1.8V */
else
{
while (lb_BusyStatus == false)
{
/* SEND CMD55 APP_CMD with RCA as 0 */
lu32_ErrState = SD_CMD_AppCommand(hsd->SDx, 0);
if (lu32_ErrState)
{
return lu32_ErrState;
}
/* Send ACMD41 SD_SEND_OP_COND */
lu32_ErrState = SD_ACMD_SendOperCondition(hsd->SDx, ACMD41_ARG_HCS|ACMD41_ARG_S18R|ACMD41_ARG_VOLTAGE_WINDOW_32_33, &hsd->OCR);
if (lu32_ErrState)
{
return lu32_ErrState;
}
lb_BusyStatus = hsd->OCR & OCR_BUSY ? true : false;
}
/* Card Capacity Status */
if (hsd->OCR & OCR_CCS)
{
hsd->CardInfo.CardType = CARD_TYPE_SDHC_SDXC;
}
else
{
hsd->CardInfo.CardType = CARD_TYPE_SDSC;
}
/* switching to 1.8V Accepted */
if (hsd->OCR & OCR_S18A)
{
/* SEND CMD11 VOLTAGE_SWITCH */
lu32_ErrState = SD_CMD_VoltageSwitch(hsd->SDx);
if (lu32_ErrState == INT_NO_ERR)
{
/* Data line is in use */
while(!(__SD_GET_PRESENT_STATE(hsd->SDx) & PreState_DAT0_SIGNAL_MASK));
/* Host switch 1.8V */
__SD_1_8V_ENABLE(hsd->SDx, 1);
/* Host default select SDR12 */
__SD_SDCLK_DISABLE(hsd->SDx);
__SD_UHS_MODE(hsd->SDx, 0);
__SD_SDCLK_ENABLE(hsd->SDx);
/* Wait to Card ready */
uint32_t lu32_Timeout = 100;
while (lu32_Timeout--)
{
if (!SD_CMD_SendStatus(hsd->SDx, hsd->RCA, &lu32_Response))
{
break;
}
}
}
}
else
{
lu32_ErrState = E2_1_8V_ERR;
}
}
}
return lu32_ErrState;
}
/************************************************************************************
* @fn __SDCard_InitCard
*
* @brief Initializes the sd card.
*/
static uint32_t __SDCard_InitCard(SD_HandleTypeDef *hsd)
{
uint32_t lu32_ErrState = INT_NO_ERR;
uint32_t lu32_Response;
uint32_t CMD6_Data[16];
/* CMD2: ALL_SEND_CID */
lu32_ErrState = SD_CMD_AllSendCID(hsd->SDx, hsd->CID);
if (lu32_ErrState)
{
return lu32_ErrState;
}
/* CMD3: SEND_RELATIVE_ADDR */
lu32_ErrState = SD_CMD_SendRelAddr(hsd->SDx, &hsd->RCA);
if (lu32_ErrState)
{
return lu32_ErrState;
}
/* CMD9: SEND_CSD */
lu32_ErrState = SD_CMD_SendCSD(hsd->SDx, hsd->RCA, hsd->CSD);
if (lu32_ErrState)
{
return lu32_ErrState;
}
/* CMD7: SEL_DESEL_CARD */
lu32_ErrState = SD_CMD_SelectCard(hsd->SDx, hsd->RCA);
if (lu32_ErrState)
{
return lu32_ErrState;
}
/* Wait to enter transfer state */
uint32_t lu32_Timeout = 100;
while (lu32_Timeout--)
{
/* CMD13: SEND_STATUS */
lu32_ErrState = SD_CMD_SendStatus(hsd->SDx, hsd->RCA, &lu32_Response);
if (lu32_ErrState)
{
return lu32_ErrState;
}
if (lu32_Response & CARD_CURRENT_STATE_TRAN)
break;
}
/* Switch card function */
if (hsd->Init.SpeedMode != SPEED_DS)
{
/* CMD6: SWITCH_FUNC */
lu32_ErrState = SD_CMD_SwitchFunc(hsd->SDx, 0x80FFFFF0 | hsd->Init.SpeedMode);
if (lu32_ErrState)
{
return lu32_ErrState;
}
if (lu32_ErrState == INT_NO_ERR)
{
/* Wait for Buffer Read Ready Int */
while(!(__SD_GET_INT_STATUS(hsd->SDx) & INT_BUFFER_READ_READY));
/* Clear Buffer_Read_Ready */
__SD_CLR_INT_STATUS(hsd->SDx, INT_BUFFER_READ_READY);
/* Read one block */
for (int i = 0; i < 16; i++)
{
CMD6_Data[i] = __SD_GET_BUFFERDATA(hsd->SDx);
}
/* wait for transfer complete or any errors occur */
while(!(__SD_GET_INT_STATUS(hsd->SDx) & (INT_TRANSFER_COMPLETE | INT_ERR_MASK)));
/* Any errors occur */
if (__SD_GET_INT_STATUS(hsd->SDx) & INT_ERR_MASK)
{
return (__SD_GET_INT_STATUS(hsd->SDx) & INT_ERR_MASK);
}
/* clear interrupt status */
__SD_CLR_ALL_INT_STATUS(hsd->SDx);
/* Check Card */
/* Card Not support selected Speed */
if ((CMD6_Data[4] & 0xF) == 0xF)
{
lu32_ErrState = E3_SPEED_ERR;
return lu32_ErrState;
}
/* Update Speed mode */
else
{
if (hsd->Init.SpeedMode == SPEED_HS)
{
/* HIGH Speed mode */
__SD_SPEED_MODE(hsd->SDx, 1);
}
else
{
/* SDR25/SDR50/SDR104/DDR50 */
__SD_SDCLK_DISABLE(hsd->SDx);
__SD_UHS_MODE(hsd->SDx, (hsd->Init.SpeedMode & 0xF));
__SD_SDCLK_ENABLE(hsd->SDx);
}
}
}
}
/* Update bus clock speed */
__SD_CLOCK_DIV_LOW_8BIT(hsd->SDx, (hsd->Init.ClockDiv / 2));
/* Fixed Block Size 512 Byte */
__SD_SET_BLOCK_SIZE(hsd->SDx, 512);
return lu32_ErrState;
}

View File

@ -0,0 +1,613 @@
/*
******************************************************************************
* @file driver_sd_mmc.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2022
* @brief Multi-Media card application HAL module driver.
******************************************************************************
* @attention
*
* Copyright (c) 2022 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/* Private function prototypes -----------------------------------------------*/
static uint32_t __eMMC_PowerON(MMC_HandleTypeDef *hmmc);
static uint32_t __eMMC_InitCard(MMC_HandleTypeDef *hmmc);
static void __MMCCard_GetCardCSD(MMC_HandleTypeDef *hmmc);
static void __MMCCard_GetCardCID(MMC_HandleTypeDef *hmmc);
/************************************************************************************
* @fn eMMC_Init
*
* @brief Initializes the Embedded Multi Media Card.
*
* @param hmmc: Pointer to MMC handle
*/
uint32_t eMMC_Init(MMC_HandleTypeDef *hmmc)
{
uint32_t lu32_ErrState = INT_NO_ERR;
/* eMMC class initialization */
SD_SDMMCClass_Init(hmmc->SDx);
/* Identify card operating voltage */
lu32_ErrState = __eMMC_PowerON(hmmc);
if (lu32_ErrState)
{
return lu32_ErrState;
}
/* Card initialization */
lu32_ErrState = __eMMC_InitCard(hmmc);
if (lu32_ErrState)
{
return lu32_ErrState;
}
/* Get the card information from the CID register */
__MMCCard_GetCardCID(hmmc);
/* Get the card information from the CSD register */
__MMCCard_GetCardCSD(hmmc);
return lu32_ErrState;
}
/************************************************************************************
* @fn eMMC_BusWidth_Select
*
* @brief SDCard 1bit/4bit/8bit bus width select.
*
* @param hmmc: Pointer to MMC handle.
* fu32_BusWidth: bus width. can select MMC_BUS_WIDTH_1BIT.
* MMC_BUS_WIDTH_4BIT.
* MMC_BUS_WIDTH_8BIT.
*/
uint32_t eMMC_BusWidth_Select(MMC_HandleTypeDef *hmmc, uint32_t fu32_BusWidth)
{
uint32_t lu32_ErrState = INT_NO_ERR;
uint32_t fu32_Argument;
/* Access */
fu32_Argument = MMC_CMD6_ACCESS_WRITE_BYTE;
/* Index */
fu32_Argument |= MMC_EX_CSD_INDEX_BUS_WIDTH << 16;
/* Value */
fu32_Argument |= fu32_BusWidth << 8;
/* Send CMD6 SWITCH */
lu32_ErrState = MMC_CMD_Switch(hmmc->SDx, fu32_Argument);
if (lu32_ErrState)
{
return lu32_ErrState;
}
else
{
/* Data line is in use */
while(__SD_GET_PRESENT_STATE(hmmc->SDx) & PreState_DAT_LINE_MASK);
/* Host set bus width */
if (fu32_BusWidth == MMC_BUS_WIDTH_8BIT)
{
/* Enable Bus width 8bit */
__SD_8BIT_WIDTH_ENABLE(hmmc->SDx);
}
else
{
/* Disable Bus width 8bit */
__SD_8BIT_WIDTH_DISABLE(hmmc->SDx);
if (fu32_BusWidth == MMC_BUS_WIDTH_4BIT)
__SD_DATA_WIDTH_4BIT(hmmc->SDx);
else
__SD_DATA_WIDTH_1BIT(hmmc->SDx);
}
}
return lu32_ErrState;
}
/************************************************************************************
* @fn eMMC_ReadBolcks
*
* @brief Reads block(s) from a specified address in a eMMC.
* The Data transfer by polling mode.
*
* @param hsd: Pointer to SD handle.
* fp_Data: pointer to the received dat buffer.
* fu32_BlockAddr: Block Start Address.
* fu16_BlockNum: Number of SD blocks to read.
*/
uint32_t eMMC_ReadBolcks(MMC_HandleTypeDef *hmmc, uint32_t *fp_Data, uint32_t fu32_BlockAddr, uint16_t fu16_BlockNum)
{
int i;
uint32_t lu32_ErrState = INT_NO_ERR;
if (fu16_BlockNum == 0)
return E1_NUM_ERR;
if (fu16_BlockNum == 1)
{
/* SEND CMD17 READ_SINGLI_BLOCK */
lu32_ErrState = MMC_CMD_ReadSingleBlock(hmmc->SDx, fu32_BlockAddr);
if (lu32_ErrState)
return lu32_ErrState;
/* Wait for Buffer Read Ready Int */
while(!(__SD_GET_INT_STATUS(hmmc->SDx) & INT_BUFFER_READ_READY));
/* Clear Buffer_Read_Ready */
__SD_CLR_INT_STATUS(hmmc->SDx, INT_BUFFER_READ_READY);
/* Read one block */
for (i = 0; i < BLOCKSIZE / 4; i++)
{
*fp_Data++ = __SD_GET_BUFFERDATA(hmmc->SDx);
}
}
else
{
/* SEND CMD23 SET_BLOCK_COUNT */
lu32_ErrState = MMC_CMD_SetBlockCount(hmmc->SDx, fu16_BlockNum);
if (lu32_ErrState)
return lu32_ErrState;
/* Set block count */
__SD_SET_BLOCK_COUNT(hmmc->SDx, fu16_BlockNum);
/* SEND CMD18 READ_MULTIPLE_BLOCK */
lu32_ErrState = MMC_CMD_ReadMultiBlock(hmmc->SDx, fu32_BlockAddr);
if (lu32_ErrState)
return lu32_ErrState;
while (fu16_BlockNum--)
{
/* Wait for Buffer_Read_Ready */
while(!(__SD_GET_INT_STATUS(hmmc->SDx) & INT_BUFFER_READ_READY));
/* Clear Buffer_Read_Ready */
__SD_CLR_INT_STATUS(hmmc->SDx, INT_BUFFER_READ_READY);
/* Read one block */
for (i = 0; i < BLOCKSIZE / 4; i++)
{
*fp_Data++ = __SD_GET_BUFFERDATA(hmmc->SDx);
}
}
}
/* wait for transfer complete or any errors occur */
while(!(__SD_GET_INT_STATUS(hmmc->SDx) & (INT_TRANSFER_COMPLETE | INT_ERR_MASK)));
/* Any errors occur */
if (__SD_GET_INT_STATUS(hmmc->SDx) & INT_ERR_MASK)
{
lu32_ErrState = __SD_GET_INT_STATUS(hmmc->SDx) & INT_ERR_MASK;
}
/* clear interrupt status */
__SD_CLR_ALL_INT_STATUS(hmmc->SDx);
return lu32_ErrState;
}
/************************************************************************************
* @fn eMMC_WriteBolcks
*
* @brief Write block(s) from a specified address in a eMMC.
* The Data transfer by polling mode.
*
* @param hsd: Pointer to SD handle.
* fp_Data: pointer to the received dat buffer.
* fu32_BlockAddr: Block Start Address.
* fu16_BlockNum: Number of SD blocks to write.
*/
uint32_t eMMC_WriteBolcks(MMC_HandleTypeDef *hmmc, uint32_t *fp_Data, uint32_t fu32_BlockAddr, uint16_t fu16_BlockNum)
{
int i;
uint32_t lu32_ErrState = INT_NO_ERR;
if (fu16_BlockNum == 0)
return E1_NUM_ERR;
if (fu16_BlockNum == 1)
{
/* SEND CMD24 WRITE_BLOCK */
lu32_ErrState = MMC_CMD_WriteSingleBlock(hmmc->SDx, fu32_BlockAddr);
if (lu32_ErrState)
return lu32_ErrState;
/* Wait for buffer write enable Int */
while(!(__SD_GET_PRESENT_STATE(hmmc->SDx) & PreState_BUFFER_WRITE_EN_MASK));
/* write one block */
for (i = 0; i < BLOCKSIZE / 4; i++)
{
__SD_SET_BUFFERDATA(hmmc->SDx, *fp_Data++);
}
}
else
{
/* SEND CMD23 SET_BLOCK_COUNT */
lu32_ErrState = MMC_CMD_SetBlockCount(hmmc->SDx, fu16_BlockNum);
if (lu32_ErrState)
return lu32_ErrState;
/* Set block count */
__SD_SET_BLOCK_COUNT(hmmc->SDx, fu16_BlockNum);
/* SEND CMD25 WRITE_MULTIPLE_BLOCK */
lu32_ErrState = MMC_CMD_WriteMultiBlock(hmmc->SDx, fu32_BlockAddr);
if (lu32_ErrState)
return lu32_ErrState;
/* First block transfer check the PresentState register */
/* Wait for Buffer_Write_Enable */
while(!(__SD_GET_PRESENT_STATE(hmmc->SDx) & PreState_BUFFER_WRITE_EN_MASK));
/* write one block */
for (i = 0; i < BLOCKSIZE / 4; i++)
{
__SD_SET_BUFFERDATA(hmmc->SDx, *fp_Data++);
}
fu16_BlockNum--;
/* Other block transfer check the StatusInt register */
while(fu16_BlockNum--)
{
/* Wait for Buffer_Write_Ready */
while(!(__SD_GET_INT_STATUS(hmmc->SDx) & INT_BUFFER_WRITE_READY));
/* Clear Buffer_Write_Ready */
__SD_CLR_INT_STATUS(hmmc->SDx, INT_BUFFER_WRITE_READY);
/* write one block */
for (i = 0; i < BLOCKSIZE / 4; i++)
{
__SD_SET_BUFFERDATA(hmmc->SDx, *fp_Data++);
}
}
}
/* wait for transfer complete or any errors occur */
while(!(__SD_GET_INT_STATUS(hmmc->SDx) & (INT_TRANSFER_COMPLETE | INT_ERR_MASK)));
/* Any errors occur */
if (__SD_GET_INT_STATUS(hmmc->SDx) & INT_ERR_MASK)
{
lu32_ErrState = __SD_GET_INT_STATUS(hmmc->SDx) & INT_ERR_MASK;
}
/* clear interrupt status */
__SD_CLR_ALL_INT_STATUS(hmmc->SDx);
return lu32_ErrState;
}
/************************************************************************************
* @fn eMMC_ReadBolcks_SDMA
*
* @brief Reads block(s) from a specified address in a eMMC.
* The Data transfer by SDMA(Simple DMA) mode.
*
* @param hsd: Pointer to SD handle.
* fp_Data: pointer to the received dat buffer.
* fu32_BlockAddr: Block Start Address.
* fu16_BlockNum: Number of SD blocks to read.
*/
uint32_t eMMC_ReadBolcks_SDMA(MMC_HandleTypeDef *hmmc, uint32_t *fp_Data, uint32_t fu32_BlockAddr, uint16_t fu16_BlockNum)
{
int i;
uint32_t lu32_ErrState = INT_NO_ERR;
bool lb_TrfComplete = true;
uint32_t lu32_Addr = (uint32_t)fp_Data;
if (fu16_BlockNum == 0)
return E1_NUM_ERR;
/* SEND CMD23 SET_BLOCK_COUNT */
lu32_ErrState = MMC_CMD_SetBlockCount(hmmc->SDx, fu16_BlockNum);
if (lu32_ErrState)
return lu32_ErrState;
/* set SDMA system Address */
__SD_SET_SDMA_SYSTEM_ADDR(hmmc->SDx, (uint32_t)fp_Data);
/* Set block count */
__SD_SET_BLOCK_COUNT(hmmc->SDx, fu16_BlockNum);
/* SEND CMD18 READ_MULTIPLE_BLOCK */
lu32_ErrState = MMC_CMD_ReadBlock_SDMA(hmmc->SDx, fu32_BlockAddr);
if (lu32_ErrState)
return lu32_ErrState;
/* Address alignment */
lu32_Addr &= SDMA_ADDR_ALIGN_MASK;
/* wait for transfer complete or any errors occur */
while (lb_TrfComplete)
{
if (__SD_GET_INT_STATUS(hmmc->SDx) & (INT_TRANSFER_COMPLETE | INT_ERR_MASK))
{
lb_TrfComplete = false;
}
if (__SD_GET_INT_STATUS(hmmc->SDx) & INT_DMA_INT)
{
__SD_CLR_INT_STATUS(hmmc->SDx, INT_DMA_INT);
/* SDMA system Address alignment increases */
lu32_Addr += SDMA_ADDR_UNIT;
/* Update SDMA system Address */
__SD_SET_SDMA_SYSTEM_ADDR(hmmc->SDx, (uint32_t)lu32_Addr);
}
}
/* Any errors occur */
if (__SD_GET_INT_STATUS(hmmc->SDx) & INT_ERR_MASK)
{
lu32_ErrState = __SD_GET_INT_STATUS(hmmc->SDx) & INT_ERR_MASK;
}
/* clear interrupt status */
__SD_CLR_ALL_INT_STATUS(hmmc->SDx);
return lu32_ErrState;
}
/************************************************************************************
* @fn eMMC_WriteBolcks_SDMA
*
* @brief Write block(s) from a specified address in a eMMC.
* The Data transfer by SDMA(Simple DMA) mode.
*
* @param hsd: Pointer to SD handle.
* fp_Data: pointer to the received dat buffer.
* fu32_BlockAddr: Block Start Address.
* fu16_BlockNum: Number of SD blocks to write.
*/
uint32_t eMMC_WriteBolcks_SDMA(MMC_HandleTypeDef *hmmc, uint32_t *fp_Data, uint32_t fu32_BlockAddr, uint16_t fu16_BlockNum)
{
int i;
uint32_t lu32_ErrState = INT_NO_ERR;
bool lb_TrfComplete = true;
uint32_t lu32_Addr = (uint32_t)fp_Data;
if (fu16_BlockNum == 0)
return E1_NUM_ERR;
/* SEND CMD23 SET_BLOCK_COUNT */
lu32_ErrState = MMC_CMD_SetBlockCount(hmmc->SDx, fu16_BlockNum);
if (lu32_ErrState)
return lu32_ErrState;
/* set SDMA system Address */
__SD_SET_SDMA_SYSTEM_ADDR(hmmc->SDx, (uint32_t)fp_Data);
/* Set block count */
__SD_SET_BLOCK_COUNT(hmmc->SDx, fu16_BlockNum);
/* SEND CMD25 WRITE_MULTIPLE_BLOCK */
lu32_ErrState = MMC_CMD_WriteBlock_SDMA(hmmc->SDx, fu32_BlockAddr);
if (lu32_ErrState)
return lu32_ErrState;
/* Address alignment */
lu32_Addr &= SDMA_ADDR_ALIGN_MASK;
/* wait for transfer complete or any errors occur */
while (lb_TrfComplete)
{
if (__SD_GET_INT_STATUS(hmmc->SDx) & (INT_TRANSFER_COMPLETE | INT_ERR_MASK))
{
lb_TrfComplete = false;
}
if (__SD_GET_INT_STATUS(hmmc->SDx) & INT_DMA_INT)
{
__SD_CLR_INT_STATUS(hmmc->SDx, INT_DMA_INT);
/* SDMA system Address alignment increases */
lu32_Addr += SDMA_ADDR_UNIT;
/* Update SDMA system Address */
__SD_SET_SDMA_SYSTEM_ADDR(hmmc->SDx, (uint32_t)lu32_Addr);
}
}
/* Any errors occur */
if (__SD_GET_INT_STATUS(hmmc->SDx) & INT_ERR_MASK)
{
lu32_ErrState = __SD_GET_INT_STATUS(hmmc->SDx) & INT_ERR_MASK;
}
/* clear interrupt status */
__SD_CLR_ALL_INT_STATUS(hmmc->SDx);
return lu32_ErrState;
}
/************************************************************************************
* @fn MMCCard_GetCardCSD
*
* @brief Get the card information from the CSD register.
*/
static void __MMCCard_GetCardCSD(MMC_HandleTypeDef *hmmc)
{
hmmc->CSDInfo = (MMC_CardCSDTypeDef *)hmmc->CSD;
/* Card memory capacity, unit KByte */
hmmc->CardInfo.MemoryCapacity = hmmc->ExCSDInfo.SEC_COUNT / 2;
/* Card command class */
hmmc->CardInfo.Class = hmmc->CSDInfo->CCC;
}
/************************************************************************************
* @fn __MMCCard_GetCardCID
*
* @brief Get the card information from the CID register.
*/
static void __MMCCard_GetCardCID(MMC_HandleTypeDef *hmmc)
{
hmmc->CIDInfo = (MMC_CardCIDTypeDef *)hmmc->CID;
}
/************************************************************************************
* @fn __eMMC_PowerON
*
* @brief Enquires cards about their operating voltage and configures clock ontrols.
*/
static uint32_t __eMMC_PowerON(MMC_HandleTypeDef *hmmc)
{
uint32_t lu32_ErrState = INT_NO_ERR;
bool lb_BusyStatus = false;
/* CMD0: GO_IDLE_STATE */
lu32_ErrState = MMC_CMD_GoIdleState(hmmc->SDx);
if(lu32_ErrState)
{
return lu32_ErrState;
}
while (lb_BusyStatus == false)
{
/* SEND CMD1 SEND_OP_COND with eMMC_DUAL_VOLTAGE_RANGE(0xC0FF8080U) as argument */
lu32_ErrState = MMC_CMD_SendOperCondition(hmmc->SDx, eMMC_DUAL_VOLTAGE_RANGE, &hmmc->OCR);
if(lu32_ErrState)
{
return lu32_ErrState;
}
lb_BusyStatus = hmmc->OCR & OCR_BUSY ? true : false;
}
hmmc->CardInfo.CardType = 0;
/* After power routine and command returns valid voltage */
if (hmmc->OCR & eMMC_DUAL_VOLTAGE_CARD)
{
/* Voltage range of the card is within 1.70V ~ 1.95V or 2.7V ~ 3.6V */
hmmc->CardInfo.CardType = eMMC_DUAL_VOLTAGE_CARD;
}
if (hmmc->OCR & eMMC_CAPACITY_HIGHER_2G)
{
/* Capacity > 2G, sector mode */
hmmc->CardInfo.CardType |= eMMC_CAPACITY_HIGHER_2G;
}
return lu32_ErrState;
}
/************************************************************************************
* @fn __eMMC_InitCard
*
* @brief Initializes the sd card.
*/
static uint32_t __eMMC_InitCard(MMC_HandleTypeDef *hmmc)
{
uint32_t lu32_ErrState = INT_NO_ERR;
uint32_t lu32_Response, lu32_TempValue;
/* CMD2: ALL_SEND_CID */
lu32_ErrState = MMC_CMD_AllSendCID(hmmc->SDx, hmmc->CID);
if (lu32_ErrState)
{
return lu32_ErrState;
}
/* CMD3: SET_RELATIVE_ADDR */
hmmc->RCA = 0xF1170000;
lu32_ErrState = MMC_CMD_SetRelAddr(hmmc->SDx, hmmc->RCA);
if (lu32_ErrState)
{
return lu32_ErrState;
}
/* After CMD3, Bus select push-pull mode */
__SD_MMC_OD_PP(hmmc->SDx, 1);
/* CMD9: SEND_CSD */
lu32_ErrState = MMC_CMD_SendCSD(hmmc->SDx, hmmc->RCA, hmmc->CSD);
if (lu32_ErrState)
{
return lu32_ErrState;
}
/* CMD7: SEL_DESEL_CARD */
lu32_ErrState = MMC_CMD_SelectCard(hmmc->SDx, hmmc->RCA);
if (lu32_ErrState)
{
return lu32_ErrState;
}
/* Wait to enter transfer state */
uint32_t lu32_Timeout = 100;
while (lu32_Timeout--)
{
/* CMD13: SEND_STATUS */
lu32_ErrState = SD_CMD_SendStatus(hmmc->SDx, hmmc->RCA, &lu32_Response);
if (lu32_ErrState)
{
return lu32_ErrState;
}
if (lu32_Response & CARD_CURRENT_STATE_TRAN)
break;
}
/* CMD8: SEND_EXT_CSD */
lu32_ErrState = MMC_CMD_SendExtendedCSD(hmmc->SDx);
if (lu32_ErrState)
{
return lu32_ErrState;
}
/* Wait for Buffer Read Ready Int */
while(!(__SD_GET_INT_STATUS(hmmc->SDx) & INT_BUFFER_READ_READY));
/* Clear Buffer_Read_Ready */
__SD_CLR_INT_STATUS(hmmc->SDx, INT_BUFFER_READ_READY);
/* Read one block */
for (int i = 0; i < BLOCKSIZE / 4; i++)
{
lu32_TempValue = __SD_GET_BUFFERDATA(hmmc->SDx);
/* Extract Parameter */
switch (i)
{
case MMC_EX_CSD_INDEX_SEC_COUNT0 / 4:
{ /* Byte 212,213,214,215 */
hmmc->ExCSDInfo.SEC_COUNT = lu32_TempValue;
}break;
case MMC_EX_CSD_INDEX_BUS_WIDTH / 4:
{ /* Byte 183 */
hmmc->ExCSDInfo.BUS_WIDTH = lu32_TempValue >> 24 & 0xFF;
}break;
case MMC_EX_CSD_INDEX_HS_TIMING / 4:
{ /* Byte 185 */
hmmc->ExCSDInfo.HS_TIMING = lu32_TempValue >> 8 & 0xFF;
}break;
case MMC_EX_CSD_INDEX_EXT_CSD_REV / 4:
{ /* Byte 192 */
hmmc->ExCSDInfo.EXT_CSD_REV = lu32_TempValue & 0xFF;
}break;
case MMC_EX_CSD_INDEX_DEVICE_TYPE / 4:
{ /* Byte 196 */
hmmc->ExCSDInfo.DEVICE_TYPE = lu32_TempValue & 0xFF;
}break;
default: break;
}
}
/* wait for transfer complete or any errors occur */
while(!(__SD_GET_INT_STATUS(hmmc->SDx) & (INT_TRANSFER_COMPLETE | INT_ERR_MASK)));
/* Any errors occur */
if (__SD_GET_INT_STATUS(hmmc->SDx) & INT_ERR_MASK)
{
lu32_ErrState = __SD_GET_INT_STATUS(hmmc->SDx) & INT_ERR_MASK;
}
/* clear interrupt status */
__SD_CLR_ALL_INT_STATUS(hmmc->SDx);
/* Update bus clock speed */
__SD_CLOCK_DIV_LOW_8BIT(hmmc->SDx, (hmmc->Init.ClockDiv / 2));
return lu32_ErrState;
}

View File

@ -0,0 +1,323 @@
/*
******************************************************************************
* @file driver_sha.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2022
* @brief IIR module driver.
* This file provides firmware functions to manage the
* SEC SHA peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
static uint8_t Context[128]; /* orignal data save buffer */
static uint16_t ContextIndex = 0;
static uint64_t TotalBits512[2];
static uint64_t TotalBits256;
/*********************************************************************
* @fn sha_init
*
* @brief SHA256 initialization procedure
*
* @param mode : SHA mode select
*/
void sha_init(enum_sha_mode_t fe_Mode)
{
SEC_SHA->SHA_CTRL.Bits.MODE = fe_Mode;
SEC_SHA->SHA_CTRL.Bits.ENDIAN_MODE = SHA_BIG_ENDIAN;
SEC_SHA->SHA_CTRL.Bits.ISR_EN = 1;
SEC_SHA->SHA_CTRL.Bits.INIT_EN = 1;
/*verity initialize*/
TotalBits256 = 0;
TotalBits512[0] = 0;
TotalBits512[1] = 0;
ContextIndex = 0;
}
static void __sha_updata_256(uint8_t *fp8_Data, uint32_t fu32_Size);
static void __sha_updata_512(uint8_t *fp8_Data, uint32_t fu32_Size);
/*********************************************************************
* @fn sha_update
*
* @brief SHA update procedure.
*
* @param fp8_Data : message to hash.
* @param fu32_Size: length of message to hash.
*/
void sha_update(uint8_t *fp8_Data, uint32_t fu32_Size)
{
if(SEC_SHA->SHA_CTRL.Bits.MODE >= SHA_512)
{
__sha_updata_512(fp8_Data, fu32_Size);
}
else
{
__sha_updata_256(fp8_Data, fu32_Size);
}
}
/*********************************************************************
* @fn sha_final
*
* @brief SHA Final calculation result
*
* @param DataOut : SHA calculation result buffer.
*/
void sha_final(uint8_t *DataOut)
{
uint32_t *DataIn = NULL;
/*sha512 or sha384 or sha512/256 or sha512/224*/
if(SEC_SHA->SHA_CTRL.Bits.MODE >= SHA_512)
{
if((TotalBits512[0] == 0) && (TotalBits512[1] == 0)) return;
uint32_t LeftBits = (ContextIndex << 3);
if(LeftBits == 0)
{
Context[0] = 0x80;
memset(&Context[1], 0, (SHA_512_BLOCK_SIZE - 1 - 16));
Context[SHA_512_BLOCK_SIZE - 1] = (uint8_t) TotalBits512[0];
Context[SHA_512_BLOCK_SIZE - 2] = (uint8_t) (TotalBits512[0] >> 8);
Context[SHA_512_BLOCK_SIZE - 3] = (uint8_t) (TotalBits512[0] >> 16);
Context[SHA_512_BLOCK_SIZE - 4] = (uint8_t) (TotalBits512[0] >> 24);
Context[SHA_512_BLOCK_SIZE - 5] = (uint8_t) (TotalBits512[0] >> 32);
Context[SHA_512_BLOCK_SIZE - 6] = (uint8_t) (TotalBits512[0] >> 40);
Context[SHA_512_BLOCK_SIZE - 7] = (uint8_t) (TotalBits512[0] >> 48);
Context[SHA_512_BLOCK_SIZE - 8] = (uint8_t) (TotalBits512[0] >> 56);
Context[SHA_512_BLOCK_SIZE - 9] = (uint8_t) TotalBits512[1];
Context[SHA_512_BLOCK_SIZE - 10] = (uint8_t) (TotalBits512[1] >> 8);
Context[SHA_512_BLOCK_SIZE - 11] = (uint8_t) (TotalBits512[1] >> 16);
Context[SHA_512_BLOCK_SIZE - 12] = (uint8_t) (TotalBits512[1] >> 24);
Context[SHA_512_BLOCK_SIZE - 13] = (uint8_t) (TotalBits512[1] >> 32);
Context[SHA_512_BLOCK_SIZE - 14] = (uint8_t) (TotalBits512[1] >> 40);
Context[SHA_512_BLOCK_SIZE - 15] = (uint8_t) (TotalBits512[1] >> 48);
Context[SHA_512_BLOCK_SIZE - 16] = (uint8_t) (TotalBits512[1] >> 56);
}
else if(LeftBits >= 896)
{
Context[ContextIndex++] = 0x80;
memset(&Context[ContextIndex], 0, (SHA_512_BLOCK_SIZE - ContextIndex));
DataIn = (uint32_t *)Context;
for(uint32_t i=0; i<16;i++)
{
SEC_SHA->DATA_1[i] = DataIn[i];
SEC_SHA->DATA_2[i] = DataIn[i + 16];
}
SEC_SHA->SHA_CTRL.Bits.CALCULATE = 1;
while(SEC_SHA->SHA_INT_STATE.Bits.INT_DONE == 0);
SEC_SHA->SHA_INT_STATE.Bits.INT_DONE = 0;
/*one more need to process*/
memset(&Context[0], 0, (SHA_512_BLOCK_SIZE - 16));
Context[SHA_512_BLOCK_SIZE - 1] = (uint8_t) TotalBits512[0];
Context[SHA_512_BLOCK_SIZE - 2] = (uint8_t) (TotalBits512[0] >> 8);
Context[SHA_512_BLOCK_SIZE - 3] = (uint8_t) (TotalBits512[0] >> 16);
Context[SHA_512_BLOCK_SIZE - 4] = (uint8_t) (TotalBits512[0] >> 24);
Context[SHA_512_BLOCK_SIZE - 5] = (uint8_t) (TotalBits512[0] >> 32);
Context[SHA_512_BLOCK_SIZE - 6] = (uint8_t) (TotalBits512[0] >> 40);
Context[SHA_512_BLOCK_SIZE - 7] = (uint8_t) (TotalBits512[0] >> 48);
Context[SHA_512_BLOCK_SIZE - 8] = (uint8_t) (TotalBits512[0] >> 56);
Context[SHA_512_BLOCK_SIZE - 9] = (uint8_t) TotalBits512[1];
Context[SHA_512_BLOCK_SIZE - 10] = (uint8_t) (TotalBits512[1] >> 8);
Context[SHA_512_BLOCK_SIZE - 11] = (uint8_t) (TotalBits512[1] >> 16);
Context[SHA_512_BLOCK_SIZE - 12] = (uint8_t) (TotalBits512[1] >> 24);
Context[SHA_512_BLOCK_SIZE - 13] = (uint8_t) (TotalBits512[1] >> 32);
Context[SHA_512_BLOCK_SIZE - 14] = (uint8_t) (TotalBits512[1] >> 40);
Context[SHA_512_BLOCK_SIZE - 15] = (uint8_t) (TotalBits512[1] >> 48);
Context[SHA_512_BLOCK_SIZE - 16] = (uint8_t) (TotalBits512[1] >> 56);
}
else
{
Context[ContextIndex++] = 0x80;
memset(&Context[ContextIndex], 0, (SHA_512_BLOCK_SIZE - ContextIndex - 16));
Context[SHA_512_BLOCK_SIZE - 1] = (uint8_t) TotalBits512[0];
Context[SHA_512_BLOCK_SIZE - 2] = (uint8_t) (TotalBits512[0] >> 8);
Context[SHA_512_BLOCK_SIZE - 3] = (uint8_t) (TotalBits512[0] >> 16);
Context[SHA_512_BLOCK_SIZE - 4] = (uint8_t) (TotalBits512[0] >> 24);
Context[SHA_512_BLOCK_SIZE - 5] = (uint8_t) (TotalBits512[0] >> 32);
Context[SHA_512_BLOCK_SIZE - 6] = (uint8_t) (TotalBits512[0] >> 40);
Context[SHA_512_BLOCK_SIZE - 7] = (uint8_t) (TotalBits512[0] >> 48);
Context[SHA_512_BLOCK_SIZE - 8] = (uint8_t) (TotalBits512[0] >> 56);
Context[SHA_512_BLOCK_SIZE - 9] = (uint8_t) TotalBits512[1];
Context[SHA_512_BLOCK_SIZE - 10] = (uint8_t) (TotalBits512[1] >> 8);
Context[SHA_512_BLOCK_SIZE - 11] = (uint8_t) (TotalBits512[1] >> 16);
Context[SHA_512_BLOCK_SIZE - 12] = (uint8_t) (TotalBits512[1] >> 24);
Context[SHA_512_BLOCK_SIZE - 13] = (uint8_t) (TotalBits512[1] >> 32);
Context[SHA_512_BLOCK_SIZE - 14] = (uint8_t) (TotalBits512[1] >> 40);
Context[SHA_512_BLOCK_SIZE - 15] = (uint8_t) (TotalBits512[1] >> 48);
Context[SHA_512_BLOCK_SIZE - 16] = (uint8_t) (TotalBits512[1] >> 56);
}
DataIn = (uint32_t *)Context;
for(uint32_t i=0; i<16;i++)
{
SEC_SHA->DATA_1[i] = DataIn[i];
SEC_SHA->DATA_2[i] = DataIn[i + 16];
}
/*start to calculate the last package data*/
SEC_SHA->SHA_CTRL.Bits.CALCULATE = 1;
while(SEC_SHA->SHA_INT_STATE.Bits.INT_DONE == 0);
SEC_SHA->SHA_INT_STATE.Bits.INT_DONE = 0;
}
else /*sha256 or sha1 or sha224*/
{
if(TotalBits256 == 0) return;
uint32_t LeftBits = (ContextIndex << 3);
if(LeftBits == 0)
{
Context[0] = 0x80;
memset(&Context[1], 0, (SHA_256_BLOCK_SIZE - 1 - 8));
Context[SHA_256_BLOCK_SIZE - 1] = (uint8_t) TotalBits256;
Context[SHA_256_BLOCK_SIZE - 2] = (uint8_t) (TotalBits256 >> 8);
Context[SHA_256_BLOCK_SIZE - 3] = (uint8_t) (TotalBits256 >> 16);
Context[SHA_256_BLOCK_SIZE - 4] = (uint8_t) (TotalBits256 >> 24);
Context[SHA_256_BLOCK_SIZE - 5] = (uint8_t) (TotalBits256 >> 32);
Context[SHA_256_BLOCK_SIZE - 6] = (uint8_t) (TotalBits256 >> 40);
Context[SHA_256_BLOCK_SIZE - 7] = (uint8_t) (TotalBits256 >> 48);
Context[SHA_256_BLOCK_SIZE - 8] = (uint8_t) (TotalBits256 >> 56);
}
else if(LeftBits >= 448)
{
Context[ContextIndex++] = 0x80;
memset(&Context[ContextIndex], 0, (SHA_256_BLOCK_SIZE - ContextIndex));
DataIn = (uint32_t *)Context;
for(uint32_t i=0; i<16;i++)
{
SEC_SHA->DATA_1[i] = DataIn[i];
}
SEC_SHA->SHA_CTRL.Bits.CALCULATE = 1;
while(SEC_SHA->SHA_INT_STATE.Bits.INT_DONE == 0);
SEC_SHA->SHA_INT_STATE.Bits.INT_DONE = 0;
/*one more need to process*/
memset(&Context[0], 0, (SHA_256_BLOCK_SIZE - 8));
Context[SHA_256_BLOCK_SIZE - 1] = (uint8_t) TotalBits256;
Context[SHA_256_BLOCK_SIZE - 2] = (uint8_t) (TotalBits256 >> 8);
Context[SHA_256_BLOCK_SIZE - 3] = (uint8_t) (TotalBits256 >> 16);
Context[SHA_256_BLOCK_SIZE - 4] = (uint8_t) (TotalBits256 >> 24);
Context[SHA_256_BLOCK_SIZE - 5] = (uint8_t) (TotalBits256 >> 32);
Context[SHA_256_BLOCK_SIZE - 6] = (uint8_t) (TotalBits256 >> 40);
Context[SHA_256_BLOCK_SIZE - 7] = (uint8_t) (TotalBits256 >> 48);
Context[SHA_256_BLOCK_SIZE - 8] = (uint8_t) (TotalBits256 >> 56);
}
else
{
Context[ContextIndex++] = 0x80;
memset(&Context[ContextIndex], 0, (SHA_256_BLOCK_SIZE - ContextIndex - 8));
Context[SHA_256_BLOCK_SIZE - 1] = (uint8_t) TotalBits256;
Context[SHA_256_BLOCK_SIZE - 2] = (uint8_t) (TotalBits256 >> 8);
Context[SHA_256_BLOCK_SIZE - 3] = (uint8_t) (TotalBits256 >> 16);
Context[SHA_256_BLOCK_SIZE - 4] = (uint8_t) (TotalBits256 >> 24);
Context[SHA_256_BLOCK_SIZE - 5] = (uint8_t) (TotalBits256 >> 32);
Context[SHA_256_BLOCK_SIZE - 6] = (uint8_t) (TotalBits256 >> 40);
Context[SHA_256_BLOCK_SIZE - 7] = (uint8_t) (TotalBits256 >> 48);
Context[SHA_256_BLOCK_SIZE - 8] = (uint8_t) (TotalBits256 >> 56);
}
DataIn = (uint32_t *)Context;
for(uint32_t i=0; i<16;i++)
{
SEC_SHA->DATA_1[i] = DataIn[i];
}
/*start to calculate the last package data*/
SEC_SHA->SHA_CTRL.Bits.CALCULATE = 1;
while(SEC_SHA->SHA_INT_STATE.Bits.INT_DONE == 0);
SEC_SHA->SHA_INT_STATE.Bits.INT_DONE = 0;
}
uint32_t LastDigest[16];
memset(&LastDigest, 0, 64);
/*data out*/
if(SEC_SHA->SHA_CTRL.Bits.MODE >= SHA_512)
{
for(uint32_t i=0;i<8;i++)
{
LastDigest[2*i] = SEC_SHA->HASH_VAL_H[i];
LastDigest[2*i + 1] = SEC_SHA->HASH_VAL_L[i];
*(DataOut++) = (uint8_t)(LastDigest[2*i] >> 24);
*(DataOut++) = (uint8_t)(LastDigest[2*i] >> 16);
*(DataOut++) = (uint8_t)(LastDigest[2*i] >> 8);
*(DataOut++) = (uint8_t)(LastDigest[2*i]);
*(DataOut++) = (uint8_t)(LastDigest[2*i + 1] >> 24);
*(DataOut++) = (uint8_t)(LastDigest[2*i + 1] >> 16);
*(DataOut++) = (uint8_t)(LastDigest[2*i + 1] >> 8);
*(DataOut++) = (uint8_t)(LastDigest[2*i + 1]);
}
}
else
{
for(uint32_t i=0;i<8;i++)
{
LastDigest[i] = SEC_SHA->HASH_VAL_L[i];
*(DataOut++) = (uint8_t)(LastDigest[i] >> 24);
*(DataOut++) = (uint8_t)(LastDigest[i] >> 16);
*(DataOut++) = (uint8_t)(LastDigest[i] >> 8);
*(DataOut++) = (uint8_t)(LastDigest[i]);
}
}
}
static void __sha_updata_256(uint8_t *fp8_Data, uint32_t fu32_Size)
{
/*total bits add*/
TotalBits256 += (fu32_Size << 3);
while(fu32_Size-- > 0)
{
Context[ContextIndex++] = *(fp8_Data++);
if(ContextIndex >= SHA_256_BLOCK_SIZE)
{
ContextIndex = 0;
uint32_t *DataIn = (uint32_t *)Context;
for(uint32_t i=0; i<16;i++)
{
SEC_SHA->DATA_1[i] = DataIn[i];
}
SEC_SHA->SHA_CTRL.Bits.CALCULATE = 1;
while(SEC_SHA->SHA_INT_STATE.Bits.INT_DONE == 0);
SEC_SHA->SHA_INT_STATE.Bits.INT_DONE = 0;
}
}
}
static void __sha_updata_512(uint8_t *fp8_Data, uint32_t fu32_Size)
{
TotalBits512[0] += (fu32_Size << 3);
if(TotalBits512[0] < (uint64_t)(fu32_Size << 3) ) {
TotalBits512[1]++;
}
while(fu32_Size-- > 0)
{
Context[ContextIndex++] = *(fp8_Data++);
if(ContextIndex >= SHA_512_BLOCK_SIZE)
{
ContextIndex = 0;
uint32_t *DataIn = (uint32_t *)Context;
for(uint32_t i=0; i<16;i++)
{
SEC_SHA->DATA_1[i] = DataIn[i];
SEC_SHA->DATA_2[i] = DataIn[i + 16];
}
SEC_SHA->SHA_CTRL.Bits.CALCULATE = 1;
while(SEC_SHA->SHA_INT_STATE.Bits.INT_DONE == 0);
SEC_SHA->SHA_INT_STATE.Bits.INT_DONE = 0;
}
}
}

View File

@ -0,0 +1,240 @@
/*
******************************************************************************
* @file driver_spdif.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2023
* @brief SPDIF module driver.
* This file provides firmware functions to manage the
* SPDIF peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2023 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/******************************************************************************
* @fn SPDIF_IRQHandler
*
* @brief spdif handle function in spdif isr
*
* @param hspdif : spdif handle
*/
void SPDIF_IRQHandler(SPDIF_HandleTypeDef *hspdif)
{
if(__SPDIF_IS_INT_ALEMPTY())
{
if((__SPDIF_GET_INT_STATUS() & ALEMPTY_FLAG))
{
while(__SPDIF_GET_INT_STATUS() & FULL_FLAG)
{
SPDIF->SPDIF_FIFO_DATA = hspdif->p_TxData[ hspdif->u32_TxCount++];
if(hspdif->u32_TxCount >= hspdif->u32_TxSize)
{
__SPDIF_DISABLE_ALEMPTY_INT();
hspdif->b_TxBusy = false;
if(hspdif->TxCallback)
{
hspdif->TxCallback(hspdif);
}
break;
}
}
}
}
if(__SPDIF_IS_INT_ALFULL())
{
if(__SPDIF_GET_INT_STATUS() & ALFULL_FLAG)
{
while(!(__SPDIF_GET_INT_STATUS() & EMPTY_FLAG))
{
hspdif->p_RxData[hspdif->u32_RxCount++] = SPDIF->SPDIF_FIFO_DATA;
}
}
}
if(__SPDIF_IS_INT_SYNCERR())
{
if(__SPDIF_GET_INT_STATUS() & SYNCERR_FLAG)
{
while(!(__SPDIF_GET_INT_STATUS() & EMPTY_FLAG))
{
hspdif->p_RxData[hspdif->u32_RxCount++] = SPDIF->SPDIF_FIFO_DATA;
}
hspdif->b_RxBusy = false;
__SPDIF_DISABLE_ALFULL_INT();
if(hspdif->RxCallback)
{
hspdif->RxCallback(hspdif);
}
}
}
}
/******************************************************************************
* @fn spdif_init
*
* @brief Initialize the SPDIF according to the specified parameters
* in the SPDIF_HandleTypeDef
*
* @param hspdif : spdif handle
*/
void spdif_init(SPDIF_HandleTypeDef *hspdif)
{
SPDIF->SPDIF_CTRL.TSAMPLERATE = hspdif->Init.TxSampleRate;
SPDIF->SPDIF_CTRL.CHANNEL_MODE = hspdif->Init.CH_Mode;
SPDIF->SPDIF_CTRL.CLK_ENABLE = 0;
SPDIF->SPDIF_CTRL.FIFO_ENABLE = 1;
SPDIF->SPDIF_CTRL.SFR_ENABLE = 1;
SPDIF->SPDIF_CTRL.PARITYGEN = 1;
SPDIF->SPDIF_CTRL.DUPLICATE = 1;
SPDIF->SPDIF_CTRL.SETPREAMBB = 1;
SPDIF->SPDIF_CTRL.INTREQ_MASK = 1;
__SPDIF_FIFO_HALF_FULL_LEVEL(hspdif->Init.HALFIFOFull_Threshold);
__SPDIF_FIFO_ALMOST_EMPTY_LEVEL(hspdif->Init.ALFIFOEmpty_Threshold);
}
/******************************************************************************
* @fn spdif_msg_send
*
* @brief spdif send message
*
* @param hspdif : spdif handle
* fp_Data : send data pointer
* fu32_Size : send data size
*/
bool spdif_msg_send(SPDIF_HandleTypeDef *hspdif, uint32_t *fp_Data, uint32_t fu32_Size)
{
if (fu32_Size == 0) return false;
if (hspdif->b_TxBusy) return false;
if (hspdif->b_RxBusy) return false;
__SPDIF_DISABLE();
hspdif->b_TxBusy = 1;
__SPDIF_Tx_MODE();
__SPDIF_ENABLE();
while(fu32_Size)
{
while(__SPDIF_GET_INT_STATUS() & FULL_FLAG);
SPDIF->SPDIF_FIFO_DATA = *fp_Data++;
fu32_Size--;
}
while(!(__SPDIF_GET_INT_STATUS() & UNDERR_FLAG));
hspdif->b_TxBusy = 0;
return true;
}
/******************************************************************************
* @fn spdif_msg_receive
*
* @brief spdif receive message
*
* @param hspdif : spdif handle
* fp_Data : the receive data buffer
*/
bool spdif_msg_receive(SPDIF_HandleTypeDef *hspdif, uint32_t *fp_Data)
{
if (hspdif->b_TxBusy) return false;
if (hspdif->b_RxBusy) return false;
__SPDIF_DISABLE();
hspdif->b_RxBusy = 1;
__SPDIF_Rx_MODE();
__SPDIF_ENABLE();
while(1)
{
if(!(__SPDIF_GET_INT_STATUS() & EMPTY_FLAG))
{
*fp_Data++ = SPDIF->SPDIF_FIFO_DATA;
}
if(__SPDIF_GET_INT_STATUS() & SYNCERR_FLAG)
{
break;
}
}
hspdif->b_RxBusy = 0;
return true;
}
/******************************************************************************
* @fn spdif_msg_send_IT
*
* @brief spdif send message with isr
*
* @param hspdif : spdif handle
* fp_Data : send data pointer
* fu32_Size : send data size
*/
bool spdif_msg_send_IT(SPDIF_HandleTypeDef *hspdif, uint32_t *fp_Data, uint32_t fu32_Size)
{
if (fu32_Size == 0) return false;
if (hspdif->b_TxBusy) return false;
if (hspdif->b_RxBusy) return false;
hspdif->u32_TxSize = fu32_Size;
hspdif->u32_TxCount = 0;
hspdif->p_TxData = fp_Data;
hspdif->b_TxBusy = 1;
__SPDIF_Tx_MODE();
__SPDIF_ENABLE();
__SPDIF_ENABLE_ALEMPTY_INT();
return true;
}
/******************************************************************************
* @fn spdif_msg_receive_IT
*
* @brief spdif receive message with isr
*
* @param hspdif : spdif handle
* fp_Data : the receive data buffer
*/
bool spdif_msg_receive_IT(SPDIF_HandleTypeDef *hspdif, uint32_t *fp_Data)
{
if (hspdif->b_TxBusy) return false;
if (hspdif->b_RxBusy) return false;
hspdif->p_RxData = fp_Data;
hspdif->b_RxBusy = 1;
hspdif->u32_RxCount = 0;
__SPDIF_Tx_MODE();
__SPDIF_ENABLE();
__SPDIF_ENABLE_ALFULL_INT();
return true;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,513 @@
/*
******************************************************************************
* @file driver_spi_slave.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief SPI module driver.
* This file provides firmware functions to manage the
* Serial Peripheral Interface (SPI) peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "driver_spi.h"
static void spi_slave_tx_u8(SPI_HandleTypeDef *hspi)
{
while(!__SPI_IS_TxFIFO_FULL(hspi->SPIx))
{
hspi->SPIx->DR = hspi->u_TxData.p_u8[hspi->u32_TxCount++];
if (hspi->u32_TxCount >= hspi->u32_TxSize)
{
break;
}
}
}
static void spi_slave_tx_u16(SPI_HandleTypeDef *hspi)
{
while(!__SPI_IS_TxFIFO_FULL(hspi->SPIx))
{
hspi->SPIx->DR = hspi->u_TxData.p_u16[hspi->u32_TxCount++];
if (hspi->u32_TxCount >= hspi->u32_TxSize)
{
break;
}
}
}
static void spi_slave_tx_u32(SPI_HandleTypeDef *hspi)
{
while(!__SPI_IS_TxFIFO_FULL(hspi->SPIx))
{
hspi->SPIx->DR = hspi->u_TxData.p_u32[hspi->u32_TxCount++];
if (hspi->u32_TxCount >= hspi->u32_TxSize)
{
break;
}
}
}
static void spi_slave_rx_u8(SPI_HandleTypeDef *hspi)
{
while (!__SPI_IS_RxFIFO_EMPTY(hspi->SPIx))
{
hspi->u_RxData.p_u8[hspi->u32_RxCount++] = hspi->SPIx->DR;
if (hspi->u32_RxCount >= hspi->u32_RxSize)
{
break;
}
}
}
static void spi_slave_rx_u16(SPI_HandleTypeDef *hspi)
{
while (!__SPI_IS_RxFIFO_EMPTY(hspi->SPIx))
{
hspi->u_RxData.p_u16[hspi->u32_RxCount++] = hspi->SPIx->DR;
if (hspi->u32_RxCount >= hspi->u32_RxSize)
{
break;
}
}
}
static void spi_slave_rx_u32(SPI_HandleTypeDef *hspi)
{
while (!__SPI_IS_RxFIFO_EMPTY(hspi->SPIx))
{
hspi->u_RxData.p_u32[hspi->u32_RxCount++] = hspi->SPIx->DR;
if (hspi->u32_RxCount >= hspi->u32_RxSize)
{
break;
}
}
}
/************************************************************************************
* @fn spi_slave_IRQHandler
*
* @brief Handle SPI interrupt request.
*
* @param hspi: SPI handle.
*/
void spi_slave_IRQHandler(SPI_HandleTypeDef *hspi)
{
uint8_t frame_size;
/* Tx FIFO Threshold EMPTY */
if (__SPI_TxFIFO_EMPTY_INT_STATUS(hspi->SPIx))
{
frame_size = hspi->Init.Frame_Size;
if(frame_size <= SPI_FRAME_SIZE_8BIT)
{
spi_slave_tx_u8(hspi);
}
else if(frame_size <= SPI_FRAME_SIZE_16BIT)
{
spi_slave_tx_u16(hspi);
}
else
{
spi_slave_tx_u32(hspi);
}
if (hspi->u32_TxCount >= hspi->u32_TxSize)
{
__SPI_TxFIFO_EMPTY_INT_DISABLE(hspi->SPIx);
hspi->b_TxBusy = false;
if (hspi->TxCpltCallback != NULL)
{
hspi->TxCpltCallback(hspi);
}
}
}
/* Rx FIFO Threshold FULL */
else if (__SPI_RxFIFO_FULL_INT_STATUS(hspi->SPIx))
{
frame_size = hspi->Init.Frame_Size;
if(frame_size <= SPI_FRAME_SIZE_8BIT)
{
spi_slave_rx_u8(hspi);
}
else if(frame_size <= SPI_FRAME_SIZE_16BIT)
{
spi_slave_rx_u16(hspi);
}
else
{
spi_slave_rx_u32(hspi);
}
if (hspi->u32_RxCount >= hspi->u32_RxSize)
{
__SPI_RxFIFO_FULL_INT_DISABLE(hspi->SPIx);
hspi->b_RxBusy = false;
if (hspi->RxCpltCallback != NULL)
{
hspi->RxCpltCallback(hspi);
}
}
}
}
/************************************************************************************
* @fn spi_slave_init
*
* @brief Initialize the SPI according to the specified parameters in the struct_SPIInit_t
*
* @param hspi: SPI handle.
*/
void spi_slave_init(SPI_HandleTypeDef *hspi)
{
/* Disable SPI, reset FIFO */
__SPI_DISABLE(hspi->SPIx);
/* Work mode */
hspi->SPIx->CTRL0.SCPOL = hspi->Init.Work_Mode & 0x2 ? 1 : 0;
hspi->SPIx->CTRL0.SCPH = hspi->Init.Work_Mode & 0x1 ? 1 : 0;
/* FIFO Threshold */
hspi->SPIx->TXFTLR = hspi->Init.TxFIFOEmpty_Threshold;
hspi->SPIx->RXFTLR = hspi->Init.RxFIFOFull_Threshold;
/* Disable all interrupt */
hspi->SPIx->IMR.MSTIM = 0;
hspi->SPIx->IMR.TXEIM = 0;
hspi->SPIx->IMR.TXOIM = 0;
hspi->SPIx->IMR.RXUIM = 0;
hspi->SPIx->IMR.RXOIM = 0;
hspi->SPIx->IMR.RXFIM = 0;
__SPI_CS_TOGGLE_DISABLE(hspi->SPIx);
/* CS Set */
hspi->SPIx->SER = 0;
}
/************************************************************************************
* @fn spi_slave_transmit
*
* @brief Send an amount of data in blocking mode.(Standard<72><64>Dual and Quad mode)
*
* @param hspi: SPI handle.
* fp_Data: pointer to data buffer
* fu32_Size: amount of data to be sent
*/
void spi_slave_transmit(SPI_HandleTypeDef *hspi, void *fp_Data, uint32_t fu32_Size)
{
uint8_t frame_size;
union {
void *data;
uint8_t *p_u8;
uint16_t *p_u16;
uint32_t *p_u32;
} p_data;
p_data.data = fp_Data;
/* config Mult Write Transfer parameters */
spi_slave_MultWireConfig(hspi,Wire_Write);
/* Get current frame size */
frame_size = hspi->Init.Frame_Size;
/* Frame Size <= 8 */
if (frame_size <= SPI_FRAME_SIZE_8BIT)
{
while (fu32_Size--)
{
while(__SPI_IS_TxFIFO_FULL(hspi->SPIx));
/* write data to tx FIFO */
hspi->SPIx->DR = *p_data.p_u8++;
}
}
else if(frame_size <= SPI_FRAME_SIZE_16BIT)
{
while (fu32_Size--)
{
while(__SPI_IS_TxFIFO_FULL(hspi->SPIx));
/* write data to tx FIFO */
hspi->SPIx->DR = *p_data.p_u16++;
}
}
else
{
while(fu32_Size--)
{
while(__SPI_IS_TxFIFO_FULL(hspi->SPIx));
/* write data to tx FIFO */
hspi->SPIx->DR = *p_data.p_u32++;
}
}
while(__SPI_IS_BUSY(hspi->SPIx));
}
/************************************************************************************
* @fn spi_slave_transmit_IT
*
* @brief Send an amount of data in interrupt mode.(Standard<72><64>Dual and Quad mode)
*
* @param hspi: SPI handle.
* fp_Data: pointer to data buffer
* fu32_Size: amount of data to be sent
*/
void spi_slave_transmit_IT(SPI_HandleTypeDef *hspi, void*fp_Data, uint32_t fu32_Size)
{
if (hspi->b_TxBusy)
return;
uint8_t frame_size;
/* config Mult Write Transfer parameters */
spi_slave_MultWireConfig(hspi,Wire_Write);
hspi->u32_TxSize = fu32_Size;
hspi->u32_TxCount = 0;
hspi->b_TxBusy = true;
hspi->u_TxData.p_data = fp_Data;
/* Get current frame size */
frame_size = hspi->Init.Frame_Size;
if (frame_size <= SPI_FRAME_SIZE_8BIT)
{
while(!__SPI_IS_TxFIFO_FULL(hspi->SPIx))
{
hspi->SPIx->DR = hspi->u_TxData.p_u8[hspi->u32_TxCount++];
if (hspi->u32_TxCount >= fu32_Size)
{
hspi->b_TxBusy = false;
return;
}
}
}
else if (frame_size <= SPI_FRAME_SIZE_16BIT)
{
while(!__SPI_IS_TxFIFO_FULL(hspi->SPIx))
{
hspi->SPIx->DR = hspi->u_TxData.p_u16[hspi->u32_TxCount++];
if (hspi->u32_TxCount >= fu32_Size)
{
hspi->b_TxBusy = false;
return;
}
}
}
else
{
while(!__SPI_IS_TxFIFO_FULL(hspi->SPIx))
{
hspi->SPIx->DR = hspi->u_TxData.p_u32[hspi->u32_TxCount++];
if (hspi->u32_TxCount >= fu32_Size)
{
hspi->b_TxBusy = false;
return;
}
}
}
/* TxFIFO empty interrupt enable */
__SPI_TxFIFO_EMPTY_INT_ENABLE(hspi->SPIx);
}
/************************************************************************************
* @fn spi_slave_transmit_DMA
*
* @brief Send an amount of data in DMA mode.(Standard<72><64>Dual and Quad mode)
*
* @param hspi: SPI handle.
*/
void spi_slave_transmit_DMA(SPI_HandleTypeDef *hspi)
{
/* config Mult Write Transfer parameters */
spi_slave_MultWireConfig(hspi,Wire_Write);
/* DMA Config */
__SPI_DMA_TX_ENABLE(hspi->SPIx);
__SPI_DMA_TX_LEVEL(hspi->SPIx, hspi->Init.TxFIFOEmpty_Threshold);
}
/************************************************************************************
* @fn spi_slave_receive
*
* @brief Receive an amount of data in blocking mode.(Standard<72><64>Dual and Quad mode)
*
* @param hspi: SPI handle.
* fp_Data: pointer to data buffer
* fu32_Size: amount of data to be Receive
*/
void spi_slave_receive(SPI_HandleTypeDef *hspi, void *fp_Data, uint32_t fu32_Size)
{
uint8_t frame_size;
union {
void *data;
uint8_t *p_u8;
uint16_t *p_u16;
uint32_t *p_u32;
} p_data;
p_data.data = fp_Data;
/* config Mult Read Transfer parameters */
spi_slave_MultWireConfig(hspi,Wire_Read);
/* Get current frame size */
frame_size = hspi->Init.Frame_Size;
/* Frame Size <= 8 */
if (frame_size <= SPI_FRAME_SIZE_8BIT)
{
while (fu32_Size)
{
while(!__SPI_IS_RxFIFO_EMPTY(hspi->SPIx))
{
*p_data.p_u8++ = hspi->SPIx->DR;
fu32_Size--;
}
}
}
else if (frame_size <= SPI_FRAME_SIZE_16BIT)
{
while (fu32_Size)
{
while(!__SPI_IS_RxFIFO_EMPTY(hspi->SPIx))
{
*p_data.p_u16++ = hspi->SPIx->DR;
fu32_Size--;
}
}
}
else
{
while (fu32_Size)
{
while(!__SPI_IS_RxFIFO_EMPTY(hspi->SPIx))
{
*p_data.p_u32++ = hspi->SPIx->DR;
fu32_Size--;
}
}
}
while(__SPI_IS_BUSY(hspi->SPIx));
}
/************************************************************************************
* @fn spi_slave_receive_IT
*
* @brief Receive an amount of data in interrupt mode.(Standard<72><64>Dual and Quad mode)
*
* @param hspi: SPI handle.
* fp_Data: pointer to data buffer
* fu32_Size: amount of data to be Receive
*/
void spi_slave_receive_IT(SPI_HandleTypeDef *hspi, void *fp_Data, uint32_t fu32_Size)
{
if (hspi->b_RxBusy)
return;
/* config Mult Read Transfer parameters */
spi_slave_MultWireConfig(hspi,Wire_Read);
hspi->u32_RxSize = fu32_Size;
hspi->u32_RxCount = 0;
hspi->b_RxBusy = true;
hspi->u_RxData.p_data = fp_Data;
/* RxFIFO full interrupt enable */
__SPI_RxFIFO_FULL_INT_ENABLE(hspi->SPIx);
}
/************************************************************************************
* @fn spi_slave_receive_DMA
*
* @brief Receive an amount of data in interrupt mode.(Standard<72><64>Dual and Quad mode)
*
* @param hspi: SPI handle.
* fp_Data: pointer to data buffer
* fu32_Size: amount of data to be Receive
*/
void spi_slave_receive_DMA(SPI_HandleTypeDef *hspi)
{
/* config Mult Read Transfer parameters */
spi_slave_MultWireConfig(hspi,Wire_Read);
/* DMA Config */
__SPI_DMA_RX_ENABLE(hspi->SPIx);
__SPI_DMA_RX_LEVEL(hspi->SPIx, hspi->Init.RxFIFOFull_Threshold);
}
/************************************************************************************
* @fn spi_slave_MultWireConfig
*
* @brief config Mult Wire Transfer parameters.(DualbQuad mode)
*
* @param hspi: SPI handle.
*/
void spi_slave_MultWireConfig(SPI_HandleTypeDef *hspi, enum_Wire_Type_t fe_type)
{
/* Disable SPI, reset FIFO */
__SPI_DISABLE(hspi->SPIx);
/* slave mode and Frame Size*/
if (hspi->MultWireParam.Wire_X2X4X8 == Wire_X2)
{
__SPI_SLAVE_SET_MODE_X2(hspi->SPIx);
hspi->SPIx->CTRL0.DFS_32 = (hspi->Init.Frame_Size + 1) / 2 - 1;
}
else if (hspi->MultWireParam.Wire_X2X4X8 == Wire_X4)
{
__SPI_SLAVE_SET_MODE_X4(hspi->SPIx);
hspi->SPIx->CTRL0.DFS_32 = (hspi->Init.Frame_Size + 1) / 4 - 1;
}
else
{
__SPI_SLAVE_SET_MODE_X1(hspi->SPIx);
hspi->SPIx->CTRL0.DFS_32 = hspi->Init.Frame_Size;
}
if (fe_type == Wire_Write)
{
/* slave output enable */
hspi->SPIx->CTRL0.SLV_OE = 0;
/* Select Only Tx mode */
__SPI_TMODE_Tx_ONLY(hspi->SPIx);
}
else
{
/* slave output disable */
hspi->SPIx->CTRL0.SLV_OE = 1;
/* Select Only Rx mode */
__SPI_TMODE_Rx_ONLY(hspi->SPIx);
}
/* Enable SPI */
__SPI_ENABLE(hspi->SPIx);
}

View File

@ -0,0 +1,127 @@
/*
******************************************************************************
* @file driver_tick.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief Tick module driver.
* This file provides firmware functions to manage the System Tick peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/************************************************************************************
* @fn tick_IRQHandler
*
* @brief Handle Tick interrupt request.
*
* @param htick: Tick handle.
*/
void tick_IRQHandler(TICK_HandleTypeDef *htick)
{
uint32_t status = Tick->INT_STA.Word;
/* system wake up from sleep */
if (status & TICK_INT_TYPE_SLP) {
if ((htick) && (htick->TickSleepCallback)) {
htick->TickSleepCallback();
}
Tick->INT_STA.Bits.SLP = 1;
}
/* tick reach target value */
if (status & TICK_INT_TYPE_TGT) {
if ((htick) && (htick->TickTargetCallback)) {
htick->TickTargetCallback();
}
Tick->INT_STA.Bits.TGT = 1;
Tick->INT_CTL.Bits.TGT = 0;
}
}
/************************************************************************************
* @fn tick_init
*
* @brief Init System Tick.
*
* @param htick: Tick handle.
*/
void tick_init(TICK_HandleTypeDef *handle)
{
/* enable Timerstamp compare default */
Tick->CTL.CMP_EN = 1;
/* enable sleep interrupt as default */
Tick->INT_CTL.Bits.SLP = 1;
}
/************************************************************************************
* @fn tick_get
*
* @brief Get current System Tick.
*
* @param clk: pointer used to store clock counter.
* fine: pointer used to store fine counter.
*/
void tick_get(uint32_t *clk, uint32_t *fine)
{
Tick->CTL.SMP = 1;
while(Tick->CTL.SMP == 1);
*clk = Tick->CLK_SMP;
*fine = Tick->FINE_SMP;
}
/************************************************************************************
* @fn tick_set_target
*
* @brief Set system tick target time and wait for the target time in block mode.
*
* @param clk: target clock counter.
* fine: target fine counter.
*/
void tick_set_target(uint32_t clk, uint32_t fine)
{
Tick->CLK_TGT = clk;
Tick->FINE_TGT = fine;
while (Tick->INT_RAW.Bits.TGT == 0);
Tick->INT_STA.Bits.TGT = 1;
}
/************************************************************************************
* @fn tick_set_target_IT
*
* @brief Set system tick target time in interrupt mode.
*
* @param clk: target clock counter.
* fine: target fine counter.
*/
void tick_set_target_IT(uint32_t clk, uint32_t fine)
{
Tick->CLK_TGT = clk;
Tick->FINE_TGT = fine;
Tick->INT_CTL.Bits.TGT = 1;
}
/************************************************************************************
* @fn tick_start_corr
*
* @brief Used to correction system tick after wake from sleep mode.
*
* @param clk: clock counter corrcetion value.
* fine: fine counter corrcetion value.
*/
void tick_start_corr(uint32_t clk, uint32_t fine)
{
Tick->CLK_CORR = clk;
Tick->FINE_CORR = fine;
Tick->SLP_CTL.SLP_CORR_EN = 1;
while(Tick->SLP_CTL.SLP_CORR_EN == 1);
}

View File

@ -0,0 +1,117 @@
/*
******************************************************************************
* @file driver_timer.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief Timer module driver.
* This file provides firmware functions to manage the Timer peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/************************************************************************************
* @fn timer_init
*
* @brief timer initialize.
*
* @param TIMERx: Timer handle.
* fu32_LoadCount: Timer Load Count.
*/
void timer_init(struct_Timer_t *TIMERx, uint32_t fu32_LoadCount)
{
TIMERx->LoadCount = fu32_LoadCount;
TIMERx->Control.MODE = 1;
}
/************************************************************************************
* @fn timer_int_enable
*
* @brief timer interrupt enable.
*
* @param TIMERx: Timer handle.
*/
void timer_int_enable(struct_Timer_t *TIMERx)
{
TIMERx->Control.INT_MASK = 0;
}
/************************************************************************************
* @fn timer_int_disable
*
* @brief timer interrupt disable.
*
* @param TIMERx: Timer handle.
*/
void timer_int_disable(struct_Timer_t *TIMERx)
{
TIMERx->Control.INT_MASK = 1;
}
/************************************************************************************
* @fn timer_int_clear
*
* @brief timer interrupt status clear.
*
* @param TIMERx: Timer handle.
*/
void timer_int_clear(struct_Timer_t *TIMERx)
{
uint32_t lu32_TempValue;
lu32_TempValue = TIMERx->IntClear;
}
/************************************************************************************
* @fn timer_int_status
*
* @brief get timer interrupt status.
*
* @param TIMERx: Timer handle.
*/
bool timer_int_status(struct_Timer_t *TIMERx)
{
return TIMERx->IntStatus;
}
/************************************************************************************
* @fn timer_start
*
* @brief Timer start count.
*
* @param TIMERx: Timer handle.
*/
void timer_start(struct_Timer_t *TIMERx)
{
TIMERx->Control.ENABLE = 1;
}
/************************************************************************************
* @fn timer_stop
*
* @brief Timer stop count.
*
* @param TIMERx: Timer handle.
*/
void timer_stop(struct_Timer_t *TIMERx)
{
TIMERx->Control.ENABLE = 0;
}
/************************************************************************************
* @fn timer_get_CurrentCount
*
* @brief get Timer current count.
*
* @param TIMERx: Timer handle.
*/
uint32_t timer_get_CurrentCount(struct_Timer_t *TIMERx)
{
return TIMERx->CurrentValue;
}

View File

@ -0,0 +1,105 @@
/*
******************************************************************************
* @file driver_trigfunc.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2023
* @brief trigfunc module driver.
* This file provides firmware functions to manage the
* trigfunc(trigonometric function) peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2023 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
double trigfunc_sin(double fe_argin)
{
double f_value = 0;
uint32_t int_value = 0;
fe_argin = QUANTIZATION_PARAMETER * fe_argin;
int_value = (int)fe_argin;
f_value = fe_argin - int_value;
if((f_value) >= 0.5)
{
int_value++;
}
TRIGFUNC->TRIGFUNC_INTR &= ~TRIGFUNC_INTRCR;
TRIGFUNC->TRIGFUNC_CTRL = TRIG_CAL_SIN_AND_COS | BYTE_2;
TRIGFUNC->TRIGFUNC_ARG1_IN = int_value;
while(!__TRIGFUNC_CAL_IS_DONE_STATUS());
return (int16_t)(TRIGFUNC->TRIGFUNC_RESULT2_OUT) / QUANTIZATION_PARAMETER;
}
double trigfunc_cos(double fe_argin)
{
double f_value = 0;
uint32_t int_value = 0;
fe_argin = QUANTIZATION_PARAMETER * fe_argin;
int_value = (int)fe_argin;
f_value = fe_argin - int_value;
if((f_value) >= 0.5)
{
int_value++;
}
TRIGFUNC->TRIGFUNC_INTR &= ~TRIGFUNC_INTRCR;
TRIGFUNC->TRIGFUNC_CTRL = TRIG_CAL_SIN_AND_COS | BYTE_2;
TRIGFUNC->TRIGFUNC_ARG1_IN = int_value;
while(!__TRIGFUNC_CAL_IS_DONE_STATUS());
return (int16_t)(TRIGFUNC->TRIGFUNC_RESULT1_OUT) / QUANTIZATION_PARAMETER;
}
double trigfunc_tan(double fe_argin)
{
double f_value;
uint32_t int_value = 0;
fe_argin = QUANTIZATION_PARAMETER * fe_argin;
int_value = (int)fe_argin;
f_value = fe_argin - int_value;
if((f_value) >= 0.5)
{
int_value++;
}
TRIGFUNC->TRIGFUNC_INTR &= ~TRIGFUNC_INTRCR;
TRIGFUNC->TRIGFUNC_CTRL = TRIG_CAL_TAN | BYTE_2;
TRIGFUNC->TRIGFUNC_ARG1_IN = int_value;
while(!__TRIGFUNC_CAL_IS_DONE_STATUS());
return (int16_t)(TRIGFUNC->TRIGFUNC_RESULT1_OUT) / (double)0x100 ;
}
double trigfunc_atan(double fe_argin)
{
int16_t f_value;
TRIGFUNC->TRIGFUNC_INTR &= ~TRIGFUNC_INTRCR;
TRIGFUNC->TRIGFUNC_CTRL = TRIG_CAL_ARCTAN_X | BYTE_2;
f_value = fe_argin * 0x100;
TRIGFUNC->TRIGFUNC_ARG1_IN = f_value;
while(!__TRIGFUNC_CAL_IS_DONE_STATUS());
return (int16_t)(TRIGFUNC->TRIGFUNC_RESULT1_OUT) * 180 / QUANTIZATION_PARAMETER;
}

View File

@ -0,0 +1,120 @@
/*
******************************************************************************
* @file driver_trng.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2023
* @brief TRNG module driver.
* This file provides firmware functions to manage the
* True Random Number Generator (TRNG) peripheral.
******************************************************************************
* @attention
*
* Copyright (c) 2023 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
static int trng_sel_smp_verify(int Rand_sel_index, int Sample_cnt_index)
{
int Error;
TRNG->TRNG_IMR = 0XFFFFFF00;
TRNG->TRNG_SrcEN = 0;
TRNG->TRNG_DebugControl = 0;
/* Selects the number of inverters in the ring oscillator */
TRNG->TRNG_Config = Rand_sel_index;
while((TRNG->TRNG_Config & Rand_sel_index) != Rand_sel_index);
TRNG->TRNG_SAMPLE_CNT1 = Sample_cnt_index;
while((TRNG->TRNG_SAMPLE_CNT1 & Sample_cnt_index) != Sample_cnt_index);
TRNG->TRNG_AUTOCORR = 0;
TRNG->TRNG_SrcEN = 1;
while(!(TRNG->TRNG_ISR));
if (TRNG->TRNG_ISR & TRNG_STATUS_EHR_VALID)
Error = 0;
else
Error = 1;
if (Error)
{
TRNG->TRNG_Reset = 1;
}
TRNG->TRNG_ICR = 0XFFFFFFFF;
return !Error;
}
/************************************************************************************
* @fn trng_init
*
* @brief trng init.
*/
void trng_init(void)
{
#define MAX_SAMPLE_CNT_INDX (0xFFFFFF00)
uint32_t Rand_sel_index;
uint32_t Sample_cnt_index;
uint32_t Rand_Sample_Passed;
for (Rand_sel_index = 1; Rand_sel_index < 4; Rand_sel_index++)
{
Rand_Sample_Passed = 0;
Sample_cnt_index = 33333;
do{
Rand_Sample_Passed = trng_sel_smp_verify(Rand_sel_index, Sample_cnt_index);
Sample_cnt_index += 111;
} while ((Sample_cnt_index <= (MAX_SAMPLE_CNT_INDX)) && !Rand_Sample_Passed);
while(TRNG->TRNG_BIST_CNTR0 <= 0);
while(TRNG->TRNG_BIST_CNTR1 <= 0);
while(TRNG->TRNG_BIST_CNTR2 <= 0);
if (Rand_Sample_Passed)
break;
}
TRNG->TRNG_SrcEN = 0;
}
/************************************************************************************
* @fn trng_read_rand_num
*
* @brief Read random numbers.
*
* @param fp_buffer: random numbers buffer.
* @param length: random numbers length, max 24 byte.
*/
void trng_read_rand_num(uint8_t *fp_buffer, uint8_t length)
{
int i;
uint32_t lu32_buffer[6];
uint8_t *Point = (uint8_t *)lu32_buffer;
if (length > 24)
length = 24;
/* TRNG enable */
TRNG->TRNG_SrcEN = 1;
/* Wait VALID */
while(!(TRNG->TRNG_ISR & TRNG_STATUS_EHR_VALID));
for(int i = 0; i < 6; i++)
lu32_buffer[i] = TRNG->TRNG_Data[i];
for (int i = 0; i < length; i++)
fp_buffer[i] = Point[i];
/* TRNG disable */
TRNG->TRNG_SrcEN = 0;
/* Clear status */
TRNG->TRNG_ICR = TRNG_STATUS_EHR_VALID;
}

View File

@ -0,0 +1,325 @@
/*
******************************************************************************
* @file driver_uart.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief UART module driver.
* This file provides firmware functions to manage the
* Universal Asynchronous Receiver/Transmitter (UART) peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/************************************************************************************
* @fn uart_IRQHandler
*
* @brief Handle UART interrupt request.
*
* @param huart: UART handle.
*/
__WEAK void uart_IRQHandler(UART_HandleTypeDef *huart)
{
switch (__UART_INT_GET_ID(huart->UARTx))
{
case INT_INDEX_TXE:
{
/* Data transit end */
if (huart->u32_TxCount >= huart->u32_TxSize)
{
__UART_INT_TXE_DISABLE(huart->UARTx);
huart->b_TxBusy = false;
}
else
{
/* UART_FIFO_ENABLE */
if (__UART_IS_FIFO_Enable(huart))
{
/* Until TxFIFO full */
while(!__UART_IS_TxFIFO_FULL(huart->UARTx))
{
huart->UARTx->DATA_DLL.DATA = huart->p_TxData[huart->u32_TxCount++];
/* Data transit end */
if (huart->u32_TxCount >= huart->u32_TxSize)
{
__UART_INT_TXE_DISABLE(huart->UARTx);
huart->b_TxBusy = false;
if (huart->TxCpltCallback != NULL)
{
huart->TxCpltCallback(huart);
}
break;
}
}
}
else
{
huart->UARTx->DATA_DLL.DATA = huart->p_TxData[huart->u32_TxCount++];
}
}
}break;
case INT_INDEX_RX:
case INT_INDEX_RX_TOUT:
{
/* Rx ready */
while (huart->UARTx->LSR.LSR_BIT.DR)
{
huart->p_RxData[huart->u32_RxCount++] = huart->UARTx->DATA_DLL.DATA;
/* Data receive end */
if (huart->u32_RxCount >= huart->u32_RxSize)
{
__UART_INT_RX_DISABLE(huart->UARTx);
huart->b_RxBusy = false;
if (huart->RxCpltCallback != NULL)
{
huart->RxCpltCallback(huart);
}
break;
}
}
}break;
default: break;
}
}
/************************************************************************************
* @fn uart_init
*
* @brief Initialize the UART according to the specified parameters in the struct_UARTInit_t
*
* @param huart: UART handle.
*/
void uart_init(UART_HandleTypeDef *huart)
{
/* Config Data Length */
huart->UARTx->LCR.Bits.DLS = huart->Init.DataLength;
/* Config Stop Bits*/
huart->UARTx->LCR.Bits.STOP = huart->Init.StopBits;
/* Config Auto Flow */
if(huart->Init.AUTO_FLOW)
{
__UART_AUTO_FLOW_CONTROL_ENABLE( huart->UARTx);
}
/* Config Parity */
if (huart->Init.Parity != UART_PARITY_NONE)
{
huart->UARTx->LCR.Bits.PEN = 1;
switch (huart->Init.Parity)
{
case UART_PARITY_ODD: huart->UARTx->LCR.Bits.SP = 0; huart->UARTx->LCR.Bits.EPS = 0; break;
case UART_PARITY_EVEN: huart->UARTx->LCR.Bits.SP = 0; huart->UARTx->LCR.Bits.EPS = 1; break;
case UART_PARITY_0: huart->UARTx->LCR.Bits.SP = 1; huart->UARTx->LCR.Bits.EPS = 1; break;
case UART_PARITY_1: huart->UARTx->LCR.Bits.SP = 1; huart->UARTx->LCR.Bits.EPS = 0; break;
default: break;
}
}
else
{
huart->UARTx->LCR.Bits.PEN = 0;
}
/* Config FIFO<46><4F>DMA<4D><41>RxFIF/TxFIFO threshold */
huart->FCR_Shadow = huart->Init.FIFO_Mode | (huart->Init.FIFO_Mode << FCR_DMAM);
huart->UARTx->FCR_IID.FCR = huart->FCR_Shadow;
/* Config BaudRate */
uart_config_baudRate(huart);
}
/************************************************************************************
* @fn uart_transmit
*
* @brief Send an amount of data in blocking mode.
*
* @param huart: UART handle.
* @param fp_Data: Pointer to data buffer.
* @param fu32_Size: Amount of data to be sent.
*/
void uart_transmit(UART_HandleTypeDef *huart, uint8_t *fp_Data, uint32_t fu32_Size)
{
/* UART_FIFO_ENABLE */
if (__UART_IS_FIFO_Enable(huart))
{
while (fu32_Size--)
{
/* TxFIFO FULL */
while(!(huart->UARTx->USR.TFNF));
/* Send data */
huart->UARTx->DATA_DLL.DATA = *fp_Data++;
}
}
else
{
while (fu32_Size--)
{
/* Tx not empty */
while(!(huart->UARTx->LSR.LSR_BIT.THRE));
/* Send data */
huart->UARTx->DATA_DLL.DATA = *fp_Data++;
}
}
}
/************************************************************************************
* @fn uart_receive
*
* @brief Receive an amount of data in blocking mode.
*
* @param huart: UART handle.
* @param fp_Data: Pointer to data buffer.
* @param fu32_Size: Amount of data to be receive.
*/
void uart_receive(UART_HandleTypeDef *huart, uint8_t *fp_Data, uint32_t fu32_Size)
{
while (fu32_Size--)
{
/* Rx ready */
while (!(huart->UARTx->LSR.LSR_BIT.DR));
/* receive data */
*fp_Data++ = huart->UARTx->DATA_DLL.DATA;
}
}
/************************************************************************************
* @fn uart_transmit_IT
*
* @brief Send an amount of data in interrupt mode.
*
* @param huart: UART handle.
* @param fp_Data: Pointer to data buffer.
* @param fu32_Size: Amount of data to be sent.
*/
void uart_transmit_IT(UART_HandleTypeDef *huart, uint8_t *fp_Data, uint32_t fu32_Size)
{
if (huart->b_TxBusy)
return;
huart->p_TxData = fp_Data;
huart->u32_TxCount = 0;
huart->u32_TxSize = fu32_Size;
huart->b_TxBusy = true;
/* UART_FIFO_ENABLE */
if (__UART_IS_FIFO_Enable(huart))
{
// /* Tx FIFO reset */
// __UART_TxFIFO_Reset(huart);
/* Tx empty interrupt and fifo enable */
__UART_INT_TXE_ENABLE_FE(huart->UARTx);
}
else
{
/* Tx empty interrupt and fifo disable */
__UART_INT_TXE_ENABLE_FD(huart->UARTx);
}
}
/************************************************************************************
* @fn uart_transmit_IT
*
* @brief Receive an amount of data in interrupt mode.
*
* @param huart: UART handle.
* @param fp_Data: Pointer to data buffer.
* @param fu32_Size: Amount of data to be receive.
*/
void uart_receive_IT(UART_HandleTypeDef *huart, uint8_t *fp_Data, uint32_t fu32_Size)
{
if (huart->b_RxBusy)
return;
huart->p_RxData = fp_Data;
huart->u32_RxCount = 0;
huart->u32_RxSize = fu32_Size;
huart->b_RxBusy = true;
// /* Rx FIFO reset */
// __UART_RxFIFO_Reset(huart);
/* data ready<64><79>character timeout interrupt enable */
__UART_INT_RX_ENABLE(huart->UARTx);
}
/************************************************************************************
* @fn uart_config_baudRate
*
* @brief Config BaudRate
*
* @param huart: UART handle.
*/
void uart_config_baudRate(UART_HandleTypeDef *huart)
{
uint32_t i;
uint32_t lu32_UartClock;
uint32_t lu32_Integer;
uint64_t lu64_Fractional;
uint16_t lu32_TempValue[2];
lu32_UartClock = system_get_peripheral_clock(PER_CLK_UARTx);
/* Calculate the integer part */
lu32_Integer = lu32_UartClock / (16 * huart->Init.BaudRate);
/* Calculate the fractional part */
lu64_Fractional = lu32_UartClock % (16 * huart->Init.BaudRate);
lu64_Fractional = (lu64_Fractional * 10000) / (16 * huart->Init.BaudRate);
for (i = 0; i < 0x3F; i++)
{
lu32_TempValue[0] = (i * 10000) / 64;
lu32_TempValue[1] = ((i + 1) * 10000) / 64;
if (lu64_Fractional >= lu32_TempValue[0] && lu64_Fractional <= lu32_TempValue[1])
{
if (lu64_Fractional - lu32_TempValue[0] < lu32_TempValue[1] - lu64_Fractional)
{
lu64_Fractional = i;
}
else
{
lu64_Fractional = i + 1;
}
break;
}
else if (i == 0x3E)
{
lu64_Fractional = 0x3F;
}
}
/* DLL<4C><4C>DLH register access enable */
__UART_DLL_DLH_ACCESS_ENABLE(huart->UARTx);
huart->UARTx->DATA_DLL.DLL = lu32_Integer & 0xFF;
huart->UARTx->IER_DLH.DLH = (lu32_Integer >> 8) & 0xFF;
huart->UARTx->DLF.DLF = lu64_Fractional;
/* DLL<4C><4C>DLH register access disable */
__UART_DLL_DLH_ACCESS_DISABLE(huart->UARTx);
}

View File

@ -0,0 +1,172 @@
/*
******************************************************************************
* @file driver_yuv2rgb.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2022
* @brief YUV2RGB module driver.
* This file provides firmware functions to manage the YUV2RGB.
******************************************************************************
* @attention
*
* Copyright (c) 2022 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/************************************************************************************
* @fn yuv2rgb_IRQHandler
*
* @brief yuv2rgb interrupt handler.
*
* @param hyuv2rgb: YUV2RGB handle.
*/
__WEAK void yuv2rgb_IRQHandler(YUV2RGB_HandleTypeDef *hyuv2rgb)
{
if (__YUV2RGB_GET_INT_STATUS(hyuv2rgb->YUV2RGBx) & YUV_FIFO_ALMOST_EMPTY)
{
while(!(__YUV2RGB_GET_INT_RAW_STATUS(hyuv2rgb->YUV2RGBx) & YUV_FIFO_FULL))
{
switch (hyuv2rgb->Init.YUV_Format)
{
case YUV_FORMAT_444: hyuv2rgb->YUV2RGBx->YUV_DATA = *hyuv2rgb->u_YUVData.p_u32++; break;
case YUV_FORMAT_422: hyuv2rgb->YUV2RGBx->YUV_DATA = *hyuv2rgb->u_YUVData.p_u16++; break;
default:break;
}
hyuv2rgb->u32_YUVCount++;
if (hyuv2rgb->u32_YUVCount >= hyuv2rgb->u32_Pixels)
{
__YUV2RGB_INT_DISABLE(hyuv2rgb->YUV2RGBx, YUV_FIFO_ALMOST_EMPTY);
break;
}
}
}
if (__YUV2RGB_GET_INT_STATUS(hyuv2rgb->YUV2RGBx) & RGB_FIFO_ALMOST_FULL)
{
while (!(__YUV2RGB_GET_INT_RAW_STATUS(hyuv2rgb->YUV2RGBx) & RGB_FIFO_EMPTY))
{
switch (hyuv2rgb->Init.RGB_Format)
{
case RGB_FORMAT_888: *hyuv2rgb->u_RGBData.p_u32++ = hyuv2rgb->YUV2RGBx->RGB_DATA; break;
case RGB_FORMAT_565: *hyuv2rgb->u_RGBData.p_u16++ = hyuv2rgb->YUV2RGBx->RGB_DATA; break;
case RGB_FORMAT_332: *hyuv2rgb->u_RGBData.p_u8++ = hyuv2rgb->YUV2RGBx->RGB_DATA; break;
default:break;
}
hyuv2rgb->u32_RGBCount++;
if (hyuv2rgb->u32_RGBCount >= hyuv2rgb->u32_Pixels)
{
__YUV2RGB_INT_DISABLE(hyuv2rgb->YUV2RGBx, RGB_FIFO_ALMOST_FULL);
hyuv2rgb->b_CovertBusy = false;
break;
}
}
}
}
/************************************************************************************
* @fn yuv2rgb_init
*
* @brief Initialize YUV2RGB UART according to the specified parameters
* in the struct_YUV2RGBInit_t.
*
* @param hyuv2rgb: YUV2RGB handle.
*/
void yuv2rgb_init(YUV2RGB_HandleTypeDef *hyuv2rgb)
{
/* YUV2RGB enable */
__YUV2RGB_ENABLE(hyuv2rgb->YUV2RGBx);
/* DMA default enable */
__YUV2RGB_DMA_ENABLE(hyuv2rgb->YUV2RGBx);
/* Set YUV2RGB format, calculate Mode */
hyuv2rgb->YUV2RGBx->YUV2RGB_CFG.RGB_FORMAT = hyuv2rgb->Init.RGB_Format;
hyuv2rgb->YUV2RGBx->YUV2RGB_CFG.YUV_FORMAT = hyuv2rgb->Init.YUV_Format;
hyuv2rgb->YUV2RGBx->YUV2RGB_CFG.YUV_MODE = hyuv2rgb->Init.YUV_CalculateMode;
if (hyuv2rgb->Init.YUV_Format == YUV_FORMAT_444)
hyuv2rgb->YUV2RGBx->FLOW_CTRL.YUV_FLOW_LEVEL = 1;
else
hyuv2rgb->YUV2RGBx->FLOW_CTRL.YUV_FLOW_LEVEL = 2;
hyuv2rgb->YUV2RGBx->FLOW_CTRL.RGB_FLOW_LEVEL = 30;
}
/************************************************************************************
* @fn yuv2rgb_convert
*
* @brief YUV to RGB convert in blocking mode.
*
* @param hyuv2rgb: YUV2RGB handle.
* YUV_Buffer: YUV data buffer.
* RGB_BUffer: RGB data buffer.
* fu32_Pixels:
*/
void yuv2rgb_convert(YUV2RGB_HandleTypeDef *hyuv2rgb, void *YUV_Buffer, void *RGB_Buffer, uint32_t fu32_Pixels)
{
uint32_t lu32_RGBCount = 0;
uint32_t lu32_YUVCount = 0;
hyuv2rgb->u_YUVData.p_data = YUV_Buffer;
hyuv2rgb->u_RGBData.p_data = RGB_Buffer;
while(true)
{
if (!(__YUV2RGB_GET_INT_RAW_STATUS(hyuv2rgb->YUV2RGBx) & RGB_FIFO_EMPTY))
{
if (lu32_RGBCount < fu32_Pixels)
{
switch (hyuv2rgb->Init.RGB_Format)
{
case RGB_FORMAT_888: *hyuv2rgb->u_RGBData.p_u32++ = hyuv2rgb->YUV2RGBx->RGB_DATA; break;
case RGB_FORMAT_565: *hyuv2rgb->u_RGBData.p_u16++ = hyuv2rgb->YUV2RGBx->RGB_DATA; break;
case RGB_FORMAT_332: *hyuv2rgb->u_RGBData.p_u8++ = hyuv2rgb->YUV2RGBx->RGB_DATA; break;
default:break;
}
lu32_RGBCount++;
if (lu32_RGBCount >= fu32_Pixels)
break;
}
}
if (!(__YUV2RGB_GET_INT_RAW_STATUS(hyuv2rgb->YUV2RGBx) & YUV_FIFO_FULL))
{
if (lu32_YUVCount < fu32_Pixels)
{
switch (hyuv2rgb->Init.YUV_Format)
{
case YUV_FORMAT_444: hyuv2rgb->YUV2RGBx->YUV_DATA = *hyuv2rgb->u_YUVData.p_u32++; break;
case YUV_FORMAT_422: hyuv2rgb->YUV2RGBx->YUV_DATA = *hyuv2rgb->u_YUVData.p_u16++; break;
default: break;
}
lu32_YUVCount++;
}
}
}
}
/************************************************************************************
* @fn yuv2rgb_convert_IT
*
* @brief YUV to RGB convert in interrupt mode.
*
* @param hyuv2rgb: YUV2RGB handle.
*/
void yuv2rgb_convert_IT(YUV2RGB_HandleTypeDef *hyuv2rgb, void *YUV_Buffer, void *RGB_Buffer, uint32_t fu32_Pixels)
{
hyuv2rgb->u_YUVData.p_data = YUV_Buffer;
hyuv2rgb->u_RGBData.p_data = RGB_Buffer;
hyuv2rgb->u32_RGBCount = 0;
hyuv2rgb->u32_YUVCount = 0;
hyuv2rgb->u32_Pixels = fu32_Pixels;
hyuv2rgb->b_CovertBusy = true;
__YUV2RGB_YUV_FIFO_ALMOST_EMPTY_LEVEL(hyuv2rgb->YUV2RGBx, 6);
__YUV2RGB_RGB_FIFO_ALMOST_FULL_LEVEL(hyuv2rgb->YUV2RGBx, 1);
__YUV2RGB_INT_ENABLE(hyuv2rgb->YUV2RGBx, YUV_FIFO_ALMOST_EMPTY);
__YUV2RGB_INT_ENABLE(hyuv2rgb->YUV2RGBx, RGB_FIFO_ALMOST_FULL);
}

View File

@ -0,0 +1,977 @@
/*
******************************************************************************
* @file usb_audio.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief This file provides the high layer firmware functions to manage the
* USB Audio Device.
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
*
******************************************************************************
*/
#include "usb_audio.h"
uint8_t gu8_Respond[5];
uint8_t gu8_AudioReport;
uint32_t gu32_BitWidthSpeaker;
uint32_t gu32_BitWidthMic;
uint32_t gu32_PacketLengthSpeaker;
uint32_t gu32_PacketLengthMic;
uint32_t gu32_SamplingFreqSpeaker;
uint32_t gu32_SamplingFreqMic;
uint16_t gu16_VolumeSpeaker = USB_AUDIO_VOLUME_MAX;
uint16_t gu16_VolumeMic = USB_AUDIO_VOLUME_MAX;
uint8_t gu8_MuteSpeaker = 0x00;
uint8_t gu8_MuteMic = 0x00;
/* Audio Set Control */
typedef enum
{
AUDIO_SET_VOL_SPEAKER, /* set Speaker Volume */
AUDIO_SET_VOL_MIC, /* set Microphone Volume */
AUDIO_SET_MUTE_SPEAKER, /* set Speaker Mute */
AUDIO_SET_MUTE_MIC, /* set Microphone Mute */
AUDIO_SET_SAMPLING_SPEAKER, /* set Speaker Sampling Frequency */
AUDIO_SET_SAMPLING_MIC, /* set Microphone Sampling Frequency */
}Audio_SetControl;
Audio_SetControl ge_CTLIndex;
/* USB Standard Device Descriptor */
const uint8_t USB_Audio_DeviceDesc[] =
{
0x12, /* bLength */
0x01, /* bDescriptorType */
0x00, /* bcdUSB */
0x02,
0x00, /* bDeviceClass */
0x00, /* bDeviceSubClass */
0x00, /* bDeviceProtocol */
0x40, /* bMaxPacketSize */
0xA4, /* idVendor */
0xA5, /* idVendor */
0xA6, /* idProduct */
0xA7, /* idProduct */
0x00, /* bcdDevice rel. 2.00 */
0x02,
0x01, /* Index of manufacturer string */
0x02, /* Index of product string */
0x03, /* Index of serial number string */
0x01, /* bNumConfigurations */
};
/* USB Standard Configuration Descriptor */
const uint8_t USB_Audio_ConfigurationDesc[] =
{
/* Configuration Descriptor */
0x09, /* bLength */
0x02, /* bDescriptorType */
0x1C, /* wTotalLength */
0x01,
0x04, /* bNumInterfaces */
0x01, /* bConfigurationValue */
0x00, /* iConfiguration */
0xC0, /* bmAttributes */
0x32, /* bMaxPower */
/* Audio Interface_0 Descriptor */
0x09, /* bLength */
0x04, /* bDescriptorType */
0x00, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x00, /* bNumEndpoints */
0x01, /* bInterfaceClass: Audio */
0x01, /* bInterfaceSubClass: Audio Control */
0x00, /* bInterfaceProtocol */
0x00, /* iInterface */
/* Audio Control Interface Header Descriptor */
0x0A, /* bLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x01, /* bDescriptorSubtype: HEADER descriptor subtype */
0x00, /* bcdADC */
0x01,
0x4C, /* wTotalLength */
0x00,
0x02, /* bInCollection */
0x01, /* baInterfaceNr(1) */
0x02, /* baInterfaceNr(2) */
/* Audio Control Input Terminal Descriptor */
0x0C, /* bLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x02, /* bDescriptorSubtype: INPUT_TERMINAL */
0x01, /* bTerminalID */
0x01, /* wTerminalType: USB streaming */
0x01,
0x00, /* bAssocTerminal */
0x02, /* bNrChannels */
0x03, /* wChannelConfig */
0x00,
0x00, /* iChannelNames */
0x00, /* iTerminal */
/* Audio Control Feature Unit Descriptor */
0x0D, /* bLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x06, /* bDescriptorSubtype: FEATURE_UNIT */
0x02, /* bUnitID */
0x01, /* bSourceID */
0x02, /* bControlSize */
0x01,
0x00,
0x02,
0x00,
0x02,
0x00,
0x00, /* iFeature */
/* Audio Control Output Terminal Descriptor */
0x09, /* bLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x03, /* bDescriptorSubtype: OUTPUT_TERMINAL */
0x03, /* bTerminalID */
0x02, /* wTerminalType: Headphones */
0x03,
0x00, /* bAssocTerminal */
0x02, /* bSourceID */
0x00, /* iTerminal */
/* Audio Control Input Terminal Descriptor */
0x0C, /* bLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x02, /* bDescriptorSubtype: INPUT_TERMINAL */
0x04, /* bTerminalID */
0x01, /* wTerminalType: Microphone */
0x02,
0x00, /* bAssocTerminal */
0x01, /* bNrChannels */
0x04, /* wChannelConfig */
0x00,
0x00, /* iChannelNames */
0x00, /* iTerminal */
/* Audio Control Feature Unit Descriptor */
0x0B, /* bLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x06, /* bDescriptorSubtype: FEATURE_UNIT */
0x05, /* bUnitID */
0x04, /* bSourceID */
0x02, /* bControlSize */
0x01,
0x00,
0x02,
0x00,
0x00, /* iFeature */
/* Audio Control Output Terminal Descriptor */
0x09, /* bLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x03, /* bDescriptorSubtype: OUTPUT_TERMINAL */
0x06, /* bTerminalID */
0x01, /* wTerminalType: USB streaming */
0x01,
0x00, /* bAssocTerminal */
0x05, /* bSourceID */
0x00, /* iTerminal */
/* Audio Interface_1/0 Descriptor */
0x09, /* bLength */
0x04, /* bDescriptorType */
0x01, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x00, /* bNumEndpoints */
0x01, /* bInterfaceClass: Audio */
0x02, /* bInterfaceSubClass: Audio Streaming */
0x00, /* bInterfaceProtocol */
0x00, /* iConfiguration */
/* HID Interface_1/1 Descriptor */
0x09, /* bLength */
0x04, /* bDescriptorType */
0x01, /* bInterfaceNumber */
0x01, /* bAlternateSetting */
0x01, /* bNumEndpoints */
0x01, /* bInterfaceClass: Audio */
0x02, /* bInterfaceSubClass: Audio Streaming */
0x00, /* bInterfaceProtocol */
0x00, /* iConfiguration */
/* Class-Specific AS Interface Descriptor */
0x07, /* bLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x01, /* bDescriptorSubtype: AS_GENERAL */
0x01, /* bTerminalLink */
0x00, /* bDelay */
0x01, /* wFormatTag: PCM */
0x00,
/* Class-Specific AS Format Type Descriptor */
0x14, /* bLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x02, /* bDescriptorSubtype: FORMAT_TYPE */
0x01, /* bFormatType: FORMAT_TYPE_I */
0x02, /* bNrChannels */
2, /* bSubframeSize: 2-Byte */
16, /* bBitResolution: 16-bit */
0x04, /* bSamFreqType */
0x80, /* tSamFreq [1] : 16K */
0x3E,
0x00,
0x00, /* tSamFreq [2] : 32K */
0x7D,
0x00,
0x80, /* tSamFreq [3] : 48K */
0xBB,
0x00,
0x00, /* tSamFreq [4] : 96K */
0x77,
0x01,
/* Endpoint 2 Descriptor */
0x09, /* bLength */
0x05, /* bDescriptorType */
0x02, /* bEndpointAddress: OUT 2 */
0x0D, /* bmAttributes: Isochronous */
0x00, /* wMaxPacketSize: 512byte */
0x02,
0x01, /* bInterval */
0x00, /* bRefresh */
0x00, /* bSynchAddress */
/* Audio Streaming Isochronous Audio Data Endpoint Descriptor */
0x07, /* bLength */
0x25, /* bDescriptorType: CS_ENDPOINT */
0x01, /* bDescriptorSubtype: EP_GENERAL */
0x01, /* bmAttributes */
0x01, /* bLockDelayUnits */
0x01, /* wLockDelay */
0x00, /* */
/* HID Interface_1/2 Descriptor */
0x09, /* bLength */
0x04, /* bDescriptorType */
0x01, /* bInterfaceNumber */
0x02, /* bAlternateSetting */
0x01, /* bNumEndpoints */
0x01, /* bInterfaceClass: Audio */
0x02, /* bInterfaceSubClass: Audio Streaming */
0x00, /* bInterfaceProtocol */
0x00, /* iConfiguration */
/* Class-Specific AS Interface Descriptor */
0x07, /* bLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x01, /* bDescriptorSubtype: AS_GENERAL */
0x01, /* bTerminalLink */
0x00, /* bDelay */
0x01, /* wFormatTag: PCM */
0x00,
/* Class-Specific AS Format Type Descriptor */
0x0B, /* bLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x02, /* bDescriptorSubtype: FORMAT_TYPE */
0x01, /* bFormatType: FORMAT_TYPE_I */
0x02, /* bNrChannels */
3, /* bSubframeSize: 3-Byte */
24, /* bBitResolution: 24-bit */
0x04, /* bSamFreqType */
0x80, /* tSamFreq [1] : 48K */
0xBB,
0x00,
/* Endpoint 2 Descriptor */
0x09, /* bLength */
0x05, /* bDescriptorType */
0x02, /* bEndpointAddress: OUT 2 */
0x0D, /* bmAttributes: Isochronous */
0x00, /* wMaxPacketSize: 512byte */
0x02,
0x01, /* bInterval */
0x00, /* bRefresh */
0x00, /* bSynchAddress */
/* Audio Streaming Isochronous Audio Data Endpoint Descriptor */
0x07, /* bLength */
0x25, /* bDescriptorType: CS_ENDPOINT */
0x01, /* bDescriptorSubtype: EP_GENERAL */
0x01, /* bmAttributes */
0x01, /* bLockDelayUnits */
0x01, /* wLockDelay */
0x00, /* */
/* Audio Interface_2/0 Descriptor */
0x09, /* bLength */
0x04, /* bDescriptorType */
0x02, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x00, /* bNumEndpoints */
0x01, /* bInterfaceClass: Audio */
0x02, /* bInterfaceSubClass: Audio Streaming */
0x00, /* bInterfaceProtocol */
0x00, /* iConfiguration */
/* Audio Interface_2/1 Descriptor */
0x09, /* bLength */
0x04, /* bDescriptorType */
0x02, /* bInterfaceNumber */
0x01, /* bAlternateSetting */
0x01, /* bNumEndpoints */
0x01, /* bInterfaceClass: Audio */
0x02, /* bInterfaceSubClass: Audio Streaming */
0x00, /* bInterfaceProtocol */
0x00, /* iConfiguration */
/* Class-Specific AS Interface Descriptor */
0x07, /* bLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x01, /* bDescriptorSubtype: AS_GENERAL */
0x06, /* bTerminalLink */
0x00, /* bDelay */
0x01, /* wFormatTag: PCM */
0x00,
/* Class-Specific AS Format Type Descriptor */
0x14, /* bLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x02, /* bDescriptorSubtype: FORMAT_TYPE */
0x01, /* bFormatType: FORMAT_TYPE_I */
0x01, /* bNrChannels */
0x02, /* bSubframeSize */
0x10, /* bBitResolution */
0x04, /* bSamFreqType */
0x80, /* tSamFreq [1] */
0x3E,
0x00,
0x00, /* tSamFreq [2] */
0x7D,
0x00,
0x80, /* tSamFreq [3] */
0xBB,
0x00,
0x00, /* tSamFreq [4] */
0x77,
0x01,
/* Endpoint 1 Descriptor */
0x09, /* bLength */
0x05, /* bDescriptorType */
0x81, /* bEndpointAddress: IN 1 */
0x0D, /* bmAttributes: Isochronous */
0x00, /* wMaxPacketSize: 256byte */
0x01,
0x01, /* bInterval */
0x00, /* bRefresh */
0x00, /* bSynchAddress */
/* Audio Streaming Isochronous Audio Data Endpoint Descriptor */
0x07, /* bLength */
0x25, /* bDescriptorType: CS_ENDPOINT */
0x01, /* bDescriptorSubtype: EP_GENERAL */
0x00, /* bmAttributes */
0x01, /* bLockDelayUnits */
0x01, /* wLockDelay */
0x00,
/* HID Interface_3/0 Descriptor */
0x09, /* bLength */
0x04, /* bDescriptorType */
0x03, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x01, /* bNumEndpoints */
0x03, /* bInterfaceClass: HID */
0x00, /* bInterfaceSubClass */
0x00, /* bInterfaceProtocol */
0x00, /* iConfiguration */
/* HID Descriptor */
0x09, /* bLength */
0x21, /* bDescriptorType: HID */
0x10, /* bcdHID: 1.10 */
0x01,
0x21, /* bCountryCode */
0x01, /* bNumDescriptors */
0x22, /* bDescriptorType: Report */
0x2A, /* wDescriptorLength */
0x00,
/* Endpoint 2 Descriptor */
0x07, /* bLength */
0x05, /* bDescriptorType */
0x82, /* bEndpointAddress: IN 2 */
0x03, /* bmAttributes: Interrupt */
0x02, /* wMaxPacketSize: 2byte */
0x00,
0x14, /* bInterval: 20ms */
};
/* USB Standard Manufacture Descriptor */
const uint8_t USB_Audio_ManufactureDesc[] =
{
0x12, /* bLength */
0x03, /* bDescriptorType */
'F', 0x00, /* BString */
'R', 0x00,
'E', 0x00,
'Q', 0x00,
'C', 0x00,
'H', 0x00,
'I', 0x00,
'P', 0x00,
};
/* USB Standard Product Descriptor */
const uint8_t USB_Audio_ProductDesc[] =
{
0x1E, /* bLength */
0x03, /* bDescriptorType */
'F', 0x00, /* BString */
'R', 0x00,
'E', 0x00,
'Q', 0x00,
'C', 0x00,
'H', 0x00,
'I', 0x00,
'P', 0x00,
'-', 0x00,
'A', 0x00,
'u', 0x00,
'd', 0x00,
'i', 0x00,
'o', 0x00,
};
/* USB Standard SerialNumber Descriptor */
const uint8_t USB_Audio_SerialNumberDesc[] =
{
0x1E, /* bLength */
0x03, /* bDescriptorType */
'2', 0x00, /* BString */
'0', 0x00,
'2', 0x00,
'1', 0x00,
'-', 0x00,
'1', 0x00,
'0', 0x00,
'0', 0x00,
'1', 0x00,
'-', 0x00,
'B', 0x00,
'1', 0x00,
'3', 0x00,
'6', 0x00,
};
/* USB Standard LanuageID Descriptor */
const uint8_t USB_Audio_LanuageIDDesc[] =
{
0x04, /* bLength */
0x03, /* bDescriptorType */
0x09, /* BString */
0x04,
};
/* HID device report Descriptor */
uint8_t USB_HID_Audio_ReportDesc[] =
{
0x2A, /* Length */
0x06, 0x0C, 0x00,
0x09, 0x01,
0xA1, 0x01,
0x25, 0x01,
0x15, 0x00,
0x0A, 0xE2, 0x00, /* Mute */
0x0A, 0xEA, 0x00, /* Volume Decrement */
0x0A, 0xE9, 0x00, /* Volume Increment */
0x0A, 0xB6, 0x00, /* Scan Previous Track */
0x0A, 0xCD, 0x00, /* Play/Pause */
0x0A, 0xB5, 0x00, /* Scan Next Track */
0x0A, 0xB7, 0x00, /* STOP */
0x0A, 0xB7, 0x00, /* STOP */
0x75, 0x01,
0x95, 0x08,
0x81, 0x02,
0xC0,
};
/*********************************************************************
* @fn usb_hid_set_Audio_report
*
* @brief set report
*/
void usb_hid_set_Audio_report(uint8_t fu8_Value)
{
gu8_AudioReport = fu8_Value;
}
/*********************************************************************
* @fn usb_hid_send_Audio_report
*
* @brief set report
*/
int usb_hid_send_Audio_report(void)
{
usb_selecet_endpoint(ENDPOINT_2);
if (usb_Endpoints_GET_TxPktRdy() == false)
{
usb_write_fifo(ENDPOINT_2, &gu8_AudioReport, 1);
usb_Endpoints_SET_TxPktRdy();
}
else
{
return -1;
}
return 0;
}
/*********************************************************************
* @fn usb_Audio_SetControl
*
* @brief Set Speaker volume, Set microphone volume
* Set Speaker Mute, Set microphone Mute
* Set Speaker sampling frequency, Set microphone sampling frequency
*/
static void usb_Audio_SetControl(void)
{
uint8_t lu8_RxCount;
lu8_RxCount = usb_Endpoint0_get_RxCount();
switch (ge_CTLIndex)
{
case AUDIO_SET_VOL_SPEAKER: usb_read_fifo(ENDPOINT_0, (uint8_t *)&gu16_VolumeSpeaker, lu8_RxCount); break;
case AUDIO_SET_VOL_MIC: usb_read_fifo(ENDPOINT_0, (uint8_t *)&gu16_VolumeMic, lu8_RxCount); break;
case AUDIO_SET_MUTE_SPEAKER: usb_read_fifo(ENDPOINT_0, (uint8_t *)&gu8_MuteSpeaker, lu8_RxCount); break;
case AUDIO_SET_MUTE_MIC: usb_read_fifo(ENDPOINT_0, (uint8_t *)&gu8_MuteMic, lu8_RxCount); break;
case AUDIO_SET_SAMPLING_SPEAKER:
{
usb_read_fifo(ENDPOINT_0, (uint8_t *)&gu32_SamplingFreqSpeaker, lu8_RxCount);
void usb_Audio_ChangeSamplingRate_callback(uint8_t Index);
usb_Audio_ChangeSamplingRate_callback(AUDIO_SET_SAMPLING_SPEAKER);
}break;
case AUDIO_SET_SAMPLING_MIC:
{
usb_read_fifo(ENDPOINT_0, (uint8_t *)&gu32_SamplingFreqMic, lu8_RxCount);
void usb_Audio_ChangeSamplingRate_callback(uint8_t Index);
usb_Audio_ChangeSamplingRate_callback(AUDIO_SET_SAMPLING_MIC);
}break;
default: break;
}
usb_Endpoint0_FlushFIFO();
Endpoint_0_DataOut_Handler = NULL;
}
/*********************************************************************
* @fn usb_Audio_ClassRequest_Handler
*
* @brief Audio Class Request Handler
*
* @param None.
* @return None.
*/
static void usb_Audio_ClassRequest_Handler(usb_StandardRequest_t* pStandardRequest, usb_ReturnData_t* pReturnData)
{
if (pStandardRequest->bmRequestType & RECIPIENT_INTERFACE)
{
switch (pStandardRequest->bRequest)
{
case GET_CUR:
{
if (pStandardRequest->wValue[1] == MUTE_CONTROL)
{
if (pStandardRequest->wIndex[1] == 0x02)
{
gu8_Respond[0] = gu8_MuteSpeaker;
}
else if (pStandardRequest->wIndex[1] == 0x05)
{
gu8_Respond[0] = gu8_MuteMic;
}
pReturnData->DataBuffer = gu8_Respond;
pReturnData->DataLength = 1;
}
else if (pStandardRequest->wValue[1] == VOLUME_CONTROL)
{
if (pStandardRequest->wIndex[1] == 0x02)
{
gu8_Respond[0] = gu16_VolumeSpeaker & 0xFF;
gu8_Respond[1] = gu16_VolumeSpeaker >> 8 & 0xFF;
}
else if (pStandardRequest->wIndex[1] == 0x05)
{
gu8_Respond[0] = gu16_VolumeMic & 0xFF;
gu8_Respond[1] = gu16_VolumeMic >> 8 & 0xFF;
}
pReturnData->DataBuffer = gu8_Respond;
pReturnData->DataLength = 2;
}
}break;
case GET_MIN:
{
if (pStandardRequest->wValue[1] == VOLUME_CONTROL)
{
gu8_Respond[0] = 0x00;
gu8_Respond[1] = 0x00;
pReturnData->DataBuffer = gu8_Respond;
pReturnData->DataLength = 2;
}
}break;
case GET_MAX:
{
if (pStandardRequest->wValue[1] == VOLUME_CONTROL)
{
gu8_Respond[0] = USB_AUDIO_VOLUME_MAX;
gu8_Respond[1] = 0x00;
pReturnData->DataBuffer = gu8_Respond;
pReturnData->DataLength = 2;
}
}break;
case GET_RES:
{
if (pStandardRequest->wValue[1] == VOLUME_CONTROL)
{
gu8_Respond[0] = 0x01;
gu8_Respond[1] = 0x00;
pReturnData->DataBuffer = gu8_Respond;
pReturnData->DataLength = 2;
}
}break;
case SET_CUR:
{
if (pStandardRequest->wValue[1] == VOLUME_CONTROL)
{
/* Speaker */
if (pStandardRequest->wIndex[1] == 0x02)
{
ge_CTLIndex = AUDIO_SET_VOL_SPEAKER;
}
/* microphone */
else if (pStandardRequest->wIndex[1] == 0x05)
{
ge_CTLIndex = AUDIO_SET_VOL_MIC;
}
Endpoint_0_DataOut_Handler = usb_Audio_SetControl;
}
else if (pStandardRequest->wValue[1] == MUTE_CONTROL)
{
/* Speaker */
if (pStandardRequest->wIndex[1] == 0x02)
{
ge_CTLIndex = AUDIO_SET_MUTE_SPEAKER;
}
/* microphone */
else if (pStandardRequest->wIndex[1] == 0x05)
{
ge_CTLIndex = AUDIO_SET_MUTE_MIC;
}
Endpoint_0_DataOut_Handler = usb_Audio_SetControl;
}
}
default: break;
}
}
else if (pStandardRequest->bmRequestType & RECIPIENT_ENDPOINT)
{
switch (pStandardRequest->bRequest)
{
case SET_CUR:
{
if (pStandardRequest->wValue[1] == SAMPLING_FREQ_CONTROL)
{
/* IN Endpoint */
if (pStandardRequest->wIndex[0] == 0x81)
{
ge_CTLIndex = AUDIO_SET_SAMPLING_MIC;
}
/* OUT Endpoint */
else if (pStandardRequest->wIndex[0] == 0x02)
{
ge_CTLIndex = AUDIO_SET_SAMPLING_SPEAKER;
}
Endpoint_0_DataOut_Handler = usb_Audio_SetControl;
}
}break;
default: break;
}
}
}
/*********************************************************************
* @fn usb_hid_StandardClassRequest_Handler
*
* @brief HID Standard Class Request Handler
*
* @param None.
* @return None.
*/
static void usb_hid_StandardClassRequest_Handler(usb_StandardRequest_t* pStandardRequest, usb_ReturnData_t* pReturnData)
{
switch (pStandardRequest->wValue[1])
{
case DESCRIPTOR_HID_REPORT:
{
if (pStandardRequest->wIndex[0] == 3){
pReturnData->DataLength = USB_HID_Audio_ReportDesc[0];
pReturnData->DataBuffer = &USB_HID_Audio_ReportDesc[1];
}
}break;
default: break;
}
}
extern volatile uint16_t MIC_Buffer[960];
extern volatile uint32_t MIC_Packet;
extern volatile uint32_t MIC_RxCount;
extern volatile uint32_t MIC_TxCount;
extern volatile bool MIC_Start;
extern volatile uint32_t Speaker_Buffer[192 * 2 * 10];
extern volatile uint32_t Speaker_Packet;
extern volatile uint32_t Speaker_RxCount;
extern volatile uint32_t Speaker_TxCount;
extern volatile bool Speaker_Start;
/*********************************************************************
* @fn usb_Audio_Endpoints_Handler
*
* @brief Audio Endpoints Handler
*
*/
void usb_Audio_Endpoints_Handler(uint8_t RxStatus, uint8_t TxStatus)
{
uint32_t lu32_RxCount;
/* ENDPOINT_2 Rx */
if (RxStatus & 0x04)
{
/* Receive audio playback data */
usb_selecet_endpoint(ENDPOINT_2);
if (usb_Endpoints_GET_RxPktRdy())
{
switch (gu32_BitWidthSpeaker)
{
case USB_AUDIO_DATA_WIDTH_16BIT:
{
lu32_RxCount = usb_Endpoints_get_RxCount_16bit();
usb_read_fifo(ENDPOINT_2, (uint8_t *)&Speaker_Buffer[gu32_PacketLengthSpeaker * Speaker_Packet], lu32_RxCount);
usb_Endpoints_FlushRxFIFO();
Speaker_Packet += 1;
if (Speaker_Packet >= 10)
{
Speaker_Packet = 0;
}
Speaker_RxCount = Speaker_Packet * gu32_PacketLengthSpeaker;
if (Speaker_Packet >= 5 && Speaker_Start == false)
{
Speaker_Start = true;
}
}break;
case USB_AUDIO_DATA_WIDTH_24BIT:
{
lu32_RxCount = usb_Endpoints_get_RxCount_16bit();
uint32_t BufferIndex = (gu32_PacketLengthSpeaker * 2) * Speaker_Packet;
for(int i = 0; i < lu32_RxCount/3; i++)
usb_read_fifo(ENDPOINT_2, (uint8_t *)&Speaker_Buffer[BufferIndex + i], 3);
usb_Endpoints_FlushRxFIFO();
Speaker_Packet += 1;
if (Speaker_Packet >= 10)
{
Speaker_Packet = 0;
}
Speaker_RxCount = Speaker_Packet * (gu32_PacketLengthSpeaker * 2);
if (Speaker_Packet >= 5 && Speaker_Start == false)
{
Speaker_Start = true;
}
}break;
default:break;
}
}
}
/* ENDPOINT_1 Tx */
if (TxStatus & 0x02)
{
/* Send microphone data to Host */
if (MIC_Start)
{
usb_selecet_endpoint(ENDPOINT_1);
if (usb_Endpoints_GET_TxPktRdy() == false)
{
usb_write_fifo(ENDPOINT_1, (uint8_t *)&MIC_Buffer[MIC_TxCount], gu32_PacketLengthMic*2);
usb_Endpoints_SET_TxPktRdy();
MIC_TxCount += gu32_PacketLengthMic;
if (MIC_TxCount >= gu32_PacketLengthMic*10)
{
MIC_TxCount = 0;
}
}
}
}
}
void usb_Audio_InterfaceAlternateSet_callback(uint8_t Interface)
{
switch (Interface)
{
/* Speaker Interface */
case 1:
{
/* Change the data bit width */
if (usbdev_get_interface_alternate_num(1) == 1)
gu32_BitWidthSpeaker = USB_AUDIO_DATA_WIDTH_16BIT;
else if (usbdev_get_interface_alternate_num(1) == 2)
gu32_BitWidthSpeaker = USB_AUDIO_DATA_WIDTH_24BIT;
}break;
default:break;
}
}
void usb_Audio_ChangeSamplingRate_callback(uint8_t Index)
{
switch (Index)
{
/* Change the Speaker sampling rate */
case AUDIO_SET_SAMPLING_SPEAKER:
{
gu32_PacketLengthSpeaker = gu32_SamplingFreqSpeaker/1000;
}break;
/* Change the Mic sampling rate */
case AUDIO_SET_SAMPLING_MIC:
{
gu32_PacketLengthMic = gu32_SamplingFreqMic/1000;
}break;
default:break;
}
}
uint32_t usb_Audio_get_Speaker_Packet_Length(void)
{
return gu32_PacketLengthSpeaker;
}
uint32_t usb_Audio_get_Mic_Packet_Length(void)
{
return gu32_PacketLengthMic;
}
uint32_t usb_Audio_get_Speaker_Bit_Width(void)
{
return gu32_BitWidthSpeaker;
}
uint32_t usb_Audio_get_Mic_Bit_Width(void)
{
return gu32_BitWidthMic;
}
uint32_t usb_Audio_get_Speaker_Mute_status(void)
{
return gu8_MuteSpeaker;
}
uint32_t usb_Audio_get_Mic_Mute_status(void)
{
return gu8_MuteMic;
}
uint32_t usb_Audio_get_Speaker_Volume(void)
{
return gu16_VolumeSpeaker;
}
uint32_t usb_Audio_get_Mic_Volume(void)
{
return gu16_VolumeMic;
}
uint32_t usb_Audio_get_Speaker_SamplingFreq(void)
{
return gu32_SamplingFreqSpeaker;
}
uint32_t usb_Audio_get_Mic_SamplingFreq(void)
{
return gu32_SamplingFreqMic;
}
/*********************************************************************
* @fn usb_audio_init
*
* @brief audio device parameter initialization
*
* @param None.
* @return None.
*/
void usb_audio_init(void)
{
/* Initialize the relevant pointer */
usbdev_get_dev_desc((uint8_t *)USB_Audio_DeviceDesc);
usbdev_get_config_desc((uint8_t *)USB_Audio_ConfigurationDesc);
usbdev_get_string_Manufacture((uint8_t *)USB_Audio_ManufactureDesc);
usbdev_get_string_Product((uint8_t *)USB_Audio_ProductDesc);
usbdev_get_string_SerialNumber((uint8_t *)USB_Audio_SerialNumberDesc);
usbdev_get_string_LanuageID((uint8_t *)USB_Audio_LanuageIDDesc);
Endpoint_0_StandardClassRequest_Handler = usb_hid_StandardClassRequest_Handler;
Endpoint_0_ClassRequest_Handler = usb_Audio_ClassRequest_Handler;
Endpoints_Handler = usb_Audio_Endpoints_Handler;
USB_InterfaceAlternateSet_callback = usb_Audio_InterfaceAlternateSet_callback;
USB_Reset_Handler = usb_audio_init;
/* config data endpoint fifo */
usb_selecet_endpoint(ENDPOINT_1);
usb_TxSyncEndpoint_enable();
usb_endpoint_Txfifo_config(64/8, 5); /* 256 Byte, 64 ~ 319 */
usb_TxMaxP_set(256/8);
usb_selecet_endpoint(ENDPOINT_2);
usb_RxSyncEndpoint_enable();
usb_endpoint_Rxfifo_config(320/8, 6); /* 512 Byte, 320 ~ 831 */
usb_RxMaxP_set(512/8);
usb_endpoint_Txfifo_config(832/8, 1); /* 16 Byte, 832 ~ 464 */
usb_TxMaxP_set(16/8);
usb_TxInt_Enable(ENDPOINT_1);
usb_RxInt_Enable(ENDPOINT_2);
}

View File

@ -0,0 +1,518 @@
/*
******************************************************************************
* @file usb_cdc.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief This file provides the high layer firmware functions to manage the
* USB CDC Class.(Communication Device Class)
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
*
******************************************************************************
* How to use, for example:
*
* int main(void)
* {
* NVIC_ClearPendingIRQ(USBMCU_IRQn);
* NVIC_SetPriority(USBMCU_IRQn, 0);
* NVIC_EnableIRQ(USBMCU_IRQn);
*
* usb_device_init();
* usb_cdc_init();
*
* // Wait for other initialization of the MCU
* while(1)
* {
* usb_cdc_serialReceive();
* }
* }
******************************************************************************
*/
#include "usb_cdc.h"
extern UART_HandleTypeDef Uart_CDC_handle;
#define CDC_MAX_PACK (64) /* Fixed 64 bytes */
#define CDC_MAX_IN_PACK (1024) /* IN Endpoint max pack buffer */
volatile bool COM_Activate = false;
volatile uint32_t Tx_Count = 0;
volatile uint32_t Tx_Total = 0;
uint8_t RxBuffer[CDC_MAX_PACK];
uint8_t TxBuffer[CDC_MAX_IN_PACK];
USBD_CDC_LineCodingTypeDef LineCoding;
/* USB Standard Device Descriptor */
const uint8_t USB_CDC_DeviceDesc[] =
{
0x12, /* bLength */
0x01, /* bDescriptorType */
0x00, /* bcdUSB */
0x02,
0x02, /* bDeviceClass */
0x02, /* bDeviceSubClass */
0x00, /* bDeviceProtocol */
0x40, /* bMaxPacketSize */
0xAA, /* idVendor */
0xFF, /* idVendor */
0x55, /* idProduct */
0x55, /* idProduct */
0x00, /* bcdDevice rel. 2.00 */
0x20,
0x01, /* Index of manufacturer string */
0x02, /* Index of product string */
0x03, /* Index of serial number string */
0x01, /* bNumConfigurations */
};
/* USB Standard Configuration Descriptor */
const uint8_t USB_CDC_ConfigurationDesc[] =
{
/* Configuration Descriptor */
0x09, /* bLength */
0x02, /* bDescriptorType */
0x43, /* wTotalLength */
0x00,
0x02, /* bNumInterfaces */
0x01, /* bConfigurationValue */
0x00, /* iConfiguration */
0xC0, /* bmAttributes */
0x32, /* bMaxPower */
/* CDC Interface Descriptor */
0x09, /* bLength */
0x04, /* bDescriptorType */
0x00, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x01, /* bNumEndpoints */
0x02, /* bInterfaceClass */
0x02, /* bInterfaceSubClass */
0x01, /* bInterfaceProtocol */
0x00, /* iConfiguration */
/* Header Functional Descriptor */
0x05, /* bLength: Endpoint Descriptor size */
0x24, /* bDescriptorType: CS_INTERFACE */
0x00, /* bDescriptorSubtype: Header Func Desc */
0x10, /* bcdCDC: spec release number */
0x01,
/* Call Management Functional Descriptor */
0x05, /* bFunctionLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x01, /* bDescriptorSubtype: Call Management Func Desc */
0x00, /* bmCapabilities: D0+D1 */
0x01, /* bDataInterface: 1 */
/* ACM Functional Descriptor */
0x04, /* bFunctionLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x02, /* bDescriptorSubtype: Abstract Control Management desc */
0x02, /* bmCapabilities */
/* Union Functional Descriptor */
0x05, /* bFunctionLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x06, /* bDescriptorSubtype: Union func desc */
0x00, /* bMasterInterface: Communication class interface */
0x01, /* bSlaveInterface0: Data Class Interface */
/* Endpoint 2 Descriptor */
0x07, /* bLength */
0x05, /* bDescriptorType */
0x82, /* bEndpointAddress */
0x03, /* bmAttributes: Interrupt */
0x08, /* wMaxPacketSize: */
0x00,
0x10, /* bInterval */
/* Data class interface descriptor */
0x09, /* bLength */
0x04, /* bDescriptorType */
0x01, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x02, /* bNumEndpoints */
0x0A, /* bInterfaceClass */
0x00, /* bInterfaceSubClass */
0x00, /* bInterfaceProtocol */
0x00, /* iConfiguration */
/* Endpoint OUT Descriptor */
0x07, /* bLength */
0x05, /* bDescriptorType */
0x01, /* bEndpointAddress */
0x02, /* bmAttributes: Bulk */
0x40, /* wMaxPacketSize */
0x00,
0x00, /* bInterval */
/* Endpoint IN Descriptor */
0x07, /* bLength */
0x05, /* bDescriptorType */
0x81, /* bEndpointAddress */
0x02, /* bmAttributes: Bulk */
0x40, /* wMaxPacketSize */
0x00,
0x00, /* bInterval */
};
/* USB Standard Manufacture Descriptor */
const uint8_t USB_CDC_ManufactureDesc[] =
{
0x12, /* bLength */
0x03, /* bDescriptorType */
'F', 0x00, /* BString */
'R', 0x00,
'E', 0x00,
'Q', 0x00,
'C', 0x00,
'H', 0x00,
'I', 0x00,
'P', 0x00,
};
/* USB Standard Configuration Descriptor */
const uint8_t USB_CDC_ProductDesc[] =
{
0x1A, /* bLength */
0x03, /* bDescriptorType */
'F', 0x00, /* BString */
'R', 0x00,
'E', 0x00,
'Q', 0x00,
'C', 0x00,
'H', 0x00,
'I', 0x00,
'P', 0x00,
'-', 0x00,
'C', 0x00,
'O', 0x00,
'M', 0x00,
};
/* USB Standard Configuration Descriptor */
const uint8_t USB_CDC_SerialNumberDesc[] =
{
0x1E, /* bLength */
0x03, /* bDescriptorType */
'2', 0x00, /* BString */
'0', 0x00,
'2', 0x00,
'1', 0x00,
'-', 0x00,
'1', 0x00,
'0', 0x00,
'0', 0x00,
'1', 0x00,
'-', 0x00,
'A', 0x00,
'1', 0x00,
'3', 0x00,
'5', 0x00,
};
/* USB Standard Configuration Descriptor */
const uint8_t USB_CDC_LanuageIDDesc[] =
{
0x04, /* bLength */
0x03, /* bDescriptorType */
0x09, /* BString */
0x04,
};
/*********************************************************************
* @fn usb_cdc_serialReceive
*
* @brief serial port receives data
*
* @param None.
* @return None.
*/
void usb_cdc_serialReceive(void)
{
uint32_t SendLength;
while (!__UART_IS_RxFIFO_EMPTY(Uart_CDC_handle.UARTx))
{
TxBuffer[Tx_Total++] = __UART_READ_FIFO(Uart_CDC_handle.UARTx);
if (Tx_Total >= CDC_MAX_IN_PACK)
{
Tx_Total = 0;
}
}
/* have Data to be sent */
SendLength = Tx_Total >= Tx_Count ? Tx_Total - Tx_Count : CDC_MAX_IN_PACK - Tx_Count;
if (SendLength)
{
usb_selecet_endpoint(ENDPOINT_1);
if (usb_Endpoints_GET_TxPktRdy() == false)
{
if (SendLength > CDC_MAX_PACK)
{
usb_write_fifo(ENDPOINT_1, &TxBuffer[Tx_Count], CDC_MAX_PACK);
Tx_Count += CDC_MAX_PACK;
}
else
{
usb_write_fifo(ENDPOINT_1, &TxBuffer[Tx_Count], SendLength);
Tx_Count += SendLength;
}
if (Tx_Count >= CDC_MAX_IN_PACK)
{
Tx_Count = 0;
}
usb_Endpoints_SET_TxPktRdy();
}
}
}
/*********************************************************************
* @fn usb_cdc_serialSend
*
* @brief Sending data over a serial port
*
* @param None.
* @return None.
*/
static void usb_cdc_serialSend(uint8_t *Buffer, uint8_t Size)
{
while (Size--)
{
/* Tx empty */
while(__UART_IS_TxFIFO_FULL(Uart_CDC_handle.UARTx));
/* Send data */
__UART_WRITE_FIFO(Uart_CDC_handle.UARTx, *Buffer++);
}
}
/* CDC Line coding */
uint8_t CDC_LineCoding[7];
/*********************************************************************
* @fn usb_cdc_SetLineCoding
*
* @brief receive Host data and Set Line Coding
*
* @param None.
* @return None.
*/
static void usb_cdc_SetLineCoding(void)
{
USBD_CDC_LineCodingTypeDef Temp_LineCoding;
uint8_t lu8_RxCount;
uint8_t lu8_UartLine;
lu8_RxCount = usb_Endpoint0_get_RxCount();
usb_read_fifo(ENDPOINT_0, CDC_LineCoding, lu8_RxCount);
usb_Endpoint0_FlushFIFO();
Endpoint_0_DataOut_Handler = NULL;
Temp_LineCoding.dwDTERate = CDC_LineCoding[0];
Temp_LineCoding.dwDTERate |= CDC_LineCoding[1] << 8;
Temp_LineCoding.dwDTERate |= CDC_LineCoding[2] << 16;
Temp_LineCoding.dwDTERate |= CDC_LineCoding[3] << 24;
Temp_LineCoding.bCharFormat = CDC_LineCoding[4];
Temp_LineCoding.bParityType = CDC_LineCoding[5];
Temp_LineCoding.bDataBits = CDC_LineCoding[6];
/* Modify the uart configuration */
if (LineCoding.dwDTERate != Temp_LineCoding.dwDTERate)
{
LineCoding.dwDTERate = Temp_LineCoding.dwDTERate;
Uart_CDC_handle.Init.BaudRate = LineCoding.dwDTERate;
uart_config_baudRate(&Uart_CDC_handle);
}
if (LineCoding.bCharFormat != Temp_LineCoding.bCharFormat ||
LineCoding.bParityType != Temp_LineCoding.bParityType ||
LineCoding.bDataBits != Temp_LineCoding.bDataBits)
{
LineCoding.bCharFormat = Temp_LineCoding.bCharFormat;
LineCoding.bParityType = Temp_LineCoding.bParityType;
LineCoding.bDataBits = Temp_LineCoding.bDataBits;
switch (LineCoding.bDataBits)
{
case 8: lu8_UartLine = 0x03; break;
case 7: lu8_UartLine = 0x02; break;
case 6: lu8_UartLine = 0x01; break;
case 5: lu8_UartLine = 0x00; break;
default: break;
}
switch (LineCoding.bCharFormat)
{
case 0: lu8_UartLine |= 0x03; break;
case 1:
case 2: lu8_UartLine |= 1 << 2; break;
default: break;
}
switch (LineCoding.bParityType)
{
case 1: lu8_UartLine |= (1 << 3); break;
case 2: lu8_UartLine |= (1 << 3) | (1 << 4); break;
default: break;
}
__UART_SET_LINE_CTRL(Uart_CDC_handle.UARTx, lu8_UartLine);
}
}
/*********************************************************************
* @fn usb_cdc_ClassRequest_Handler
*
* @brief CDC Class Request Handler
*
* @param None.
* @return None.
*/
static void usb_cdc_ClassRequest_Handler(usb_StandardRequest_t* pStandardRequest, usb_ReturnData_t* pReturnData)
{
switch (pStandardRequest->bRequest)
{
case CDC_SET_LINE_CODING:
{
/* Host data out */
Endpoint_0_DataOut_Handler = usb_cdc_SetLineCoding;
}break;
case CDC_GET_LINE_CODING:
{
CDC_LineCoding[0] = (LineCoding.dwDTERate >> 0) & 0xFF;
CDC_LineCoding[1] = (LineCoding.dwDTERate >> 8) & 0xFF;
CDC_LineCoding[2] = (LineCoding.dwDTERate >> 16) & 0xFF;
CDC_LineCoding[3] = (LineCoding.dwDTERate >> 24) & 0xFF;
CDC_LineCoding[4] = LineCoding.bCharFormat;
CDC_LineCoding[5] = LineCoding.bParityType;
CDC_LineCoding[6] = LineCoding.bDataBits;
pReturnData->DataBuffer = CDC_LineCoding;
pReturnData->DataLength = sizeof(CDC_LineCoding);
}break;
case CDC_SET_CONTROL_LINE_STATE:
{
/* COM acitvate or inacitvate */
if (pStandardRequest->wValue[0])
{
COM_Activate = true;
}
else
{
COM_Activate = false;
}
/* clear count */
Tx_Count = 0;
Tx_Total = 0;
/* Flush FIFO */
usb_selecet_endpoint(ENDPOINT_1);
usb_Endpoints_FlushRxFIFO();
usb_Endpoints_FlushTxFIFO();
usb_selecet_endpoint(ENDPOINT_0);
}break;
default: break;
}
}
/*********************************************************************
* @fn usb_cdc_OtherEndpoints_Handler
*
* @brief CDC other Endpoints handler
*
* @param None.
* @return None.
*/
static void usb_cdc_OtherEndpoints_Handler(uint8_t RxStatus, uint8_t TxStatus)
{
uint8_t lu8_RxCount;
/* DATA OUT */
if (RxStatus & ENDPOINT_1_MASK)
{
usb_selecet_endpoint(ENDPOINT_1);
lu8_RxCount = usb_Endpoints_get_RxCount();
usb_read_fifo(ENDPOINT_1, RxBuffer, lu8_RxCount);
usb_cdc_serialSend(RxBuffer, lu8_RxCount);
usb_Endpoints_FlushRxFIFO();
}
}
/*********************************************************************
* @fn usb_cdc_init
*
* @brief CDC device parameter initialization
*
* @param None.
* @return None.
*/
void usb_cdc_init(void)
{
/* Initialize the relevant pointer */
usbdev_get_dev_desc((uint8_t *)USB_CDC_DeviceDesc);
usbdev_get_config_desc((uint8_t *)USB_CDC_ConfigurationDesc);
usbdev_get_string_Manufacture((uint8_t *)USB_CDC_ManufactureDesc);
usbdev_get_string_Product((uint8_t *)USB_CDC_ProductDesc);
usbdev_get_string_SerialNumber((uint8_t *)USB_CDC_SerialNumberDesc);
usbdev_get_string_LanuageID((uint8_t *)USB_CDC_LanuageIDDesc);
Endpoint_0_ClassRequest_Handler = usb_cdc_ClassRequest_Handler;
Endpoints_Handler = usb_cdc_OtherEndpoints_Handler;
USB_Reset_Handler = usb_cdc_init;
/* config data endpoint fifo */
usb_selecet_endpoint(ENDPOINT_1);
usb_endpoint_Txfifo_config(0x08, 3);
usb_endpoint_Rxfifo_config(0x10, 3);
usb_TxMaxP_set(8);
usb_RxMaxP_set(8);
usb_selecet_endpoint(ENDPOINT_2);
usb_endpoint_Txfifo_config(0x28, 1);
usb_RxMaxP_set(1);
/* Endpoint_1 Rx interrupt enable */
usb_RxInt_Enable(ENDPOINT_1);
LineCoding.dwDTERate = 115200;
LineCoding.bCharFormat = 0x00;
LineCoding.bParityType = 0x00;
LineCoding.bDataBits = 0x08;
}

View File

@ -0,0 +1,492 @@
/*
******************************************************************************
* @file usb_core.c
* @author FreqChip Firmware Team
* @version V1.1.0
* @date 2021
* @brief This file provides all the USB core functions.
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "usb_core.h"
/*********************************************************************
* @fn usb_device_init
*
* @brief Initializes the usb-otg as a device.
*/
void usb_device_init(void)
{
/* OTG_CID = 1 */
/* OTG_VBUS_LO = 1 */
/* OTG_VBUS_SES = 1 */
/* OTG_VBUS_VAL = 1 */
/* USB_PHY_ADP_CFG = 9 */
USB_OTG_CTRL = USB_OTG_CTRL_DEVICE_CFG;
/* Disable USB all Interrupt except endpoint0 and Bus reset*/
USB->IntrUSBE = 0x04; /* Enable Bus reset INT */
USB->IntrTx1E = 0x01; /* Enable Endpoint0 INT */
USB->IntrTx2E = 0x00;
USB->IntrRx1E = 0x00;
USB->IntrRx2E = 0x00;
}
/*********************************************************************
* @fn usb_host_init
*
* @brief Initializes the usb-otg as a host.
*/
void usb_host_init(void)
{
/* OTG_CID = 0 */
/* OTG_VBUS_LO = 1 */
/* OTG_VBUS_SES = 1 */
/* OTG_VBUS_VAL = 1 */
/* USB_PHY_ADP_CFG = 9 */
USB_OTG_CTRL = USB_OTG_CTRL_HOST_CFG;
/* Disable USB all Interrupt except endpoint0 and Bus reset*/
USB->IntrUSBE = 0x00; /* Enable Bus reset INT */
USB->IntrTx1E = 0x01; /* Enable Endpoint0 INT */
USB->IntrTx2E = 0x00;
USB->IntrRx1E = 0x00;
USB->IntrRx2E = 0x00;
}
/*********************************************************************
* @fn usb_selecet_endpoint
*
* @brief Selected Endpoint
*
* @param Endpoint : endpoint select.
* @return None.
*/
void usb_selecet_endpoint(enum_Endpoint_t Endpoint)
{
USB->Index = Endpoint;
}
/*********************************************************************
* @fn usb_get_endpoint
*
* @brief get current Endpoint
*
* @param None.
* @return current Endpoint
*/
uint8_t usb_get_endpoint(void)
{
return USB->Index;
}
/*********************************************************************
* @fn usb_set_address
*
* @brief set device address
*
* @param address : device address.
* @return None.
*/
void usb_set_address(uint8_t address)
{
USB->FAddr = address;
}
/*********************************************************************
* @fn usb_get_frame
*
* @brief get current frame number
*
* @param None.
* @return None.
*/
uint32_t usb_get_frame(void)
{
uint32_t lu32_Frame;
lu32_Frame = (uint32_t)USB->Frame2 << 8;
lu32_Frame |= (uint32_t)USB->Frame1;
return lu32_Frame;
}
/*********************************************************************
* @fn usb_TxEndpointSync_enable
*
* @brief Tx Synchronous endpoint enable
*/
void usb_TxSyncEndpoint_enable(void)
{
USB_POINTS->TxCSR2 |= USB_TXCSR2_ISO;
}
/*********************************************************************
* @fn usb_RxSyncEndpoint_enable
*
* @brief Rx Synchronous endpoint enable
*/
void usb_RxSyncEndpoint_enable(void)
{
USB_POINTS->RxCSR2 |= USB_RXCSR2_DEVICE_ISO;
}
/*********************************************************************
* @fn usb_SignalInt_Enable
*
* @brief Enable Signal detect interrupt.
*
* @param fu8_Signal : Signal select.
* @return None.
*/
void usb_SingleInt_Enable(uint8_t fu8_Signal)
{
USB->IntrUSBE |= fu8_Signal;
}
/*********************************************************************
* @fn usb_SignalInt_Disable
*
* @brief Disable Signal detect interrupt.
*
* @param fu8_Signal : Signal select.
* @return None.
*/
void usb_SignalInt_Disable(uint8_t fu8_Signal)
{
USB->IntrUSBE &= ~fu8_Signal;
}
/*********************************************************************
* @fn usb_TxInt_Enable
*
* @brief Enable transmit completion interrupt
*
* @param Endpoint : endpoint select.
* @return None.
*/
void usb_TxInt_Enable(enum_Endpoint_t Endpoint)
{
USB->IntrTx1E |= 1 << Endpoint;
}
/*********************************************************************
* @fn usb_TxInt_Disable
*
* @brief Disable transmit completion interrupt
*
* @param Endpoint : endpoint select.
* @return None.
*/
void usb_TxInt_Disable(enum_Endpoint_t Endpoint)
{
USB->IntrTx1E &= ~(1 << Endpoint);
}
/*********************************************************************
* @fn usb_RxInt_Enable
*
* @brief Enable receive completion interrupt
*
* @param Endpoint : endpoint select.
* @return None.
*/
void usb_RxInt_Enable(enum_Endpoint_t Endpoint)
{
if (Endpoint == ENDPOINT_0)
return;
USB->IntrRx1E |= 1 << Endpoint;
}
/*********************************************************************
* @fn usb_RxInt_Disable
*
* @brief Disable receive completion interrupt
*
* @param Endpoint : endpoint select.
* @return None.
*/
void usb_RxInt_Disable(enum_Endpoint_t Endpoint)
{
if (Endpoint == ENDPOINT_0)
return;
USB->IntrRx1E &= ~(1 << Endpoint);
}
/*********************************************************************
* @fn usb_endpoint_Txfifo_config
*
* @brief config Txfifo
*
* @param StartAddress: Start address of the endpoint FIFO.
* MaxPacket : Maximum packet size.
*
* @return None.
*/
void usb_endpoint_Txfifo_config(uint32_t StartAddress, uint32_t MaxPacket)
{
/* Start address of the endpoint FIFO in units of 8 TxFIFO1 bytes as follows: */
/* --------------------------------- */
/* | StartAddress | Address | */
/* | 0x00 | 0x000 | */
/* | 0x01 | 0x008 | */
/* | 0x02 | 0x010 | */
/* | ... | ... | */
/* | 0x7F | 0x3FF | */
/* --------------------------------- */
/* Maximum packet size to be allowed for */
/* --------------------------------------- */
/* | MaxPacket | Packet Size(Bytes) | */
/* | 0 | 8 | */
/* | 1 | 16 | */
/* | 2 | 32 | */
/* | 3 | 64 | */
/* | 4 | 128 | */
/* | 5 | 256 | */
/* | 6 | 512 | */
/* | 7 | 1024 | */
/* --------------------------------------- */
/* use only 7bit */
StartAddress &= 0x7F;
/* use only 3bit */
MaxPacket &= 0x7;
USB_POINTS->TxFIFO1 = StartAddress;
USB_POINTS->TxFIFO2 = MaxPacket << 5;
}
/*********************************************************************
* @fn usb_endpoint_Rxfifo_config
*
* @brief config Rxfifo
*
* @param StartAddress: Start address of the endpoint FIFO.
* MaxPacket : Maximum packet size.
*
* @return None.
*/
void usb_endpoint_Rxfifo_config(uint32_t StartAddress, uint32_t MaxPacket)
{
/*
reference usb_endpoint_Txfifo_config()
*/
/* use only 7bit */
StartAddress &= 0x7F;
/* use only 3bit */
MaxPacket &= 0x7;
USB_POINTS->RxFIFO1 = StartAddress;
USB_POINTS->RxFIFO2 = MaxPacket << 5;
}
/*********************************************************************
* @fn usb_TxMaxP_set
*
* @brief the maximum packet size for transactions through the
* currently-selected Tx endpoint
*
* @param MaxPacket: in units of 8 bytes
* @return None.
*/
void usb_TxMaxP_set(uint32_t MaxPacket)
{
/* Maximum packet size to be allowed for */
/* --------------------------------------- */
/* | MaxPacket | Packet Size(Bytes) | */
/* | 0 | 0 | */
/* | 1 | 8 | */
/* | 2 | 16 | */
/* | ... | ... | */
/* | 128 | 1024 | */
/* --------------------------------------- */
USB_POINTS->TxMaxP = MaxPacket;
}
/*********************************************************************
* @fn usb_RxMaxP_set
*
* @brief the maximum packet size for transactions through the
* currently-selected Rx endpoint
*
* @param MaxPacket: in units of 8 bytes
* @return None.
*/
void usb_RxMaxP_set(uint32_t MaxPacket)
{
/*
reference usb_TxMaxP_set()
*/
USB_POINTS->RxMaxP = MaxPacket;
}
/*********************************************************************
* @fn usb_Host_TxEndpointType
*
* @brief In host mode, the tx endpoint type select.
*
* @param fe_Type: Endpoint Type
* @return None.
*/
void usb_Host_TxEndpointType(enum_HostEndpointType_t fe_Type)
{
USB_POINTS->TxType &= ~USB_HOST_TXTYPE_PROTOCOL_MSK;
USB_POINTS->TxType |= fe_Type << USB_HOST_TXTYPE_PROTOCOL_POS;
}
/*********************************************************************
* @fn usb_Host_RxEndpointType
*
* @brief In host mode, the rx endpoint type select.
*
* @param fe_Type: Endpoint Type
* @return None.
*/
void usb_Host_RxEndpointType(enum_HostEndpointType_t fe_Type)
{
USB_POINTS->RxType &= ~USB_HOST_RXTYPE_PROTOCOL_MSK;
USB_POINTS->RxType |= fe_Type << USB_HOST_RXTYPE_PROTOCOL_POS;
}
/*********************************************************************
* @fn usb_Host_TxTargetEndpoint
*
* @brief The tx target endpoint number of the host transmit.
*
* @param fe_Type: Endpoint Type
* @return None.
*/
void usb_Host_TxTargetEndpoint(uint8_t fu8_TargetEndpointNum)
{
USB_POINTS->TxType &= ~USB_HOST_TXTYPE_TARGET_ENDP_NUM_MSK;
USB_POINTS->TxType |= fu8_TargetEndpointNum;
}
/*********************************************************************
* @fn usb_Host_RxTargetEndpoint
*
* @brief The rx target endpoint number of the host receive.
*
* @param fe_Type: Endpoint Type
* @return None.
*/
void usb_Host_RxTargetEndpoint(uint8_t fu8_TargetEndpointNum)
{
USB_POINTS->RxType &= ~USB_HOST_RXTYPE_TARGET_ENDP_NUM_MSK;
USB_POINTS->RxType |= fu8_TargetEndpointNum;
}
/*********************************************************************
* @fn usb_Host_TxPollingInterval
*
* @brief Tx Polling Interval in interrup or isochronous transfers.
* The unit is ms.(1 ~ 255)
*
* @param fu8_TxInterval: Polling interval.
* @return None.
*/
void usb_Host_TxPollingInterval(uint8_t fu8_TxInterval)
{
USB_POINTS->TxInterval = fu8_TxInterval;
}
/*********************************************************************
* @fn usb_Host_TxNAKLimit
*
* @brief Tx NAK limit in bulk transfer. NAK Limit 2 ~ 255.
* Note: A value of 0 or 1 disable the NAK timeout function.
*
* @param fu8_TxNAKLimit: Tx NAK limit value.
* @return None.
*/
void usb_Host_TxNAKLimit(uint8_t fu8_TxNAKLimit)
{
USB_POINTS->TxInterval = fu8_TxNAKLimit;
}
/*********************************************************************
* @fn usb_Host_RxPollingInterval
*
* @brief Rx Polling Interval in interrup or isochronous transfers.
* The unit is ms.(1 ~ 255)
*
* @param fu8_RxInterval: Polling interval.
* @return None.
*/
void usb_Host_RxPollingInterval(uint8_t fu8_RxInterval)
{
USB_POINTS->RxInterval = fu8_RxInterval;
}
/*********************************************************************
* @fn usb_Host_RxNAKLimit
*
* @brief Rx NAK limit in bulk transfer. NAK Limit 2 ~ 255.
* Note: A value of 0 or 1 disable the NAK timeout function.
*
* @param fu8_RxNAKLimit: Rx NAK limit value.
* @return None.
*/
void usb_Host_RxNAKLimit(uint8_t fu8_RxNAKLimit)
{
USB_POINTS->RxInterval = fu8_RxNAKLimit;
}
/*********************************************************************
* @fn usb_write_fifo
*
* @brief Write data to the endpoint fifo
*
* @param Endpoint : endpoint select.
* Buffer : transmit buffer pointer.
* Size : transmit Size.
* @return None.
*/
void usb_write_fifo(enum_Endpoint_t Endpoint, uint8_t *Buffer, uint32_t Size)
{
volatile uint8_t *fifo;
fifo = &USB_POINTS->FIFO[Endpoint * 4];
while (Size--)
{
*fifo = *Buffer++;
}
}
/*********************************************************************
* @fn usb_read_fifo
*
* @brief Reads data from the endpoint fifo
*
* @param Endpoint : endpoint select.
* Buffer : receive buffer pointer.
* Size : receive Size.
* @return None.
*/
void usb_read_fifo(enum_Endpoint_t Endpoint, uint8_t *Buffer, uint32_t Size)
{
volatile uint8_t *fifo;
fifo = &USB_POINTS->FIFO[Endpoint * 4];
while (Size--)
{
*Buffer++ = *fifo;
}
}

View File

@ -0,0 +1,620 @@
/*
******************************************************************************
* @file usb_dev.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief This file provides all the USBD device functions.
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "usb_dev.h"
uint16_t USB_Interface_Status; /* Interface status */
uint16_t USB_Device_Status = 0x0002; /* Device status */
uint16_t USB_IN_Endpoint_Status[5]; /* IN endpoints status */
uint16_t USB_OUT_Endpoint_Status[5]; /* OUT endpoints status */
uint8_t USB_Configuration; /* Configuration setting */
uint8_t USB_InterfaceAlternateSet[20]; /* Interface Alternate setting */
usb_DescriptorsTypeDef_t DevDescriptors;
usb_StandardRequest_t StandardRequest;
usb_ReturnData_t ReturnData;
void (*Endpoint_0_StandardClassRequest_Handler)(usb_StandardRequest_t* pStandardRequest, usb_ReturnData_t* pReturnData) = NULL;
void (*Endpoint_0_ClassRequest_Handler)(usb_StandardRequest_t* pStandardRequest, usb_ReturnData_t* pReturnData) = NULL;
void (*Endpoint_0_VendorRequest_Handler)(usb_StandardRequest_t* pStandardRequest, usb_ReturnData_t* pReturnData) = NULL;
void (*Endpoint_0_DataOut_Handler)(void) = NULL;
void (*Endpoints_Handler)(uint8_t RxStatus, uint8_t TxStatus) = NULL;
void (*USB_SOF_Handler)(void) = NULL;
void (*USB_Reset_Handler)(void) = NULL;
void (*USB_Resume_Handler)(void) = NULL;
void (*USB_Suspend_Handler)(void) = NULL;
void (*USB_Connect_Handler)(void) = NULL;
void (*USB_InterfaceAlternateSet_callback)(uint8_t Interface);
/*********************************************************************
* @fn usbdev_get_dev_desc
*
* @brief Get device descriptor buffer pointer.
*********************************************************************/
void usbdev_get_dev_desc(uint8_t *Descriptor)
{
DevDescriptors.DeviceDescriptor = Descriptor;
}
/*********************************************************************
* @fn usbdev_get_config_desc
*
* @brief USB full speed device Get Configuration<6F><6E>Interface<63><65>
* Endpoint Descriptor.
*********************************************************************/
void usbdev_get_config_desc(uint8_t *Descriptor)
{
DevDescriptors.ConfigurationDescriptor = Descriptor;
}
/*********************************************************************
* @fn usbdev_get_string_Manufacture
*
* @brief Get device Manufacture string Descriptor.
*********************************************************************/
void usbdev_get_string_Manufacture(uint8_t *Descriptor)
{
DevDescriptors.stringManufacture = Descriptor;
}
/*********************************************************************
* @fn usbdev_get_string_Product
*
* @brief Get device Product string Descriptor.
*********************************************************************/
void usbdev_get_string_Product(uint8_t *Descriptor)
{
DevDescriptors.stringProduct = Descriptor;
}
/*********************************************************************
* @fn usbdev_get_string_SerialNumber
*
* @brief Get device SerialNumber string Descriptor.
*********************************************************************/
void usbdev_get_string_SerialNumber(uint8_t *Descriptor)
{
DevDescriptors.stringSerialNumber = Descriptor;
}
/*********************************************************************
* @fn usbdev_get_string_LanuageID
*
* @brief Get device LanuageID string Descriptor.
*********************************************************************/
void usbdev_get_string_LanuageID(uint8_t *Descriptor)
{
DevDescriptors.stringLanuageID = Descriptor;
}
/*********************************************************************
* @fn usbdev_get_string_OS
*
* @brief Get OS String Descriptor.
*********************************************************************/
void usbdev_get_string_OS(uint8_t *Descriptor)
{
DevDescriptors.stringOS = Descriptor;
}
/*********************************************************************
* @fn usbdev_get_device_status
*
* @brief Get device_status. bit0 : self-powered
* bit1 : device remove wakeup
*********************************************************************/
uint16_t usbdev_get_device_status(void)
{
return USB_Device_Status;
}
/*********************************************************************
* @fn usbdev_get_in_endpoints_status
*
* @brief Get in endpoints status. bit0 : 0 normal
* bit0 : 1 endpoint_halt
* @param index: In endpoints index.
*********************************************************************/
uint16_t usbdev_get_in_endpoints_status(uint32_t index)
{
return USB_IN_Endpoint_Status[index];
}
/*********************************************************************
* @fn usbdev_get_out_endpoints_status
*
* @brief Get out endpoints status.
*
* @param index: Out endpoints index.
*********************************************************************/
uint16_t usbdev_get_out_endpoints_status(uint32_t index)
{
return USB_OUT_Endpoint_Status[index];
}
/*********************************************************************
* @fn usbdev_get_device_configuration_num
*
* @brief Get device configuration num
*********************************************************************/
uint8_t usbdev_get_device_configuration_num(void)
{
return USB_Configuration;
}
/*********************************************************************
* @fn usbdev_get_interface_alternate_num
*
* @brief Get device interface alternate num
*
* @param index: interface index.
*********************************************************************/
uint8_t usbdev_get_interface_alternate_num(uint32_t index)
{
return USB_InterfaceAlternateSet[index];
}
/*********************************************************************
* @fn Endpoint_0_IRQHandler
*
* @brief USB endpoint0 Interrupt Request handler
*
* @param None.
* @return None.
*/
static void Endpoint_0_IRQHandler(void)
{
uint8_t lu8_RxCount;
static bool lb_WaitSetAddress = false;
static bool lb_PktMAX = false;
usb_selecet_endpoint(ENDPOINT_0);
/* Clear SetupEnd status */
if (USB_POINT0->CSR01 & USB_CSR01_SETUPEND)
{
USB_POINT0->CSR01 |= USB_CSR01_SVCSETUPEND;
}
/* endpoint 0 receive a packet */
if (usb_Endpoint0_GET_RxPktRdy())
{
/* Data Out packet */
if (Endpoint_0_DataOut_Handler != NULL)
{
Endpoint_0_DataOut_Handler();
}
/* Standard Request packet */
else
{
lu8_RxCount = usb_Endpoint0_get_RxCount();
usb_read_fifo(ENDPOINT_0, (uint8_t *)&StandardRequest, lu8_RxCount);
/* Standard Request */
if ((StandardRequest.bmRequestType & REQUEST_TYPE_MASK) == TYPE_STANDARD)
{
switch (StandardRequest.bRequest)
{
/* request descriptor */
case REQUEST_GET_DESCRIPTOR:
{
/* Build the returned data */
ReturnData.RequestLength = (uint16_t)StandardRequest.wLength[1] << 8;
ReturnData.RequestLength |= (uint16_t)StandardRequest.wLength[0];
switch (StandardRequest.wValue[1])
{
case DESCRIPTOR_DEVICE:
{
ReturnData.DataBuffer = DevDescriptors.DeviceDescriptor;
ReturnData.DataLength = ReturnData.DataBuffer[0];
}break;
case DESCRIPTOR_CONFIGURATION:
{
ReturnData.DataBuffer = DevDescriptors.ConfigurationDescriptor;
ReturnData.DataLength = (uint32_t)ReturnData.DataBuffer[3] << 8;
ReturnData.DataLength |= (uint32_t)ReturnData.DataBuffer[2];
}break;
case DESCRIPTOR_STRING:
{
switch (StandardRequest.wValue[0])
{
case STRING_MANUFACTURE:
{
ReturnData.DataBuffer = DevDescriptors.stringManufacture;
}break;
case STRING_PRODUCT:
{
ReturnData.DataBuffer = DevDescriptors.stringProduct;
}break;
case STRING_SERIAL_Number:
{
ReturnData.DataBuffer = DevDescriptors.stringSerialNumber;
}break;
case STRING_LANUAGE_ID:
{
ReturnData.DataBuffer = DevDescriptors.stringLanuageID;
}break;
case STRING_OS:
{
ReturnData.DataBuffer = DevDescriptors.stringOS;
}break;
default: break;
}
ReturnData.DataLength = ReturnData.DataBuffer[0];
}break;
case DESCRIPTOR_DEVICE_QUALIFIER:
{
/* USB2.0 full speed send stall */
usb_Endpoint0_SendStall();
}break;
case DESCRIPTOR_BOS:
{
/* USB2.0 does not support DESCRIPTOR_BOS */
usb_Endpoint0_SendStall();
}break;
case DESCRIPTOR_HID:
case DESCRIPTOR_HID_REPORT:
{
if (Endpoint_0_StandardClassRequest_Handler != NULL)
{
Endpoint_0_StandardClassRequest_Handler(&StandardRequest, &ReturnData);
}
}break;
default: break;
}
}break;
/* set device address */
case REQUEST_SET_ADDRESS:
{
/* wait an empty IN packet */
lb_WaitSetAddress = true;
}break;
/* set configuration */
case REQUEST_SET_CONFIGURATION:
{
USB_Configuration = StandardRequest.wValue[0];
}break;
/* get configuration */
case REQUEST_GET_CONFIGURATION:
{
ReturnData.RequestLength = 1;
ReturnData.DataBuffer = &USB_Configuration;
ReturnData.DataLength = 1;
}break;
/* set interface */
case REQUEST_SET_INTERFACE:
{
USB_InterfaceAlternateSet[StandardRequest.wIndex[0]] = StandardRequest.wValue[0];
if (USB_InterfaceAlternateSet_callback != NULL)
{
USB_InterfaceAlternateSet_callback(StandardRequest.wIndex[0]);
}
}break;
/* get interface */
case REQUEST_GET_INTERFACE:
{
ReturnData.RequestLength = (uint16_t)StandardRequest.wLength[1] << 8;
ReturnData.RequestLength |= (uint16_t)StandardRequest.wLength[0];
ReturnData.DataBuffer = &USB_InterfaceAlternateSet[StandardRequest.wIndex[0]];
ReturnData.DataLength = ReturnData.RequestLength;
}break;
/* get status */
case REQUEST_GET_STATUS:
{
/* Get Device status */
if ((StandardRequest.bmRequestType & REQUEST_RECIPIENT_MASK) == RECIPIENT_DEVICE)
{
ReturnData.DataBuffer = (uint8_t *)&USB_Device_Status;
}
/* Get Interface status */
else if ((StandardRequest.bmRequestType & REQUEST_RECIPIENT_MASK) == RECIPIENT_INTERFACE)
{
ReturnData.DataBuffer = (uint8_t *)&USB_Interface_Status;
}
/* Get Endpoints status */
else if((StandardRequest.bmRequestType & REQUEST_RECIPIENT_MASK) == RECIPIENT_ENDPOINT)
{
if (StandardRequest.wIndex[0] & DIRECTION_IN)
{
ReturnData.DataBuffer = (uint8_t *)&USB_IN_Endpoint_Status[StandardRequest.wIndex[0] & 0x0F];
}
else
{
ReturnData.DataBuffer = (uint8_t *)&USB_OUT_Endpoint_Status[StandardRequest.wIndex[0] & 0x0F];
}
}
/* Build the returned data */
ReturnData.RequestLength = 2;
ReturnData.DataLength = 2;
}break;
/* Set feature */
case REQUEST_SET_FEATURE:
{
/* clear device feature */
if ((StandardRequest.bmRequestType & REQUEST_RECIPIENT_MASK) == RECIPIENT_DEVICE)
{
if ((StandardRequest.wValue[0] == 1) && (StandardRequest.wValue[1] == 0))
{
USB_Device_Status |= 0x0002;
}
}
/* Set Endpoint feature */
else if ((StandardRequest.bmRequestType & REQUEST_RECIPIENT_MASK) == RECIPIENT_ENDPOINT)
{
if ((StandardRequest.wValue[0] == 0) && (StandardRequest.wValue[1] == 0))
{
if (StandardRequest.wIndex[0] & DIRECTION_IN)
{
USB_IN_Endpoint_Status[StandardRequest.wIndex[0] & 0x0F] = 0x0001;
}
else
{
USB_OUT_Endpoint_Status[StandardRequest.wIndex[0] & 0x0F] = 0x0001;
}
}
}
}break;
/* Clear feature */
case REQUEST_CLEAR_FEATURE:
{
/* clear device feature */
if ((StandardRequest.bmRequestType & REQUEST_RECIPIENT_MASK) == RECIPIENT_DEVICE)
{
if ((StandardRequest.wValue[0] == 1) && (StandardRequest.wValue[1] == 0))
{
USB_Device_Status &= ~0x0002;
}
}
/* clear Endpoint feature */
else if ((StandardRequest.bmRequestType & REQUEST_RECIPIENT_MASK) == RECIPIENT_ENDPOINT)
{
if ((StandardRequest.wValue[0] == 0) && (StandardRequest.wValue[1] == 0))
{
if (StandardRequest.wIndex[0] & DIRECTION_IN)
{
USB_IN_Endpoint_Status[StandardRequest.wIndex[0] & 0x0F] = 0x0000;
}
else
{
USB_OUT_Endpoint_Status[StandardRequest.wIndex[0] & 0x0F] = 0x0000;
}
}
}
}break;
default: break;
}
}
/* Class Request */
else if ((StandardRequest.bmRequestType & REQUEST_TYPE_MASK) == TYPE_CLASS)
{
if (Endpoint_0_ClassRequest_Handler != NULL)
{
Endpoint_0_ClassRequest_Handler(&StandardRequest, &ReturnData);
}
}
/* Vendor Request */
else if ((StandardRequest.bmRequestType & REQUEST_TYPE_MASK) == TYPE_VENDOR)
{
if (Endpoint_0_VendorRequest_Handler != NULL)
{
Endpoint_0_VendorRequest_Handler(&StandardRequest, &ReturnData);
}
}
/* clear TxPktRdy/RxPktRdy */
usb_Endpoint0_FlushFIFO();
}
}
/* endpoint 0 transmit a packet */
else
{
if (lb_WaitSetAddress == true)
{
lb_WaitSetAddress = false;
usb_set_address(StandardRequest.wValue[0]);
}
}
/* DataBuffer needs to be sent */
if (ReturnData.DataLength)
{
if (ReturnData.RequestLength < ReturnData.DataLength)
{
ReturnData.DataLength = ReturnData.RequestLength;
}
if (ReturnData.DataLength > ENDPOINT0_MAX)
{
usb_write_fifo(ENDPOINT_0, ReturnData.DataBuffer, ENDPOINT0_MAX);
ReturnData.DataLength -= ENDPOINT0_MAX;
ReturnData.DataBuffer += ENDPOINT0_MAX;
}
else
{
usb_write_fifo(ENDPOINT_0, ReturnData.DataBuffer, ReturnData.DataLength);
if (ReturnData.DataLength == ENDPOINT0_MAX)
{ /* Packet length is equal to 64 byte, without DataEnd */
lb_PktMAX = true;
}
else
{
usb_Endpoint0_DataEnd();
}
ReturnData.DataLength = 0;
}
usb_Endpoint0_SET_TxPktRdy();
}
else
{
/* The packet length of 64 bytes was sent */
if (lb_PktMAX)
{
/* The next packet is empty */
usb_Endpoint0_DataEnd();
usb_Endpoint0_SET_TxPktRdy();
lb_PktMAX = false;
}
}
}
/*********************************************************************
* @fn Endpoints_IRQHandler
*
* @brief ALL Endpoint Interrupt Request handler
*
* @param None.
* @return None.
*/
static void Endpoints_IRQHandler(void)
{
volatile uint8_t lu8_RxStatus;
volatile uint8_t lu8_TxStatus;
volatile uint8_t lu8_EndpointBackup;
lu8_EndpointBackup = usb_get_endpoint();
lu8_TxStatus = usb_get_TxStatus();
lu8_RxStatus = usb_get_RxStatus();
/* endpoint 0 Interrupt handler */
if (lu8_TxStatus & ENDPOINT_0_MASK)
{
lu8_TxStatus &= ~ENDPOINT_0_MASK;
Endpoint_0_IRQHandler();
}
/* other endpoints Rx/Tx Interrupt handler */
if (lu8_RxStatus | lu8_TxStatus)
{
if (Endpoints_Handler != NULL)
{
Endpoints_Handler(lu8_RxStatus, lu8_TxStatus);
}
}
usb_selecet_endpoint((enum_Endpoint_t)lu8_EndpointBackup);
}
static void USB_Status_IRQHandler(void)
{
volatile uint8_t lu8_EndpointBackup;
volatile uint8_t lu8_USBStatus;
lu8_EndpointBackup = usb_get_endpoint();
lu8_USBStatus = usb_get_USBStatus();
/* USB Bus SOF packet */
if (lu8_USBStatus & USB_INT_STATUS_SOF)
{
if (USB_SOF_Handler != NULL)
{
USB_SOF_Handler();
}
}
/* USB Bus reset signal, Will be clear USB register */
/* need configure USB register again */
if (lu8_USBStatus & USB_INT_STATUS_RESET)
{
USB->IntrUSBE = 0x04; /* Enable Bus reset INT */
USB->IntrTx1E = 0x01; /* Enable Endpoint0 INT */
USB->IntrTx2E = 0x00;
USB->IntrRx1E = 0x00;
USB->IntrRx2E = 0x00;
if (USB_Reset_Handler != NULL)
{
USB_Reset_Handler();
}
}
/* USB Bus Resume signal */
if (lu8_USBStatus & USB_INT_STATUS_RESUME)
{
if (USB_Resume_Handler != NULL)
{
USB_Resume_Handler();
}
}
/* USB Bus Suspend signal */
if (lu8_USBStatus & USB_INT_STATUS_SUSPEND)
{
if (USB_Suspend_Handler != NULL)
{
USB_Suspend_Handler();
}
}
/* USB Bus connect signal */
if (lu8_USBStatus & USB_INT_STATUS_CONN)
{
if (USB_Connect_Handler != NULL)
{
USB_Connect_Handler();
}
}
usb_selecet_endpoint((enum_Endpoint_t)lu8_EndpointBackup);
}
#define USB_IRQHandler usbotg_irq
/*********************************************************************
* @fn USB_IRQHandler
*
* @brief USB interrupt Request handler
*
* @param None.
* @return None.
*/
void USB_IRQHandler(void)
{
Endpoints_IRQHandler();
USB_Status_IRQHandler();
}

View File

@ -0,0 +1,612 @@
/*
******************************************************************************
* @file usb_hid.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief This file provides the high layer firmware functions to manage the
* USB HID Device.(Human Interface Device)
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
*
******************************************************************************
* How to use, for example:
*
* int main(void)
* {
* NVIC_ClearPendingIRQ(USBMCU_IRQn);
* NVIC_SetPriority(USBMCU_IRQn, 0);
* NVIC_EnableIRQ(USBMCU_IRQn);
*
* usb_device_init();
* usb_hid_init();
*
* // Wait for other initialization of the MCU
*
* while(1)
* {
* usb_hid_send_mouse_report();
* usb_hid_send_keyboard_report();
* }
* }
******************************************************************************
*/
#include "usb_hid.h"
#define REPORT0_LENGTH (4)
#define REPORT1_LENGTH (8)
uint8_t HID_Mouse_Report[REPORT0_LENGTH];
uint8_t HID_Keyboard_Report[REPORT1_LENGTH];
/* USB Standard Device Descriptor */
const uint8_t USB_HID_DeviceDesc[] =
{
0x12, /* bLength */
0x01, /* bDescriptorType */
0x00, /* bcdUSB */
0x02,
0x00, /* bDeviceClass */
0x00, /* bDeviceSubClass */
0x00, /* bDeviceProtocol */
0x40, /* bMaxPacketSize */
0xA4, /* idVendor */
0xA8, /* idVendor */
0x55, /* idProduct */
0x22, /* idProduct */
0x00, /* bcdDevice rel. 2.00 */
0x20,
0x01, /* Index of manufacturer string */
0x02, /* Index of product string */
0x03, /* Index of serial number string */
0x01, /* bNumConfigurations */
};
/* HID Descriptor */
#define HID_DESCRIPTOR_0 0x09, /* bLength */ \
0x21, /* bDescriptorType: HID */ \
0x10, /* bcdHID: 1.10 */ \
0x01, \
0x21, /* bCountryCode */ \
0x01, /* bNumDescriptors */ \
0x22, /* bDescriptorType: Report */ \
0x2E, /* wDescriptorLength */ \
0x00
/* HID Descriptor */
#define HID_DESCRIPTOR_1 0x09, /* bLength */ \
0x21, /* bDescriptorType: HID */ \
0x10, /* bcdHID: 1.10 */ \
0x01, \
0x21, /* bCountryCode */ \
0x01, /* bNumDescriptors */ \
0x22, /* bDescriptorType: Report */ \
0x41, /* wDescriptorLength */ \
0x00
const uint8_t USB_HID_Desc_0[] =
{
HID_DESCRIPTOR_0,
};
const uint8_t USB_HID_Desc_1[] =
{
HID_DESCRIPTOR_1,
};
/* USB Standard Configuration Descriptor */
const uint8_t USB_HID_ConfigurationDesc[] =
{
/* Configuration Descriptor */
0x09, /* bLength */
0x02, /* bDescriptorType */
0x42, /* wTotalLength */
0x00,
0x02, /* bNumInterfaces */
0x01, /* bConfigurationValue */
0x00, /* iConfiguration */
0xA0, /* bmAttributes */
0x32, /* bMaxPower */
/* HID Interface_0 Descriptor */
0x09, /* bLength */
0x04, /* bDescriptorType */
0x00, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x01, /* bNumEndpoints */
0x03, /* bInterfaceClass: HID */
0x01, /* bInterfaceSubClass: Boot interface */
0x02, /* bInterfaceProtocol: Mouse */
0x00, /* iConfiguration */
/* HID Descriptor */
HID_DESCRIPTOR_0,
/* Endpoint 1 Descriptor */
0x07, /* bLength */
0x05, /* bDescriptorType */
0x81, /* bEndpointAddress */
0x03, /* bmAttributes: Interrupt */
0x40, /* wMaxPacketSize: 64byte */
0x00,
0x08, /* bInterval */
/* HID Interface_1 Descriptor */
0x09, /* bLength */
0x04, /* bDescriptorType */
0x01, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x02, /* bNumEndpoints */
0x03, /* bInterfaceClass: HID */
0x01, /* bInterfaceSubClass: Boot interface */
0x01, /* bInterfaceProtocol: Keyboard */
0x00, /* iConfiguration */
/* HID Descriptor */
HID_DESCRIPTOR_1,
/* Endpoint 2 IN Descriptor */
0x07, /* bLength */
0x05, /* bDescriptorType */
0x82, /* bEndpointAddress */
0x03, /* bmAttributes: Interrupt */
0x40, /* wMaxPacketSize: 64byte */
0x00,
0x0A, /* bInterval */
/* Endpoint 2 OUT Descriptor */
0x07, /* bLength */
0x05, /* bDescriptorType */
0x02, /* bEndpointAddress */
0x03, /* bmAttributes: Interrupt */
0x40, /* wMaxPacketSize: 64byte */
0x00,
0x0A, /* bInterval */
};
/* USB Standard Manufacture Descriptor */
const uint8_t USB_HID_ManufactureDesc[] =
{
0x12, /* bLength */
0x03, /* bDescriptorType */
'F', 0x00, /* BString */
'R', 0x00,
'E', 0x00,
'Q', 0x00,
'C', 0x00,
'H', 0x00,
'I', 0x00,
'P', 0x00,
};
/* USB Standard Configuration Descriptor */
const uint8_t USB_HID_ProductDesc[] =
{
0x1A, /* bLength */
0x03, /* bDescriptorType */
'F', 0x00, /* BString */
'R', 0x00,
'E', 0x00,
'Q', 0x00,
'C', 0x00,
'H', 0x00,
'I', 0x00,
'P', 0x00,
'-', 0x00,
'H', 0x00,
'I', 0x00,
'D', 0x00,
};
/* USB Standard Configuration Descriptor */
const uint8_t USB_HID_SerialNumberDesc[] =
{
0x1E, /* bLength */
0x03, /* bDescriptorType */
'2', 0x00, /* BString */
'0', 0x00,
'2', 0x00,
'1', 0x00,
'-', 0x00,
'1', 0x00,
'0', 0x00,
'0', 0x00,
'1', 0x00,
'-', 0x00,
'B', 0x00,
'1', 0x00,
'3', 0x00,
'5', 0x00,
};
/* USB Standard Configuration Descriptor */
const uint8_t USB_HID_LanuageIDDesc[] =
{
0x04, /* bLength */
0x03, /* bDescriptorType */
0x09, /* BString */
0x04,
};
/* HID device report Descriptor */
uint8_t USB_HID_Mouse_ReportDesc[] =
{
0x2E, /* Length */
0x05, 0x01,
0x09, 0x02,
0xA1, 0x01,
0x09, 0x01,
0xA1, 0x00,
0x05, 0x09,
0x19, 0x01,
0x29, 0x03,
0x15, 0x00,
0x25, 0x01,
0x95, 0x08,
0x75, 0x01,
0x81, 0x02,
0x05, 0x01,
0x09, 0x30,
0x09, 0x31,
0x09, 0x38,
0x15, 0x81,
0x25, 0x7F,
0x75, 0x08,
0x95, 0x03,
0x81, 0x06,
0xC0,
0xC0,
};
/* HID device report Descriptor */
uint8_t USB_HID_Keyboard_ReportDesc[] =
{
0x41, /* Length */
0x05, 0x01,
0x09, 0x06,
0xA1, 0x01,
0x05, 0x07,
0x19, 0xE0,
0x29, 0xE7,
0x15, 0x00,
0x25, 0x01,
0x75, 0x01,
0x95, 0x08,
0x81, 0x02,
0x95, 0x01,
0x75, 0x08,
0x81, 0x01,
0x95, 0x03,
0x75, 0x01,
0x05, 0x08,
0x19, 0x01,
0x29, 0x03,
0x91, 0x02,
0x95, 0x05,
0x75, 0x01,
0x91, 0x01,
0x95, 0x06,
0x75, 0x08,
0x15, 0x00,
0x26, 0xFF, 0x00,
0x05, 0x07,
0x19, 0x00,
0x2A, 0xFF, 0x00,
0x81, 0x00,
0xC0,
0xC0,
};
/*********************************************************************
* @fn usb_hid_set_mouse_report
*
* @brief set report
*
* @param None.
* @return None.
*/
void usb_hid_set_mouse_report(uint8_t fu8_Index, uint8_t fu8_Value)
{
HID_Mouse_Report[fu8_Index] = fu8_Value;
/*
HID_Report[0]: 0000 0001 left button
0000 0010 right button
0000 0100 middle button
HID_Report[1]: X (-127 ~ +127)
HID_Report[2]: Y (-127 ~ +127)
HID_Report[3]: wheel (-127 ~ +127)
*/
}
/*********************************************************************
* @fn usb_hid_set_keyboard_report
*
* @brief set report
*
* @param None.
* @return None.
*/
void usb_hid_set_keyboard_report(uint16_t fu16_Key)
{
uint32_t i;
switch (fu16_Key)
{
case KEY_LEFT_CONTROL: HID_Keyboard_Report[0] |= 0x01; break;
case KEY_LEFT_SHIFT: HID_Keyboard_Report[0] |= 0x02; break;
case KEY_LEFT_ALT: HID_Keyboard_Report[0] |= 0x04; break;
case KEY_LEFT_GUI: HID_Keyboard_Report[0] |= 0x08; break;
case KEY_RIGHT_CONTROL: HID_Keyboard_Report[0] |= 0x10; break;
case KEY_RIGHT_SHIFT: HID_Keyboard_Report[0] |= 0x20; break;
case KEY_RIGHT_ALT: HID_Keyboard_Report[0] |= 0x40; break;
case KEY_RIGHT_GUI: HID_Keyboard_Report[0] |= 0x80; break;
default:
{
for (i = 2; i < 8; i++)
{
if (HID_Keyboard_Report[i] == fu16_Key)
{
break;
}
if (HID_Keyboard_Report[i] == 0x00)
{
HID_Keyboard_Report[i] = fu16_Key;
break;
}
}
}break;
}
}
/*********************************************************************
* @fn usb_hid_clear_keyboard_report
*
* @brief set report
*
* @param None.
* @return None.
*/
void usb_hid_clear_keyboard_report(uint16_t fu16_Key)
{
uint32_t i, k;
switch (fu16_Key)
{
case KEY_LEFT_CONTROL: HID_Keyboard_Report[0] &= ~0x01; break;
case KEY_LEFT_SHIFT: HID_Keyboard_Report[0] &= ~0x02; break;
case KEY_LEFT_ALT: HID_Keyboard_Report[0] &= ~0x04; break;
case KEY_LEFT_GUI: HID_Keyboard_Report[0] &= ~0x08; break;
case KEY_RIGHT_CONTROL: HID_Keyboard_Report[0] &= ~0x10; break;
case KEY_RIGHT_SHIFT: HID_Keyboard_Report[0] &= ~0x20; break;
case KEY_RIGHT_ALT: HID_Keyboard_Report[0] &= ~0x40; break;
case KEY_RIGHT_GUI: HID_Keyboard_Report[0] &= ~0x80; break;
default:
{
for (i = 2; i < 8; i++)
{
if (HID_Keyboard_Report[i] == fu16_Key)
{
HID_Keyboard_Report[i] = 0x00;
for (k = i; k < 7; k++)
{
if (HID_Keyboard_Report[k + 1] != 0x00)
{
HID_Keyboard_Report[k] = HID_Keyboard_Report[k + 1];
HID_Keyboard_Report[k + 1] = 0x00;
}
else
{
break;
}
}
break;
}
}
}break;
}
}
/*********************************************************************
* @fn usb_hid_send_mouse_report
*
* @brief send report to host
*
* @param None.
* @return None.
*/
void usb_hid_send_mouse_report(void)
{
usb_selecet_endpoint(ENDPOINT_1);
/* FIFO empty */
if (usb_Endpoints_GET_TxPktRdy() == false)
{
usb_write_fifo(ENDPOINT_1, HID_Mouse_Report, REPORT0_LENGTH);
usb_Endpoints_SET_TxPktRdy();
}
}
/*********************************************************************
* @fn usb_hid_send_keyboard_report
*
* @brief send report to host
*
* @param None.
* @return None.
*/
void usb_hid_send_keyboard_report(void)
{
usb_selecet_endpoint(ENDPOINT_2);
/* FIFO empty */
if (usb_Endpoints_GET_TxPktRdy() == false)
{
usb_write_fifo(ENDPOINT_2, HID_Keyboard_Report, REPORT1_LENGTH);
usb_Endpoints_SET_TxPktRdy();
}
}
/*********************************************************************
* @fn usb_hid_ClassRequest_Handler
*
* @brief HID Class Request Handler
*
* @param None.
* @return None.
*/
static void usb_hid_ClassRequest_Handler(usb_StandardRequest_t* pStandardRequest, usb_ReturnData_t* pReturnData)
{
static uint8_t HID_Protocol = 1; // 0: Boot Protocol
// 1: Report Protocol
switch (pStandardRequest->bRequest)
{
case HID_GET_PROTOCOL:
{
pReturnData->DataBuffer = &HID_Protocol;
pReturnData->DataLength = 1;
}break;
case HID_SET_PROTOCOL:
{
HID_Protocol = pStandardRequest->wValue[0];
}break;
case HID_GET_IDLE:
{
/* Device does not support Getidle command */
usb_Endpoint0_SendStall();
}break;
case HID_SET_IDLE:
{
/* Device does not support Setidle command */
usb_Endpoint0_SendStall();
}break;
default: break;
}
}
/*********************************************************************
* @fn usb_hid_StandardClassRequest_Handler
*
* @brief HID Standard Class Request Handler
*
* @param None.
* @return None.
*/
static void usb_hid_StandardClassRequest_Handler(usb_StandardRequest_t* pStandardRequest, usb_ReturnData_t* pReturnData)
{
switch (pStandardRequest->wValue[1])
{
case DESCRIPTOR_HID_REPORT:
{
if (pStandardRequest->wIndex[0] == 0){
pReturnData->DataLength = USB_HID_Mouse_ReportDesc[0];
pReturnData->DataBuffer = &USB_HID_Mouse_ReportDesc[1];
}
else if (pStandardRequest->wIndex[0] == 1){
pReturnData->DataLength = USB_HID_Keyboard_ReportDesc[0];
pReturnData->DataBuffer = &USB_HID_Keyboard_ReportDesc[1];
}
}break;
case DESCRIPTOR_HID:
{
if (pStandardRequest->wIndex[0] == 0){
pReturnData->DataLength = 9;
pReturnData->DataBuffer = (uint8_t *)USB_HID_Desc_0;
}
else if (pStandardRequest->wIndex[0] == 1){
pReturnData->DataLength = 9;
pReturnData->DataBuffer = (uint8_t *)USB_HID_Desc_1;
}
}break;
default: break;
}
}
/*********************************************************************
* @fn usb_hid_Endpoints_Handler
*
* @brief hid Endpoints Handler
*
* @param None.
* @return None.
*/
void usb_hid_Endpoints_Handler(uint8_t RxStatus, uint8_t TxStatus)
{
uint8_t lu8_RxCount;
uint8_t lu8_Buffer[4] = {0,0,0,0};
if (RxStatus & 1 << ENDPOINT_2)
{
usb_selecet_endpoint(ENDPOINT_2);
lu8_RxCount = usb_Endpoints_get_RxCount();
usb_read_fifo(ENDPOINT_2, lu8_Buffer, lu8_RxCount);
usb_Endpoints_FlushRxFIFO();
}
}
/*********************************************************************
* @fn usb_hid_init
*
* @brief hid device parameter initialization
*
* @param None.
* @return None.
*/
void usb_hid_init(void)
{
/* Initialize the relevant pointer */
usbdev_get_dev_desc((uint8_t *)USB_HID_DeviceDesc);
usbdev_get_config_desc((uint8_t *)USB_HID_ConfigurationDesc);
usbdev_get_string_Manufacture((uint8_t *)USB_HID_ManufactureDesc);
usbdev_get_string_Product((uint8_t *)USB_HID_ProductDesc);
usbdev_get_string_SerialNumber((uint8_t *)USB_HID_SerialNumberDesc);
usbdev_get_string_LanuageID((uint8_t *)USB_HID_LanuageIDDesc);
Endpoint_0_StandardClassRequest_Handler = usb_hid_StandardClassRequest_Handler;
Endpoint_0_ClassRequest_Handler = usb_hid_ClassRequest_Handler;
Endpoints_Handler = usb_hid_Endpoints_Handler;
USB_Reset_Handler = usb_hid_init;
/* config data endpoint fifo */
usb_selecet_endpoint(ENDPOINT_1);
usb_endpoint_Txfifo_config(0x08, 3);
usb_TxMaxP_set(8);
usb_RxMaxP_set(8);
usb_selecet_endpoint(ENDPOINT_2);
usb_endpoint_Txfifo_config(0x18, 3);
usb_endpoint_Rxfifo_config(0x20, 3);
usb_TxMaxP_set(8);
usb_RxMaxP_set(8);
usb_RxInt_Enable(ENDPOINT_2);
usb_SuspendDetectEn();
usb_SingleInt_Enable(USB_INT_STATUS_SUSPEND);
usb_SingleInt_Enable(USB_INT_STATUS_RESUME);
}

View File

@ -0,0 +1,526 @@
/*
******************************************************************************
* @file usb_mass_storage.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2023
* @brief This file provides the high layer firmware functions to manage the
* Mass Storage Device.
******************************************************************************
* @attention
*
* Copyright (c) 2023 FreqChip.
* All rights reserved.
*
******************************************************************************
* How to use, for example:
*
* int main(void)
* {
* NVIC_ClearPendingIRQ(USBMCU_IRQn);
* NVIC_SetPriority(USBMCU_IRQn, 0);
* NVIC_EnableIRQ(USBMCU_IRQn);
*
* usb_device_init();
* usb_mass_storage_init();
*
* // Wait for other initialization of the MCU
*
* while(1)
* {
* }
* }
******************************************************************************
*/
#include "fr30xx.h"
#define DISK_BLOCKS (100)
#define DISK_PAGE_SIZE (512) /* one page 512 byte fixed */
#define RAM_SIMULATE_DISK_CAPACITY (DISK_PAGE_SIZE * DISK_BLOCKS)
uint8_t Disk[RAM_SIMULATE_DISK_CAPACITY];
/* USB Standard Device Descriptor */
const uint8_t USB_MassStorage_DeviceDesc[] =
{
0x12, /* bLength */
0x01, /* bDescriptorType */
0x00, /* bcdUSB */
0x02,
0x00, /* bDeviceClass: Class info in ifc Descriptors */
0x00, /* bDeviceSubClass */
0x00, /* bDeviceProtocol */
0x40, /* bMaxPacketSize */
0xA9, /* idVendor */
0x13, /* idVendor */
0xCC, /* idProduct */
0x10, /* idProduct */
0x00, /* bcdDevice rel. 2.00 */
0x20,
0x01, /* Index of manufacturer string */
0x02, /* Index of product string */
0x03, /* Index of serial number string */
0x01, /* bNumConfigurations */
};
/* USB Standard Configuration Descriptor */
const uint8_t USB_MassStorage_ConfigurationDesc[] =
{
/* Configuration Descriptor */
0x09, /* bLength */
0x02, /* bDescriptorType */
0x20, /* wTotalLength */
0x00,
0x01, /* bNumInterfaces */
0x01, /* bConfigurationValue */
0x00, /* iConfiguration */
0x80, /* bmAttributes */
0x96, /* bMaxPower */
/* Interface Descriptor */
0x09, /* bLength */
0x04, /* bDescriptorType */
0x00, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x02, /* bNumEndpoints */
0x08, /* bInterfaceClass: Mass Storage */
0x06, /* bInterfaceSubClass SCSI Transparent Conmmand Set */
0x50, /* bInterfaceProtocol Bulk-Only Transport */
0x00, /* iConfiguration */
/* Endpoint 1 IN Descriptor */
0x07, /* bLength */
0X05, /* bDescriptorType */
0x81, /* bEndpointAddress */
0x02, /* bmAttributes: bulk */
0x40, /* wMaxPacketSize: 64byte */
0x00,
0x00, /* bInterval */
/* Endpoint 1 OUT Descriptor */
0x07, /* bLength */
0X05, /* bDescriptorType */
0x01, /* bEndpointAddress */
0x02, /* bmAttributes: bulk */
0x40, /* wMaxPacketSize: 64byte */
0x00,
0x00, /* bInterval */
};
/* USB Standard Manufacture Descriptor */
const uint8_t USB_MassStorage_ManufactureDesc[] =
{
0x12, /* bLength */
0x03, /* bDescriptorType */
'F', 0x00, /* BString */
'R', 0x00,
'E', 0x00,
'Q', 0x00,
'C', 0x00,
'H', 0x00,
'I', 0x00,
'P', 0x00,
};
/* USB Standard Configuration Descriptor */
const uint8_t USB_MassStorage_ProductDesc[] =
{
0x2C, /* bLength */
0x03, /* bDescriptorType */
'F', 0x00, /* BString */
'R', 0x00,
'E', 0x00,
'Q', 0x00,
'C', 0x00,
'H', 0x00,
'I', 0x00,
'P', 0x00,
'-', 0x00,
'D', 0x00,
'a', 0x00,
't', 0x00,
'a', 0x00,
'T', 0x00,
'r', 0x00,
'a', 0x00,
'v', 0x00,
'e', 0x00,
'l', 0x00,
'e', 0x00,
'r', 0x00,
};
/* USB Standard Configuration Descriptor */
const uint8_t USB_MassStorage_SerialNumberDesc[] =
{
0x1E, /* bLength */
0x03, /* bDescriptorType */
'2', 0x00, /* BString */
'0', 0x00,
'2', 0x00,
'3', 0x00,
'-', 0x00,
'2', 0x00,
'0', 0x00,
'0', 0x00,
'2', 0x00,
'-', 0x00,
'C', 0x00,
'1', 0x00,
'3', 0x00,
'5', 0x00,
};
/* USB Standard Configuration Descriptor */
const uint8_t USB_MassStorage_LanuageIDDesc[] =
{
0x04, /* bLength */
0x03, /* bDescriptorType */
0x09, /* BString */
0x04,
};
const uint8_t SCSI_Inquiry_Response[] =
{
0x00, /* Device Type */
0x80, /* Removable */
0x00, /* Version */
0x01, /* Response Data Format */
0x1F, /* Additional Length */
0x00,0x00,0x00,
'F','r','e','q','c','h','i','p',
'2','0','1','3','-','4','5','3','2','-','A','D','E','F','G','H',
'1','.','0','0',
};
uint8_t SCSI_ReadForamtCapacity_Response[] =
{
0x00,0x00,0x00,
0x08, /* list length */
0x00,0x00,0x01,0x90, /* Blocks */
0x02,
0x00,0x02,0x00, /* Page size */
};
uint8_t SCSI_ReadCapacity_Response[] =
{
0x00,0x00,0x01,0x8F, /* Blocks */
0x00,0x00,0x02,0x00, /* Page size */
};
const uint8_t SCSI_SENSE6_Response[] =
{
0x03,0x00,0x00,0x00,
};
static uint8_t USB_MessageBuffer[10];
/*********************************************************************
* @fn usb_MassStorage_ClassRequest_Handler
*
* @brief Mass Storage Class Request Handler
*/
static void usb_MassStorage_ClassRequest_Handler(usb_StandardRequest_t* pStandardRequest, usb_ReturnData_t* pReturnData)
{
switch (pStandardRequest->bRequest)
{
case BULK_ONLY_MASS_STORAGE_RESET:
{
usb_Endpoint0_DataEnd();
usb_Endpoint0_SET_TxPktRdy();
}break;
case GET_MAX_LUN:
{
USB_MessageBuffer[0] = FREQCHIP_MASS_STORAGE_MAX_LUN - 1;
pReturnData->DataBuffer = USB_MessageBuffer;
pReturnData->DataLength = 1;
}break;
default: break;
}
}
/*********************************************************************
* @fn usb_MassStorage_SendCSW
*
* @brief SCSI Send CSW
*/
static void usb_MassStorage_SendCSW(uint32_t fu32_CBWTag)
{
#define CBW_LEN (13)
uint8_t USB_CSWBuffer[CBW_LEN];
usb_CSW_t *CSW;
CSW = (usb_CSW_t *)USB_CSWBuffer;
CSW->dCSWSignature = CSW_SIGNATURE;
CSW->dCSWTag = fu32_CBWTag;
CSW->dCSWDataResidue = 0;
CSW->bmCSWStatus = 0x00;
if (usb_Endpoints_GET_TxPktRdy() == false)
{
usb_write_fifo(ENDPOINT_1, (uint8_t *)USB_CSWBuffer, CBW_LEN);
usb_Endpoints_SET_TxPktRdy();
}
}
/*********************************************************************
* @fn Endpoint1_Handler
*
* @brief endpoint1 RX TX Handler
*/
static void Endpoint1_Handler(uint8_t RxStatus, uint8_t TxStatus)
{
static uint8_t USB_CBWBuffer[64];
static uint32_t lu32_WriteStatus = 0;
static uint8_t *lu32_WriteDiskPoint;
static uint32_t lu32_WriteCnt;
static uint32_t lu32_ReadStatus = 0;
static uint8_t *lu32_ReadDiskPoint;
static uint32_t lu32_ReadCnt;
static usb_CBW_t *CBW;
uint32_t lu32_BlockAddr;
uint16_t lu16_BlockCnt;
uint8_t lu8_RxCount;
if (RxStatus & ENDPOINT_1_MASK)
{
usb_selecet_endpoint(ENDPOINT_1);
if (lu32_WriteStatus)
{
usb_read_fifo(ENDPOINT_1, lu32_WriteDiskPoint, 64);
usb_Endpoints_FlushRxFIFO();
lu32_WriteDiskPoint += 64;
lu32_WriteCnt -= 1;
if (lu32_WriteCnt == 0)
{
usb_MassStorage_SendCSW(CBW->dCBWTag);
lu32_WriteStatus = false;
}
}
else
{
lu8_RxCount = usb_Endpoints_get_RxCount();
if (lu8_RxCount == 0)
return;
usb_read_fifo(ENDPOINT_1, USB_CBWBuffer, lu8_RxCount);
usb_Endpoints_FlushRxFIFO();
CBW = (usb_CBW_t *)USB_CBWBuffer;
if (CBW->dCBWSignature == CBW_SIGNATURE)
{
switch (CBW->CBWCB[0])
{
case SCSI_CMD_Inquiry:
{
if (usb_Endpoints_GET_TxPktRdy() == false)
{
usb_write_fifo(ENDPOINT_1, (uint8_t *)SCSI_Inquiry_Response, sizeof(SCSI_Inquiry_Response));
usb_Endpoints_SET_TxPktRdy();
}
while(usb_Endpoints_GET_TxPktRdy());
usb_MassStorage_SendCSW(CBW->dCBWTag);
}break;
case SCSI_CMD_ReadForamtCapacity:
{
SCSI_ReadForamtCapacity_Response[4] = (DISK_BLOCKS >> 24) & 0xFF;
SCSI_ReadForamtCapacity_Response[5] = (DISK_BLOCKS >> 16) & 0xFF;
SCSI_ReadForamtCapacity_Response[6] = (DISK_BLOCKS >> 8) & 0xFF;
SCSI_ReadForamtCapacity_Response[7] = DISK_BLOCKS & 0xFF;
if (usb_Endpoints_GET_TxPktRdy() == false)
{
usb_write_fifo(ENDPOINT_1, (uint8_t *)SCSI_ReadForamtCapacity_Response, 12);
usb_Endpoints_SET_TxPktRdy();
}
while(usb_Endpoints_GET_TxPktRdy());
usb_MassStorage_SendCSW(CBW->dCBWTag);
}break;
case SCSI_CMD_ReadCapacity:
{
uint32_t lu32_Blocks = DISK_BLOCKS - 1;
SCSI_ReadCapacity_Response[0] = (lu32_Blocks >> 24) & 0xFF;
SCSI_ReadCapacity_Response[1] = (lu32_Blocks >> 16) & 0xFF;
SCSI_ReadCapacity_Response[2] = (lu32_Blocks >> 8) & 0xFF;
SCSI_ReadCapacity_Response[3] = lu32_Blocks & 0xFF;
if (usb_Endpoints_GET_TxPktRdy() == false)
{
usb_write_fifo(ENDPOINT_1, (uint8_t *)SCSI_ReadCapacity_Response, 8);
usb_Endpoints_SET_TxPktRdy();
}
while(usb_Endpoints_GET_TxPktRdy());
usb_MassStorage_SendCSW(CBW->dCBWTag);
}break;
case SCSI_CMD_ModeSENSE6:
{
if (usb_Endpoints_GET_TxPktRdy() == false)
{
usb_write_fifo(ENDPOINT_1, (uint8_t *)SCSI_SENSE6_Response, sizeof(SCSI_SENSE6_Response));
usb_Endpoints_SET_TxPktRdy();
}
while(usb_Endpoints_GET_TxPktRdy());
usb_MassStorage_SendCSW(CBW->dCBWTag);
}break;
case SCSI_CMD_Read10:
{
lu32_ReadDiskPoint = Disk;
lu32_BlockAddr = CBW->CBWCB[2] << 24;
lu32_BlockAddr |= CBW->CBWCB[3] << 16;
lu32_BlockAddr |= CBW->CBWCB[4] << 8;
lu32_BlockAddr |= CBW->CBWCB[5];
lu16_BlockCnt = CBW->CBWCB[7] << 8;
lu16_BlockCnt |= CBW->CBWCB[8];
lu32_ReadDiskPoint += DISK_PAGE_SIZE * lu32_BlockAddr;
lu32_ReadCnt += (lu16_BlockCnt * DISK_PAGE_SIZE)/64;
lu32_ReadStatus = true;
while(usb_Endpoints_GET_TxPktRdy());
usb_write_fifo(ENDPOINT_1, lu32_ReadDiskPoint, 64);
usb_Endpoints_SET_TxPktRdy();
lu32_ReadDiskPoint += 64;
lu32_ReadCnt -= 1;
usb_TxInt_Enable(ENDPOINT_1);
}break;
case SCSI_CMD_Write10:
{
lu32_WriteDiskPoint = Disk;
lu32_BlockAddr = CBW->CBWCB[2] << 24;
lu32_BlockAddr |= CBW->CBWCB[3] << 16;
lu32_BlockAddr |= CBW->CBWCB[4] << 8;
lu32_BlockAddr |= CBW->CBWCB[5];
lu16_BlockCnt = CBW->CBWCB[7] << 8;
lu16_BlockCnt |= CBW->CBWCB[8];
lu32_WriteDiskPoint += DISK_PAGE_SIZE * lu32_BlockAddr;
lu32_WriteCnt = (lu16_BlockCnt*DISK_PAGE_SIZE)/64;
lu32_WriteStatus = true;
}break;
case SCSI_CMD_TestUnitReady:
case SCSI_CMD_Prevent:
{
usb_MassStorage_SendCSW(CBW->dCBWTag);
}break;
default:
{
usb_MassStorage_SendCSW(CBW->dCBWTag);
}break;
}
}
}
}
if (TxStatus & ENDPOINT_1_MASK)
{
usb_selecet_endpoint(ENDPOINT_1);
if (lu32_ReadStatus)
{
if (usb_Endpoints_GET_TxPktRdy() == false)
{
if (lu32_ReadCnt > 0)
{
usb_write_fifo(ENDPOINT_1, (uint8_t *)lu32_ReadDiskPoint, 64);
usb_Endpoints_SET_TxPktRdy();
lu32_ReadDiskPoint += 64;
lu32_ReadCnt -= 1;
}
else if (lu32_ReadCnt == 0)
{
while(usb_Endpoints_GET_TxPktRdy());
usb_MassStorage_SendCSW(CBW->dCBWTag);
lu32_ReadStatus = false;
usb_TxInt_Disable(ENDPOINT_1);
}
}
}
}
}
/*********************************************************************
* @fn usb_mass_storage_init
*
* @brief mass storage parameter initialization
*
* @param None.
* @return None.
*/
void usb_mass_storage_init(void)
{
/* Initialize the relevant pointer */
usbdev_get_dev_desc((uint8_t *)USB_MassStorage_DeviceDesc);
usbdev_get_config_desc((uint8_t *)USB_MassStorage_ConfigurationDesc);
usbdev_get_string_Manufacture((uint8_t *)USB_MassStorage_ManufactureDesc);
usbdev_get_string_Product((uint8_t *)USB_MassStorage_ProductDesc);
usbdev_get_string_SerialNumber((uint8_t *)USB_MassStorage_SerialNumberDesc);
usbdev_get_string_LanuageID((uint8_t *)USB_MassStorage_LanuageIDDesc);
Endpoint_0_ClassRequest_Handler = usb_MassStorage_ClassRequest_Handler;
Endpoints_Handler = Endpoint1_Handler;
USB_Reset_Handler = usb_mass_storage_init;
/* config data endpoint fifo */
usb_selecet_endpoint(ENDPOINT_1);
usb_endpoint_Txfifo_config(0x08, 3);
usb_TxMaxP_set(8);
usb_RxMaxP_set(8);
usb_selecet_endpoint(ENDPOINT_1);
usb_endpoint_Rxfifo_config(0x10, 3);
usb_TxMaxP_set(8);
usb_RxMaxP_set(8);
usb_RxInt_Enable(ENDPOINT_1);
}

View File

@ -0,0 +1,364 @@
/*
******************************************************************************
* @file usb_winusb.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief This file provides the high layer firmware functions to manage the
* WinUSB Device.
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
*
******************************************************************************
* How to use, for example:
*
* int main(void)
* {
* NVIC_ClearPendingIRQ(USBMCU_IRQn);
* NVIC_SetPriority(USBMCU_IRQn, 0);
* NVIC_EnableIRQ(USBMCU_IRQn);
*
* usb_device_init();
* usb_winusb_init();
*
* // Wait for other initialization of the MCU
*
* usb_DP_Pullup_Enable();
*
* while(1)
* {
* }
* }
******************************************************************************
*/
#include "usb_winusb.h"
uint8_t WinUSB_Buffer[512];
/* USB Standard Device Descriptor */
const uint8_t USB_WinUSB_DeviceDesc[] =
{
0x12, /* bLength */
0x01, /* bDescriptorType */
0x00, /* bcdUSB */
0x02,
0xFF, /* bDeviceClass: Vendor customization */
0x00, /* bDeviceSubClass */
0x00, /* bDeviceProtocol */
0x40, /* bMaxPacketSize */
0xAA, /* idVendor */
0xBB, /* idVendor */
0xCC, /* idProduct */
0x11, /* idProduct */
0x00, /* bcdDevice rel. 2.00 */
0x20,
0x01, /* Index of manufacturer string */
0x02, /* Index of product string */
0x03, /* Index of serial number string */
0x01, /* bNumConfigurations */
};
/* USB Standard Configuration Descriptor */
const uint8_t USB_WinUSB_ConfigurationDesc[] =
{
/* Configuration Descriptor */
0x09, /* bLength */
0x02, /* bDescriptorType */
0x20, /* wTotalLength */
0x00,
0x01, /* bNumInterfaces */
0x01, /* bConfigurationValue */
0x00, /* iConfiguration */
0x80, /* bmAttributes */
0xFA, /* bMaxPower */
/* Interface Descriptor */
0x09, /* bLength */
0x04, /* bDescriptorType */
0x00, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x02, /* bNumEndpoints */
0x00, /* bInterfaceClass */
0x00, /* bInterfaceSubClass */
0x00, /* bInterfaceProtocol */
0x00, /* iConfiguration */
/* Endpoint 1 IN Descriptor */
0x07, /* bLength */
0X05, /* bDescriptorType */
0x81, /* bEndpointAddress */
0x02, /* bmAttributes: bulk */
0x40, /* wMaxPacketSize: 64byte */
0x00,
0x00, /* bInterval */
/* Endpoint 1 OUT Descriptor */
0x07, /* bLength */
0X05, /* bDescriptorType */
0x01, /* bEndpointAddress */
0x02, /* bmAttributes: bulk */
0x40, /* wMaxPacketSize: 64byte */
0x00,
0x00, /* bInterval */
};
/* USB Standard Manufacture Descriptor */
const uint8_t USB_WinUSB_ManufactureDesc[] =
{
0x12, /* bLength */
0x03, /* bDescriptorType */
'F', 0x00, /* BString */
'R', 0x00,
'E', 0x00,
'Q', 0x00,
'C', 0x00,
'H', 0x00,
'I', 0x00,
'P', 0x00,
};
/* USB Standard Configuration Descriptor */
const uint8_t USB_WinUSB_ProductDesc[] =
{
0x20, /* bLength */
0x03, /* bDescriptorType */
'F', 0x00, /* BString */
'R', 0x00,
'E', 0x00,
'Q', 0x00,
'C', 0x00,
'H', 0x00,
'I', 0x00,
'P', 0x00,
'-', 0x00,
'W', 0x00,
'i', 0x00,
'n', 0x00,
'U', 0x00,
'S', 0x00,
'B', 0x00,
};
/* USB Standard Configuration Descriptor */
const uint8_t USB_WinUSB_SerialNumberDesc[] =
{
0x1E, /* bLength */
0x03, /* bDescriptorType */
'2', 0x00, /* BString */
'0', 0x00,
'2', 0x00,
'1', 0x00,
'-', 0x00,
'1', 0x00,
'0', 0x00,
'0', 0x00,
'1', 0x00,
'-', 0x00,
'C', 0x00,
'1', 0x00,
'3', 0x00,
'5', 0x00,
};
/* USB Standard Configuration Descriptor */
const uint8_t USB_WinUSB_LanuageIDDesc[] =
{
0x04, /* bLength */
0x03, /* bDescriptorType */
0x09, /* BString */
0x04,
};
/* Compat ID OS Descriptor */
const uint8_t USB_WinUSB_OSDesc[] =
{
0x12, /* bLength */
0x03, /* bDescriptorType */
'M', 0x00, /* BString */
'S', 0x00,
'F', 0x00,
'T', 0x00,
'1', 0x00,
'0', 0x00,
'0', 0x00,
0x01,
0x00,
};
/* Compat ID OS Descriptor */
const uint8_t WINUSB_Extended_Compat_ID_OS_Feature_Descriptor[] =
{
0x28, 0x00, 0x00, 0x00, // dwLength
0x00, 0x01, // bcdVersion
0x04, 0x00, // wIndex
0x01, // bCount
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Reserved[7]
0x00, // bFirstInterfaceNumber
0x01, // RESERVED ( 0x01 )
'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, // compactiableID[8]
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // subCompactiableID[8]
0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Reserved[6]
};
/* L"DeviceInterfaceGUID" : wIndex = 0x0005 */
/* L"{12345678-1234-1234-1234-123456789ABC}" */
const uint8_t WINUSB_Extended_Property_OS_Feature_Descriptor[142] =
{
0x8E, 0x00, 0x00, 0x00, // dwTotalSize = Header + All sections
0x00, 0x01, // bcdVersion
0x05, 0x00, // wIndex
0x01, 0x00, // wCount
0x84, 0x00, 0x00, 0x00, // dwSize -- this section
0x01, 0x00, 0x00, 0x00, // dwPropertyDataType
0x28, 0x00, // wPropertyNameLength
'D', 0x00, 'e', 0x00, // bProperytName : WCHAR : L"DeviceInterfaceGUID"
'v', 0x00, 'i', 0x00, // bProperytName : WCHAR
'c', 0x00, 'e', 0x00, // bProperytName : WCHAR
'I', 0x00, 'n', 0x00, // bProperytName : WCHAR
't', 0x00, 'e', 0x00, // bProperytName : WCHAR
'r', 0x00, 'f', 0x00, // bProperytName : WCHAR
'a', 0x00, 'c', 0x00, // bProperytName : WCHAR
'e', 0x00, 'G', 0x00, // bProperytName : WCHAR
'U', 0x00, 'I', 0x00, // bProperytName : WCHAR
'D', 0x00, 0x00, 0x00, // bProperytName : WCHAR
0x4E, 0x00, 0x00, 0x00, // dwPropertyDataLength : 78 Bytes = 0x0000004E
'{', 0x00, '1', 0x00, // bPropertyData : WCHAR : L"{12345678-1234-1234-1234-123456789ABC}"
'2', 0x00, '3', 0x00, // bPropertyData
'4', 0x00, '5', 0x00, // bPropertyData
'6', 0x00, '7', 0x00, // bPropertyData
'8', 0x00, '-', 0x00, // bPropertyData
'1', 0x00, '2', 0x00, // bPropertyData
'3', 0x00, '4', 0x00, // bPropertyData
'-', 0x00, '1', 0x00, // bPropertyData
'2', 0x00, '3', 0x00, // bPropertyData
'4', 0x00, '-', 0x00, // bPropertyData
'1', 0x00, '2', 0x00, // bPropertyData
'3', 0x00, '4', 0x00, // bPropertyData
'-', 0x00, '1', 0x00, // bPropertyData
'2', 0x00, '3', 0x00, // bPropertyData
'4', 0x00, '5', 0x00, // bPropertyData
'6', 0x00, '7', 0x00, // bPropertyData
'8', 0x00, '9', 0x00, // bPropertyData
'A', 0x00, 'B', 0x00, // bPropertyData
'C', 0x00, '}', 0x00, // bPropertyData
0x00, 0x00 // bPropertyData
};
/*********************************************************************
* @fn usb_winusb_VendorRequest_Handler
*
* @brief winusb Vendor Request Handler
*
* @param None.
* @return None.
*/
static void usb_winusb_VendorRequest_Handler(usb_StandardRequest_t* pStandardRequest, usb_ReturnData_t* pReturnData)
{
pReturnData->RequestLength = (uint16_t)pStandardRequest->wLength[1] << 8;
pReturnData->RequestLength |= (uint16_t)pStandardRequest->wLength[0];
switch (pStandardRequest->bRequest)
{
case GET_MS_DESCRIPTOR:
{
switch (pStandardRequest->wIndex[0])
{
case EXTENDED_COMPAT_ID:
{
pReturnData->DataBuffer = (uint8_t *)WINUSB_Extended_Compat_ID_OS_Feature_Descriptor;
pReturnData->DataLength = sizeof(WINUSB_Extended_Compat_ID_OS_Feature_Descriptor);
}break;
case EXTENDED_PROPERTIES:
{
pReturnData->DataBuffer = (uint8_t *)WINUSB_Extended_Property_OS_Feature_Descriptor;
pReturnData->DataLength = sizeof(WINUSB_Extended_Property_OS_Feature_Descriptor);
}break;
default: break;
}
}break;
default: break;
}
}
/*********************************************************************
* @fn Endpoint1_Handler
*
* @brief endpoint1 RX TX Handler
*
* @param None.
* @return None.
*/
static void Endpoint1_Handler(uint8_t RxStatus, uint8_t TxStatus)
{
uint8_t lu8_RxCount;
if (RxStatus & ENDPOINT_1_MASK)
{
usb_selecet_endpoint(ENDPOINT_1);
lu8_RxCount = usb_Endpoints_get_RxCount();
usb_read_fifo(ENDPOINT_1, WinUSB_Buffer, lu8_RxCount);
usb_Endpoints_FlushRxFIFO();
if (usb_Endpoints_GET_TxPktRdy() == false)
{
usb_write_fifo(ENDPOINT_1, WinUSB_Buffer, lu8_RxCount);
usb_Endpoints_SET_TxPktRdy();
}
}
}
/*********************************************************************
* @fn usb_winusb_init
*
* @brief winusb device parameter initialization
*
* @param None.
* @return None.
*/
void usb_winusb_init(void)
{
/* Initialize the relevant pointer */
usbdev_get_dev_desc((uint8_t *)USB_WinUSB_DeviceDesc);
usbdev_get_config_desc((uint8_t *)USB_WinUSB_ConfigurationDesc);
usbdev_get_string_Manufacture((uint8_t *)USB_WinUSB_ManufactureDesc);
usbdev_get_string_Product((uint8_t *)USB_WinUSB_ProductDesc);
usbdev_get_string_SerialNumber((uint8_t *)USB_WinUSB_SerialNumberDesc);
usbdev_get_string_LanuageID((uint8_t *)USB_WinUSB_LanuageIDDesc);
usbdev_get_string_OS((uint8_t *)USB_WinUSB_OSDesc);
Endpoint_0_VendorRequest_Handler = usb_winusb_VendorRequest_Handler;
Endpoints_Handler = Endpoint1_Handler;
USB_Reset_Handler = usb_winusb_init;
/* config data endpoint fifo */
usb_selecet_endpoint(ENDPOINT_1);
usb_endpoint_Txfifo_config(0x08, 3);
usb_TxMaxP_set(8);
usb_RxMaxP_set(8);
usb_selecet_endpoint(ENDPOINT_1);
usb_endpoint_Rxfifo_config(0x10, 3);
usb_TxMaxP_set(8);
usb_RxMaxP_set(8);
usb_RxInt_Enable(ENDPOINT_1);
}