First commit. Temp from Mo10
This commit is contained in:
842
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_adc.c
Normal file
842
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_adc.c
Normal file
@@ -0,0 +1,842 @@
|
||||
/*!
|
||||
\file gd32e23x_adc.c
|
||||
\brief ADC driver
|
||||
|
||||
\version 2024-02-22, V2.1.0, firmware for GD32E23x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2024, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "gd32e23x_adc.h"
|
||||
|
||||
/*!
|
||||
\brief reset ADC
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_deinit(void)
|
||||
{
|
||||
rcu_periph_reset_enable(RCU_ADCRST);
|
||||
rcu_periph_reset_disable(RCU_ADCRST);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable ADC interface
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_enable(void)
|
||||
{
|
||||
if(RESET == (ADC_CTL1 & ADC_CTL1_ADCON)){
|
||||
ADC_CTL1 |= (uint32_t)ADC_CTL1_ADCON;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable ADC interface
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_disable(void)
|
||||
{
|
||||
ADC_CTL1 &= ~((uint32_t)ADC_CTL1_ADCON);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief ADC calibration and reset calibration
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_calibration_enable(void)
|
||||
{
|
||||
/* reset the selected ADC calibration register */
|
||||
ADC_CTL1 |= (uint32_t) ADC_CTL1_RSTCLB;
|
||||
/* check the RSTCLB bit state */
|
||||
while((ADC_CTL1 & ADC_CTL1_RSTCLB)){
|
||||
}
|
||||
|
||||
/* enable ADC calibration process */
|
||||
ADC_CTL1 |= ADC_CTL1_CLB;
|
||||
/* check the CLB bit state */
|
||||
while((ADC_CTL1 & ADC_CTL1_CLB)){
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable DMA request
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_dma_mode_enable(void)
|
||||
{
|
||||
ADC_CTL1 |= (uint32_t)(ADC_CTL1_DMA);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable DMA request
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_dma_mode_disable(void)
|
||||
{
|
||||
ADC_CTL1 &= ~((uint32_t)ADC_CTL1_DMA);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable the temperature sensor and Vrefint channel
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_tempsensor_vrefint_enable(void)
|
||||
{
|
||||
/* enable the temperature sensor and Vrefint channel */
|
||||
ADC_CTL1 |= ADC_CTL1_TSVREN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable the temperature sensor and Vrefint channel
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_tempsensor_vrefint_disable(void)
|
||||
{
|
||||
/* disable the temperature sensor and Vrefint channel */
|
||||
ADC_CTL1 &= ~ADC_CTL1_TSVREN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure ADC discontinuous mode
|
||||
\param[in] channel_group: select the channel group
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg ADC_REGULAR_CHANNEL: regular channel group
|
||||
\arg ADC_INSERTED_CHANNEL: inserted channel group
|
||||
\arg ADC_CHANNEL_DISCON_DISABLE: disable discontinuous mode of regular and inserted channel
|
||||
\param[in] length: number of conversions in discontinuous mode, the number can be 1..8
|
||||
for regular channel, the number has no effect for inserted channel
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_discontinuous_mode_config(uint8_t channel_group, uint8_t length)
|
||||
{
|
||||
ADC_CTL0 &= ~((uint32_t)(ADC_CTL0_DISRC | ADC_CTL0_DISIC));
|
||||
|
||||
switch(channel_group){
|
||||
case ADC_REGULAR_CHANNEL:
|
||||
/* configure the number of conversions in discontinuous mode */
|
||||
ADC_CTL0 &= ~((uint32_t)ADC_CTL0_DISNUM);
|
||||
ADC_CTL0 |= CTL0_DISNUM(((uint32_t)length - 1U));
|
||||
ADC_CTL0 |= (uint32_t)ADC_CTL0_DISRC;
|
||||
break;
|
||||
case ADC_INSERTED_CHANNEL:
|
||||
ADC_CTL0 |= (uint32_t)ADC_CTL0_DISIC;
|
||||
break;
|
||||
case ADC_CHANNEL_DISCON_DISABLE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure ADC special function
|
||||
\param[in] function: the function to configure
|
||||
one or more parameters can be selected which is shown as below:
|
||||
\arg ADC_SCAN_MODE: scan mode select
|
||||
\arg ADC_INSERTED_CHANNEL_AUTO: inserted channel group convert automatically
|
||||
\arg ADC_CONTINUOUS_MODE: continuous mode select
|
||||
\param[in] newvalue: ENABLE or DISABLE
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_special_function_config(uint32_t function, ControlStatus newvalue)
|
||||
{
|
||||
if(newvalue){
|
||||
/* enable ADC scan mode */
|
||||
if(RESET != (function & ADC_SCAN_MODE)){
|
||||
ADC_CTL0 |= ADC_SCAN_MODE;
|
||||
}
|
||||
/* enable ADC inserted channel group convert automatically */
|
||||
if(RESET != (function & ADC_INSERTED_CHANNEL_AUTO)){
|
||||
ADC_CTL0 |= ADC_INSERTED_CHANNEL_AUTO;
|
||||
}
|
||||
/* enable ADC continuous mode */
|
||||
if(RESET != (function & ADC_CONTINUOUS_MODE)){
|
||||
ADC_CTL1 |= ADC_CONTINUOUS_MODE;
|
||||
}
|
||||
}else{
|
||||
/* disable ADC scan mode */
|
||||
if(RESET != (function & ADC_SCAN_MODE)){
|
||||
ADC_CTL0 &= ~ADC_SCAN_MODE;
|
||||
}
|
||||
/* disable ADC inserted channel group convert automatically */
|
||||
if(RESET != (function & ADC_INSERTED_CHANNEL_AUTO)){
|
||||
ADC_CTL0 &= ~ADC_INSERTED_CHANNEL_AUTO;
|
||||
}
|
||||
/* disable ADC continuous mode */
|
||||
if(RESET != (function & ADC_CONTINUOUS_MODE)){
|
||||
ADC_CTL1 &= ~ADC_CONTINUOUS_MODE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure ADC data alignment
|
||||
\param[in] data_alignment: data alignment select
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg ADC_DATAALIGN_RIGHT: right alignment
|
||||
\arg ADC_DATAALIGN_LEFT: left alignment
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_data_alignment_config(uint32_t data_alignment)
|
||||
{
|
||||
if(ADC_DATAALIGN_RIGHT != data_alignment){
|
||||
ADC_CTL1 |= ADC_CTL1_DAL;
|
||||
}else{
|
||||
ADC_CTL1 &= ~((uint32_t)ADC_CTL1_DAL);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure the length of regular channel group or inserted channel group
|
||||
\param[in] channel_group: select the channel group
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg ADC_REGULAR_CHANNEL: regular channel group
|
||||
\arg ADC_INSERTED_CHANNEL: inserted channel group
|
||||
\param[in] length: the length of the channel
|
||||
regular channel 1-16
|
||||
inserted channel 1-4
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_channel_length_config(uint8_t channel_group, uint32_t length)
|
||||
{
|
||||
switch(channel_group){
|
||||
case ADC_REGULAR_CHANNEL:
|
||||
/* configure the length of regular channel group */
|
||||
ADC_RSQ0 &= ~((uint32_t)ADC_RSQ0_RL);
|
||||
ADC_RSQ0 |= RSQ0_RL((uint32_t)(length-1U));
|
||||
break;
|
||||
case ADC_INSERTED_CHANNEL:
|
||||
/* configure the length of inserted channel group */
|
||||
ADC_ISQ &= ~((uint32_t)ADC_ISQ_IL);
|
||||
ADC_ISQ |= ISQ_IL((uint32_t)(length-1U));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure ADC regular channel
|
||||
\param[in] rank: the regular group sequence rank, this parameter must be between 0 to 15
|
||||
\param[in] channel: the selected ADC channel
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg ADC_CHANNEL_x(x=0..9,16,17): ADC Channelx
|
||||
\param[in] sample_time: the sample time value
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg ADC_SAMPLETIME_1POINT5: 1.5 cycles
|
||||
\arg ADC_SAMPLETIME_7POINT5: 7.5 cycles
|
||||
\arg ADC_SAMPLETIME_13POINT5: 13.5 cycles
|
||||
\arg ADC_SAMPLETIME_28POINT5: 28.5 cycles
|
||||
\arg ADC_SAMPLETIME_41POINT5: 41.5 cycles
|
||||
\arg ADC_SAMPLETIME_55POINT5: 55.5 cycles
|
||||
\arg ADC_SAMPLETIME_71POINT5: 71.5 cycles
|
||||
\arg ADC_SAMPLETIME_239POINT5: 239.5 cycles
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_regular_channel_config(uint8_t rank, uint8_t channel, uint32_t sample_time)
|
||||
{
|
||||
uint32_t rsq,sampt;
|
||||
|
||||
/* configure ADC regular sequence */
|
||||
if(rank < 6U){
|
||||
rsq = ADC_RSQ2;
|
||||
rsq &= ~((uint32_t)(ADC_RSQX_RSQN << (5U*rank)));
|
||||
rsq |= ((uint32_t)channel << (5U*rank));
|
||||
ADC_RSQ2 = rsq;
|
||||
}else if(rank < 12U){
|
||||
rsq = ADC_RSQ1;
|
||||
rsq &= ~((uint32_t)(ADC_RSQX_RSQN << (5U*(rank-6U))));
|
||||
rsq |= ((uint32_t)channel << (5U*(rank-6U)));
|
||||
ADC_RSQ1 = rsq;
|
||||
}else if(rank < 16U){
|
||||
rsq = ADC_RSQ0;
|
||||
rsq &= ~((uint32_t)(ADC_RSQX_RSQN << (5U*(rank-12U))));
|
||||
rsq |= ((uint32_t)channel << (5U*(rank-12U)));
|
||||
ADC_RSQ0 = rsq;
|
||||
}else{
|
||||
}
|
||||
|
||||
/* configure ADC sampling time */
|
||||
if(channel < 10U){
|
||||
sampt = ADC_SAMPT1;
|
||||
sampt &= ~((uint32_t)(ADC_SAMPTX_SPTN << (3U*channel)));
|
||||
sampt |= (uint32_t)(sample_time << (3U*channel));
|
||||
ADC_SAMPT1 = sampt;
|
||||
}else if(channel < 19U){
|
||||
sampt = ADC_SAMPT0;
|
||||
sampt &= ~((uint32_t)(ADC_SAMPTX_SPTN << (3U*(channel-10U))));
|
||||
sampt |= (uint32_t)(sample_time << (3U*(channel-10U)));
|
||||
ADC_SAMPT0 = sampt;
|
||||
}else{
|
||||
/* illegal parameters */
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure ADC inserted channel
|
||||
\param[in] rank: the inserted group sequencer rank,this parameter must be between 0 to 3
|
||||
\param[in] channel: the selected ADC channel
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg ADC_CHANNEL_x(x=0..9,16,17): ADC Channelx
|
||||
\param[in] sample_time: The sample time value
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg ADC_SAMPLETIME_1POINT5: 1.5 cycles
|
||||
\arg ADC_SAMPLETIME_7POINT5: 7.5 cycles
|
||||
\arg ADC_SAMPLETIME_13POINT5: 13.5 cycles
|
||||
\arg ADC_SAMPLETIME_28POINT5: 28.5 cycles
|
||||
\arg ADC_SAMPLETIME_41POINT5: 41.5 cycles
|
||||
\arg ADC_SAMPLETIME_55POINT5: 55.5 cycles
|
||||
\arg ADC_SAMPLETIME_71POINT5: 71.5 cycles
|
||||
\arg ADC_SAMPLETIME_239POINT5: 239.5 cycles
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_inserted_channel_config(uint8_t rank, uint8_t channel, uint32_t sample_time)
|
||||
{
|
||||
uint8_t inserted_length;
|
||||
uint32_t isq,sampt;
|
||||
|
||||
inserted_length = (uint8_t)GET_BITS(ADC_ISQ , 20U , 21U);
|
||||
|
||||
isq = ADC_ISQ;
|
||||
isq &= ~((uint32_t)(ADC_ISQ_ISQN << (15U - (inserted_length - rank)*5U)));
|
||||
isq |= ((uint32_t)channel << (15U - (inserted_length - rank)*5U));
|
||||
ADC_ISQ = isq;
|
||||
|
||||
/* configure ADC sampling time */
|
||||
if(channel < 10U){
|
||||
sampt = ADC_SAMPT1;
|
||||
sampt &= ~((uint32_t)(ADC_SAMPTX_SPTN << (3U*channel)));
|
||||
sampt |= (uint32_t) sample_time << (3U*channel);
|
||||
ADC_SAMPT1 = sampt;
|
||||
}else if(channel < 19U){
|
||||
sampt = ADC_SAMPT0;
|
||||
sampt &= ~((uint32_t)(ADC_SAMPTX_SPTN << (3U*(channel - 10U))));
|
||||
sampt |= ((uint32_t)sample_time << (3U*(channel - 10U)));
|
||||
ADC_SAMPT0 = sampt;
|
||||
}else{
|
||||
/* illegal parameters */
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure ADC inserted channel offset
|
||||
\param[in] inserted_channel: insert channel select
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg ADC_INSERTED_CHANNEL_0: ADC inserted channel 0
|
||||
\arg ADC_INSERTED_CHANNEL_1: ADC inserted channel 1
|
||||
\arg ADC_INSERTED_CHANNEL_2: ADC inserted channel 2
|
||||
\arg ADC_INSERTED_CHANNEL_3: ADC inserted channel 3
|
||||
\param[in] offset: the offset data
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_inserted_channel_offset_config(uint8_t inserted_channel, uint16_t offset)
|
||||
{
|
||||
uint8_t inserted_length;
|
||||
uint32_t num = 0U;
|
||||
|
||||
inserted_length = (uint8_t)GET_BITS(ADC_ISQ, 20U, 21U);
|
||||
num = 3U - (inserted_length - inserted_channel);
|
||||
|
||||
if(num <= 3U){
|
||||
/* calculate the offset of the register */
|
||||
num = num * 4U;
|
||||
/* configure the offset of the selected channels */
|
||||
REG32((ADC) + 0x14U + num) = IOFFX_IOFF((uint32_t)offset);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable or disable ADC external trigger
|
||||
\param[in] channel_group: select the channel group
|
||||
one or more parameters can be selected which is shown as below:
|
||||
\arg ADC_REGULAR_CHANNEL: regular channel group
|
||||
\arg ADC_INSERTED_CHANNEL: inserted channel group
|
||||
\param[in] newvalue: ENABLE or DISABLE
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_external_trigger_config(uint8_t channel_group, ControlStatus newvalue)
|
||||
{
|
||||
if(newvalue){
|
||||
/* external trigger enable for regular channel */
|
||||
if(RESET != (channel_group & ADC_REGULAR_CHANNEL)){
|
||||
ADC_CTL1 |= ADC_CTL1_ETERC;
|
||||
}
|
||||
/* external trigger enable for inserted channel */
|
||||
if(RESET != (channel_group & ADC_INSERTED_CHANNEL)){
|
||||
ADC_CTL1 |= ADC_CTL1_ETEIC;
|
||||
}
|
||||
}else{
|
||||
/* external trigger disable for regular channel */
|
||||
if(RESET != (channel_group & ADC_REGULAR_CHANNEL)){
|
||||
ADC_CTL1 &= ~ADC_CTL1_ETERC;
|
||||
}
|
||||
/* external trigger disable for inserted channel */
|
||||
if(RESET != (channel_group & ADC_INSERTED_CHANNEL)){
|
||||
ADC_CTL1 &= ~ADC_CTL1_ETEIC;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure ADC external trigger source
|
||||
\param[in] channel_group: select the channel group
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg ADC_REGULAR_CHANNEL: regular channel group
|
||||
\arg ADC_INSERTED_CHANNEL: inserted channel group
|
||||
\param[in] external_trigger_source: regular or inserted group trigger source
|
||||
only one parameter can be selected which is shown as below:
|
||||
for regular channel:
|
||||
\arg ADC_EXTTRIG_REGULAR_T0_CH0: TIMER0 CH0 event select
|
||||
\arg ADC_EXTTRIG_REGULAR_T0_CH1: TIMER0 CH1 event select
|
||||
\arg ADC_EXTTRIG_REGULAR_T0_CH2: TIMER0 CH2 event select
|
||||
\arg ADC_EXTTRIG_REGULAR_T2_TRGO: TIMER2 TRGO event select
|
||||
\arg ADC_EXTTRIG_REGULAR_T14_CH0: TIMER14 CH0 event select
|
||||
\arg ADC_EXTTRIG_REGULAR_EXTI_11: external interrupt line 11
|
||||
\arg ADC_EXTTRIG_REGULAR_NONE: software trigger
|
||||
for inserted channel:
|
||||
\arg ADC_EXTTRIG_INSERTED_T0_TRGO: TIMER0 TRGO event select
|
||||
\arg ADC_EXTTRIG_INSERTED_T0_CH3: TIMER0 CH3 event select
|
||||
\arg ADC_EXTTRIG_INSERTED_T2_CH3: TIMER2 CH3 event select
|
||||
\arg ADC_EXTTRIG_INSERTED_T14_TRGO: TIMER14 TRGO event select
|
||||
\arg ADC_EXTTRIG_INSERTED_EXTI_15: external interrupt line 15
|
||||
\arg ADC_EXTTRIG_INSERTED_NONE: software trigger
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_external_trigger_source_config(uint8_t channel_group, uint32_t external_trigger_source)
|
||||
{
|
||||
switch(channel_group){
|
||||
case ADC_REGULAR_CHANNEL:
|
||||
/* external trigger select for regular channel */
|
||||
ADC_CTL1 &= ~((uint32_t)ADC_CTL1_ETSRC);
|
||||
ADC_CTL1 |= (uint32_t)external_trigger_source;
|
||||
break;
|
||||
case ADC_INSERTED_CHANNEL:
|
||||
/* external trigger select for inserted channel */
|
||||
ADC_CTL1 &= ~((uint32_t)ADC_CTL1_ETSIC);
|
||||
ADC_CTL1 |= (uint32_t)external_trigger_source;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable ADC software trigger
|
||||
\param[in] channel_group: select the channel group
|
||||
one or more parameters can be selected which is shown as below:
|
||||
\arg ADC_REGULAR_CHANNEL: regular channel group
|
||||
\arg ADC_INSERTED_CHANNEL: inserted channel group
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_software_trigger_enable(uint8_t channel_group)
|
||||
{
|
||||
/* enable regular group channel software trigger */
|
||||
if(RESET != (channel_group & ADC_REGULAR_CHANNEL)){
|
||||
ADC_CTL1 |= ADC_CTL1_SWRCST;
|
||||
}
|
||||
/* enable inserted channel group software trigger */
|
||||
if(RESET != (channel_group & ADC_INSERTED_CHANNEL)){
|
||||
ADC_CTL1 |= ADC_CTL1_SWICST;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief read ADC regular group data register
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval the conversion value
|
||||
*/
|
||||
uint16_t adc_regular_data_read(void)
|
||||
{
|
||||
return ((uint16_t)ADC_RDATA);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief read ADC inserted group data register
|
||||
\param[in] inserted_channel: inserted channel select
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg ADC_INSERTED_CHANNEL_0: ADC inserted channel 0
|
||||
\arg ADC_INSERTED_CHANNEL_1: ADC inserted channel 1
|
||||
\arg ADC_INSERTED_CHANNEL_2: ADC inserted channel 2
|
||||
\arg ADC_INSERTED_CHANNEL_3: ADC inserted channel 3
|
||||
\param[out] none
|
||||
\retval the conversion value
|
||||
*/
|
||||
uint16_t adc_inserted_data_read(uint8_t inserted_channel)
|
||||
{
|
||||
uint32_t idata;
|
||||
/* read the data of the selected channel */
|
||||
switch(inserted_channel){
|
||||
case ADC_INSERTED_CHANNEL_0:
|
||||
idata = ADC_IDATA0;
|
||||
break;
|
||||
case ADC_INSERTED_CHANNEL_1:
|
||||
idata = ADC_IDATA1;
|
||||
break;
|
||||
case ADC_INSERTED_CHANNEL_2:
|
||||
idata = ADC_IDATA2;
|
||||
break;
|
||||
case ADC_INSERTED_CHANNEL_3:
|
||||
idata = ADC_IDATA3;
|
||||
break;
|
||||
default:
|
||||
idata = 0U;
|
||||
break;
|
||||
}
|
||||
return (uint16_t)idata;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get the ADC flag bits
|
||||
\param[in] flag: the adc flag bits
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg ADC_FLAG_WDE: analog watchdog event flag
|
||||
\arg ADC_FLAG_EOC: end of group conversion flag
|
||||
\arg ADC_FLAG_EOIC: end of inserted group conversion flag
|
||||
\arg ADC_FLAG_STIC: start flag of inserted channel group
|
||||
\arg ADC_FLAG_STRC: start flag of regular channel group
|
||||
\param[out] none
|
||||
\retval FlagStatus: SET or RESET
|
||||
*/
|
||||
FlagStatus adc_flag_get(uint32_t flag)
|
||||
{
|
||||
FlagStatus reval = RESET;
|
||||
|
||||
if(ADC_STAT & flag){
|
||||
reval = SET;
|
||||
}
|
||||
return reval;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief clear the ADC flag
|
||||
\param[in] flag: the adc flag
|
||||
one or more parameters can be selected which is shown as below:
|
||||
\arg ADC_FLAG_WDE: analog watchdog event flag
|
||||
\arg ADC_FLAG_EOC: end of group conversion flag
|
||||
\arg ADC_FLAG_EOIC: end of inserted group conversion flag
|
||||
\arg ADC_FLAG_STIC: start flag of inserted channel group
|
||||
\arg ADC_FLAG_STRC: start flag of regular channel group
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_flag_clear(uint32_t flag)
|
||||
{
|
||||
ADC_STAT &= ~((uint32_t)flag);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get the ADC interrupt flag
|
||||
\param[in] flag: the adc interrupt flag
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg ADC_INT_FLAG_WDE: analog watchdog interrupt flag
|
||||
\arg ADC_INT_FLAG_EOC: end of group conversion interrupt flag
|
||||
\arg ADC_INT_FLAG_EOIC: end of inserted group conversion interrupt flag
|
||||
\param[out] none
|
||||
\retval FlagStatus: SET or RESET
|
||||
*/
|
||||
FlagStatus adc_interrupt_flag_get(uint32_t flag)
|
||||
{
|
||||
FlagStatus interrupt_flag = RESET;
|
||||
uint32_t state;
|
||||
|
||||
/* check the interrupt bits */
|
||||
switch(flag){
|
||||
case ADC_INT_FLAG_WDE:
|
||||
state = ADC_STAT & ADC_STAT_WDE;
|
||||
if((ADC_CTL0 & ADC_CTL0_WDEIE) && state){
|
||||
interrupt_flag = SET;
|
||||
}
|
||||
break;
|
||||
case ADC_INT_FLAG_EOC:
|
||||
state = ADC_STAT & ADC_STAT_EOC;
|
||||
if((ADC_CTL0 & ADC_CTL0_EOCIE) && state){
|
||||
interrupt_flag = SET;
|
||||
}
|
||||
break;
|
||||
case ADC_INT_FLAG_EOIC:
|
||||
state = ADC_STAT & ADC_STAT_EOIC;
|
||||
if((ADC_CTL0 & ADC_CTL0_EOICIE) && state){
|
||||
interrupt_flag = SET;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return interrupt_flag;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief clear ADC interrupt flag
|
||||
\param[in] flag: the adc interrupt flag
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg ADC_INT_FLAG_WDE: analog watchdog interrupt flag
|
||||
\arg ADC_INT_FLAG_EOC: end of group conversion interrupt flag
|
||||
\arg ADC_INT_FLAG_EOIC: end of inserted group conversion interrupt flag
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_interrupt_flag_clear(uint32_t flag)
|
||||
{
|
||||
ADC_STAT &= ~((uint32_t)flag);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable ADC interrupt
|
||||
\param[in] interrupt: the adc interrupt
|
||||
one or more parameters can be selected which is shown as below:
|
||||
\arg ADC_INT_WDE: analog watchdog interrupt
|
||||
\arg ADC_INT_EOC: end of group conversion interrupt
|
||||
\arg ADC_INT_EOIC: end of inserted group conversion interrupt
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_interrupt_enable(uint32_t interrupt)
|
||||
{
|
||||
/* enable analog watchdog interrupt */
|
||||
if(RESET != (interrupt & ADC_INT_WDE)){
|
||||
ADC_CTL0 |= (uint32_t)ADC_CTL0_WDEIE;
|
||||
}
|
||||
|
||||
/* enable end of group conversion interrupt */
|
||||
if(RESET != (interrupt & ADC_INT_EOC)){
|
||||
ADC_CTL0 |= (uint32_t)ADC_CTL0_EOCIE;
|
||||
}
|
||||
|
||||
/* enable end of inserted group conversion interrupt */
|
||||
if(RESET != (interrupt & ADC_INT_EOIC)){
|
||||
ADC_CTL0 |= (uint32_t)ADC_CTL0_EOICIE;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable ADC interrupt
|
||||
\param[in] interrupt: the adc interrupt flag
|
||||
one or more parameters can be selected which is shown as below:
|
||||
\arg ADC_INT_WDE: analog watchdog interrupt
|
||||
\arg ADC_INT_EOC: end of group conversion interrupt
|
||||
\arg ADC_INT_EOIC: end of inserted group conversion interrupt
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_interrupt_disable(uint32_t interrupt)
|
||||
{
|
||||
/* disable analog watchdog interrupt */
|
||||
if(RESET != (interrupt & ADC_INT_WDE)){
|
||||
ADC_CTL0 &= ~(uint32_t)ADC_CTL0_WDEIE;
|
||||
}
|
||||
|
||||
/* disable end of group conversion interrupt */
|
||||
if(RESET != (interrupt & ADC_INT_EOC)){
|
||||
ADC_CTL0 &= ~(uint32_t)ADC_CTL0_EOCIE;
|
||||
}
|
||||
|
||||
/* disable end of inserted group conversion interrupt */
|
||||
if(RESET != (interrupt & ADC_INT_EOIC)){
|
||||
ADC_CTL0 &= ~(uint32_t)ADC_CTL0_EOICIE;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure ADC analog watchdog single channel
|
||||
\param[in] channel: the selected ADC channel
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg ADC_CHANNEL_x(x=0..9,16,17): ADC Channelx
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_watchdog_single_channel_enable(uint8_t channel)
|
||||
{
|
||||
ADC_CTL0 &= (uint32_t)~(ADC_CTL0_RWDEN | ADC_CTL0_IWDEN | ADC_CTL0_WDSC | ADC_CTL0_WDCHSEL);
|
||||
|
||||
ADC_CTL0 |= (uint32_t)channel;
|
||||
ADC_CTL0 |= (uint32_t)(ADC_CTL0_RWDEN | ADC_CTL0_IWDEN | ADC_CTL0_WDSC);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure ADC analog watchdog group channel
|
||||
\param[in] channel_group: the channel group use analog watchdog
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg ADC_REGULAR_CHANNEL: regular channel group
|
||||
\arg ADC_INSERTED_CHANNEL: inserted channel group
|
||||
\arg ADC_REGULAR_INSERTED_CHANNEL: both regular and inserted group
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_watchdog_group_channel_enable(uint8_t channel_group)
|
||||
{
|
||||
ADC_CTL0 &= (uint32_t)~(ADC_CTL0_RWDEN | ADC_CTL0_IWDEN | ADC_CTL0_WDSC);
|
||||
|
||||
/* select the group */
|
||||
switch(channel_group){
|
||||
case ADC_REGULAR_CHANNEL:
|
||||
ADC_CTL0 |= (uint32_t)ADC_CTL0_RWDEN;
|
||||
break;
|
||||
case ADC_INSERTED_CHANNEL:
|
||||
ADC_CTL0 |= (uint32_t)ADC_CTL0_IWDEN;
|
||||
break;
|
||||
case ADC_REGULAR_INSERTED_CHANNEL:
|
||||
ADC_CTL0 |= (uint32_t)(ADC_CTL0_RWDEN | ADC_CTL0_IWDEN);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable ADC analog watchdog
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_watchdog_disable(void)
|
||||
{
|
||||
ADC_CTL0 &= (uint32_t)~(ADC_CTL0_RWDEN | ADC_CTL0_IWDEN | ADC_CTL0_WDSC | ADC_CTL0_WDCHSEL);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure ADC analog watchdog threshold
|
||||
\param[in] low_threshold: analog watchdog low threshold,0..4095
|
||||
\param[in] high_threshold: analog watchdog high threshold,0..4095
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_watchdog_threshold_config(uint16_t low_threshold, uint16_t high_threshold)
|
||||
{
|
||||
ADC_WDLT = (uint32_t)WDLT_WDLT(low_threshold);
|
||||
ADC_WDHT = (uint32_t)WDHT_WDHT(high_threshold);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\brief configure ADC resolution
|
||||
\param[in] resolution: ADC resolution
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg ADC_RESOLUTION_12B: 12-bit ADC resolution
|
||||
\arg ADC_RESOLUTION_10B: 10-bit ADC resolution
|
||||
\arg ADC_RESOLUTION_8B: 8-bit ADC resolution
|
||||
\arg ADC_RESOLUTION_6B: 6-bit ADC resolution
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_resolution_config(uint32_t resolution)
|
||||
{
|
||||
ADC_CTL0 &= ~((uint32_t)ADC_CTL0_DRES);
|
||||
ADC_CTL0 |= (uint32_t)resolution;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure ADC oversample mode
|
||||
\param[in] mode: ADC oversampling mode
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg ADC_OVERSAMPLING_ALL_CONVERT: all oversampled conversions for a channel are done consecutively after a trigger
|
||||
\arg ADC_OVERSAMPLING_ONE_CONVERT: each oversampled conversion for a channel needs a trigger
|
||||
\param[in] shift: ADC oversampling shift
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg ADC_OVERSAMPLING_SHIFT_NONE: no oversampling shift
|
||||
\arg ADC_OVERSAMPLING_SHIFT_1B: 1-bit oversampling shift
|
||||
\arg ADC_OVERSAMPLING_SHIFT_2B: 2-bit oversampling shift
|
||||
\arg ADC_OVERSAMPLING_SHIFT_3B: 3-bit oversampling shift
|
||||
\arg ADC_OVERSAMPLING_SHIFT_4B: 3-bit oversampling shift
|
||||
\arg ADC_OVERSAMPLING_SHIFT_5B: 5-bit oversampling shift
|
||||
\arg ADC_OVERSAMPLING_SHIFT_6B: 6-bit oversampling shift
|
||||
\arg ADC_OVERSAMPLING_SHIFT_7B: 7-bit oversampling shift
|
||||
\arg ADC_OVERSAMPLING_SHIFT_8B: 8-bit oversampling shift
|
||||
\param[in] ratio: ADC oversampling ratio
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg ADC_OVERSAMPLING_RATIO_MUL2: oversampling ratio multiple 2
|
||||
\arg ADC_OVERSAMPLING_RATIO_MUL4: oversampling ratio multiple 4
|
||||
\arg ADC_OVERSAMPLING_RATIO_MUL8: oversampling ratio multiple 8
|
||||
\arg ADC_OVERSAMPLING_RATIO_MUL16: oversampling ratio multiple 16
|
||||
\arg ADC_OVERSAMPLING_RATIO_MUL32: oversampling ratio multiple 32
|
||||
\arg ADC_OVERSAMPLING_RATIO_MUL64: oversampling ratio multiple 64
|
||||
\arg ADC_OVERSAMPLING_RATIO_MUL128: oversampling ratio multiple 128
|
||||
\arg ADC_OVERSAMPLING_RATIO_MUL256: oversampling ratio multiple 256
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_oversample_mode_config(uint8_t mode, uint16_t shift, uint8_t ratio)
|
||||
{
|
||||
/* configure ADC oversampling mode */
|
||||
if(ADC_OVERSAMPLING_ONE_CONVERT == mode){
|
||||
ADC_OVSAMPCTL |= (uint32_t)ADC_OVSAMPCTL_TOVS;
|
||||
}else{
|
||||
ADC_OVSAMPCTL &= ~((uint32_t)ADC_OVSAMPCTL_TOVS);
|
||||
}
|
||||
|
||||
/* configure the shift and ratio */
|
||||
ADC_OVSAMPCTL &= ~((uint32_t)(ADC_OVSAMPCTL_OVSR | ADC_OVSAMPCTL_OVSS));
|
||||
ADC_OVSAMPCTL |= ((uint32_t)shift | (uint32_t)ratio);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable ADC oversample mode
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_oversample_mode_enable(void)
|
||||
{
|
||||
ADC_OVSAMPCTL |= ADC_OVSAMPCTL_OVSEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable ADC oversample mode
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_oversample_mode_disable(void)
|
||||
{
|
||||
ADC_OVSAMPCTL &= ~((uint32_t)ADC_OVSAMPCTL_OVSEN);
|
||||
}
|
211
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_cmp.c
Normal file
211
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_cmp.c
Normal file
@@ -0,0 +1,211 @@
|
||||
/*!
|
||||
\file gd32f23x_cmp.c
|
||||
\brief CMP driver
|
||||
|
||||
\version 2024-02-22, V2.1.0, firmware for GD32E23x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2022, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "gd32e23x_cmp.h"
|
||||
|
||||
/*!
|
||||
\brief CMP deinit
|
||||
\param[in] cmp_periph
|
||||
\arg CMP0: comparator 0
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void cmp_deinit(cmp_enum cmp_periph)
|
||||
{
|
||||
if(CMP0 == cmp_periph){
|
||||
CMP_CS &= ((uint32_t)0xFFFF0000U);
|
||||
}else{
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief CMP mode init
|
||||
\param[in] cmp_periph
|
||||
\arg CMP0: comparator 0
|
||||
\param[in] operating_mode
|
||||
\arg CMP_MODE_HIGHSPEED: high speed mode
|
||||
\arg CMP_MODE_MIDDLESPEED: medium speed mode
|
||||
\arg CMP_MODE_LOWSPEED: low speed mode
|
||||
\arg CMP_MODE_VERYLOWSPEED: very-low speed mode
|
||||
\param[in] inverting_input
|
||||
\arg CMP_INVERTING_INPUT_1_4VREFINT: VREFINT *1/4 input
|
||||
\arg CMP_INVERTING_INPUT_1_2VREFINT: VREFINT *1/2 input
|
||||
\arg CMP_INVERTING_INPUT_3_4VREFINT: VREFINT *3/4 input
|
||||
\arg CMP_INVERTING_INPUT_VREFINT: VREFINT input
|
||||
\arg CMP_INVERTING_INPUT_PA4: PA4 input
|
||||
\arg CMP_INVERTING_INPUT_PA5: PA5 input
|
||||
\arg CMP_INVERTING_INPUT_PA0_PA2: PA0 for CMP0 or PA2 for CMP1 as inverting input
|
||||
\param[in] output_hysteresis
|
||||
\arg CMP_HYSTERESIS_NO: output no hysteresis
|
||||
\arg CMP_HYSTERESIS_LOW: output low hysteresis
|
||||
\arg CMP_HYSTERESIS_MIDDLE: output middle hysteresis
|
||||
\arg CMP_HYSTERESIS_HIGH: output high hysteresis
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void cmp_mode_init(cmp_enum cmp_periph, uint32_t operating_mode, uint32_t inverting_input, uint32_t output_hysteresis)
|
||||
{
|
||||
uint32_t temp = 0U;
|
||||
|
||||
if(CMP0 == cmp_periph){
|
||||
/* initialize comparator 0 mode */
|
||||
temp = CMP_CS;
|
||||
temp &= ~(uint32_t)(CMP_CS_CMP0M | CMP_CS_CMP0MSEL | CMP_CS_CMP0HST);
|
||||
temp |= (uint32_t)(operating_mode | inverting_input | output_hysteresis);
|
||||
CMP_CS = temp;
|
||||
}else{
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief CMP output init
|
||||
\param[in] cmp_periph
|
||||
\arg CMP0: comparator 0
|
||||
\param[in] output_selection
|
||||
\arg CMP_OUTPUT_NONE: CMP output none
|
||||
\arg CMP_OUTPUT_TIMER0_BKIN: CMP output TIMER0 break input
|
||||
\arg CMP_OUTPUT_TIMER0_IC0: CMP output TIMER0_CH0 input capture
|
||||
\arg CMP_OUTPUT_TIMER0_OCPRECLR: CMP output TIMER0 OCPRE_CLR input
|
||||
\arg CMP_OUTPUT_TIMER2_IC0: CMP output TIMER2_CH0 input capture
|
||||
\arg CMP_OUTPUT_TIMER2_OCPRECLR: CMP output TIMER2 OCPRE_CLR input
|
||||
\param[in] output_polarity
|
||||
\arg CMP_OUTPUT_POLARITY_INVERTED: output is inverted
|
||||
\arg CMP_OUTPUT_POLARITY_NONINVERTED: output is not inverted
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void cmp_output_init(cmp_enum cmp_periph, uint32_t output_selection, uint32_t output_polarity)
|
||||
{
|
||||
uint32_t temp = 0U;
|
||||
|
||||
if(CMP0 == cmp_periph){
|
||||
/* initialize comparator 0 output */
|
||||
temp = CMP_CS;
|
||||
temp &= ~(uint32_t)CMP_CS_CMP0OSEL;
|
||||
temp |= (uint32_t)output_selection;
|
||||
/* output polarity */
|
||||
if(CMP_OUTPUT_POLARITY_INVERTED == output_polarity){
|
||||
temp |= (uint32_t)CMP_CS_CMP0PL;
|
||||
}else{
|
||||
temp &= ~(uint32_t)CMP_CS_CMP0PL;
|
||||
}
|
||||
CMP_CS = temp;
|
||||
}else{
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable CMP
|
||||
\param[in] cmp_periph
|
||||
\arg CMP0: comparator 0
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void cmp_enable(cmp_enum cmp_periph)
|
||||
{
|
||||
if(CMP0 == cmp_periph){
|
||||
CMP_CS |= (uint32_t)CMP_CS_CMP0EN;
|
||||
}else{
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable CMP
|
||||
\param[in] cmp_periph
|
||||
\arg CMP0: comparator 0
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void cmp_disable(cmp_enum cmp_periph)
|
||||
{
|
||||
if(CMP0 == cmp_periph){
|
||||
CMP_CS &= ~(uint32_t)CMP_CS_CMP0EN;
|
||||
}else{
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable CMP switch
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void cmp_switch_enable(void)
|
||||
{
|
||||
CMP_CS |= (uint32_t)CMP_CS_CMP0SW;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable CMP switch
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void cmp_switch_disable(void)
|
||||
{
|
||||
CMP_CS &= ~(uint32_t)CMP_CS_CMP0SW;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief lock the CMP
|
||||
\param[in] cmp_periph
|
||||
\arg CMP0: comparator 0
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void cmp_lock_enable(cmp_enum cmp_periph)
|
||||
{
|
||||
if(CMP0 == cmp_periph){
|
||||
/* lock CMP0 */
|
||||
CMP_CS |= (uint32_t)CMP_CS_CMP0LK;
|
||||
}else{
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get output level
|
||||
\param[in] cmp_periph
|
||||
\arg CMP0: comparator 0
|
||||
\param[out] none
|
||||
\retval the output level
|
||||
*/
|
||||
uint32_t cmp_output_level_get(cmp_enum cmp_periph)
|
||||
{
|
||||
/* get output level of CMP0 */
|
||||
if((uint32_t)RESET != (CMP_CS & CMP_CS_CMP0O)) {
|
||||
return CMP_OUTPUTLEVEL_HIGH;
|
||||
}else{
|
||||
return CMP_OUTPUTLEVEL_LOW;
|
||||
}
|
||||
}
|
241
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_crc.c
Normal file
241
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_crc.c
Normal file
@@ -0,0 +1,241 @@
|
||||
/*!
|
||||
\file gd32e23x_crc.c
|
||||
\brief CRC driver
|
||||
|
||||
\version 2024-02-22, V2.1.0, firmware for GD32E23x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2024, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "gd32e23x_crc.h"
|
||||
|
||||
/*!
|
||||
\brief deinit CRC calculation unit
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void crc_deinit(void)
|
||||
{
|
||||
CRC_IDATA = (uint32_t)0xFFFFFFFFU;
|
||||
CRC_DATA = (uint32_t)0xFFFFFFFFU;
|
||||
CRC_FDATA = (uint32_t)0x00000000U;
|
||||
CRC_POLY = (uint32_t)0x04C11DB7U;
|
||||
CRC_CTL = CRC_CTL_RST;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable the reverse operation of output data
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void crc_reverse_output_data_enable(void)
|
||||
{
|
||||
CRC_CTL &= (uint32_t)(~ CRC_CTL_REV_O);
|
||||
CRC_CTL |= (uint32_t)CRC_CTL_REV_O;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable the reverse operation of output data
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void crc_reverse_output_data_disable(void)
|
||||
{
|
||||
CRC_CTL &= (uint32_t)(~ CRC_CTL_REV_O);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief reset data register to the value of initializaiton data register
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void crc_data_register_reset(void)
|
||||
{
|
||||
CRC_CTL |= (uint32_t)CRC_CTL_RST;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief read the data register
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval 32-bit value of the data register
|
||||
*/
|
||||
uint32_t crc_data_register_read(void)
|
||||
{
|
||||
uint32_t data;
|
||||
data = CRC_DATA;
|
||||
return (data);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief read the free data register
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval 8-bit value of the free data register
|
||||
*/
|
||||
uint8_t crc_free_data_register_read(void)
|
||||
{
|
||||
uint8_t fdata;
|
||||
fdata = (uint8_t)CRC_FDATA;
|
||||
return (fdata);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief write the free data register
|
||||
\param[in] free_data: specify 8-bit data
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void crc_free_data_register_write(uint8_t free_data)
|
||||
{
|
||||
CRC_FDATA = (uint32_t)free_data;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief write the initializaiton data register
|
||||
\param[in] init_data:specify 32-bit data
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void crc_init_data_register_write(uint32_t init_data)
|
||||
{
|
||||
CRC_IDATA = (uint32_t)init_data;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure the CRC input data function
|
||||
\param[in] data_reverse: specify input data reverse function
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg CRC_INPUT_DATA_NOT: input data is not reversed
|
||||
\arg CRC_INPUT_DATA_BYTE: input data is reversed on 8 bits
|
||||
\arg CRC_INPUT_DATA_HALFWORD: input data is reversed on 16 bits
|
||||
\arg CRC_INPUT_DATA_WORD: input data is reversed on 32 bits
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void crc_input_data_reverse_config(uint32_t data_reverse)
|
||||
{
|
||||
CRC_CTL &= (uint32_t)(~CRC_CTL_REV_I);
|
||||
CRC_CTL |= (uint32_t)data_reverse;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure the CRC size of polynomial function
|
||||
\param[in] poly_size: size of polynomial
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg CRC_CTL_PS_32: 32-bit polynomial for CRC calculation
|
||||
\arg CRC_CTL_PS_16: 16-bit polynomial for CRC calculation
|
||||
\arg CRC_CTL_PS_8: 8-bit polynomial for CRC calculation
|
||||
\arg CRC_CTL_PS_7: 7-bit polynomial for CRC calculation
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void crc_polynomial_size_set(uint32_t poly_size)
|
||||
{
|
||||
CRC_CTL &= (uint32_t)(~(CRC_CTL_PS));
|
||||
CRC_CTL |= (uint32_t)poly_size;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure the CRC polynomial value function
|
||||
\param[in] poly: configurable polynomial value
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void crc_polynomial_set(uint32_t poly)
|
||||
{
|
||||
CRC_POLY &= (uint32_t)(~CRC_POLY_POLY);
|
||||
CRC_POLY = poly;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief CRC calculate single data
|
||||
\param[in] sdata: specify input data
|
||||
\param[in] data_format: input data format
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg INPUT_FORMAT_WORD: input data in word format
|
||||
\arg INPUT_FORMAT_HALFWORD: input data in half-word format
|
||||
\arg INPUT_FORMAT_BYTE: input data in byte format
|
||||
\param[out] none
|
||||
\retval CRC calculate value
|
||||
*/
|
||||
uint32_t crc_single_data_calculate(uint32_t sdata, uint8_t data_format)
|
||||
{
|
||||
if(INPUT_FORMAT_WORD == data_format){
|
||||
REG32(CRC) = sdata;
|
||||
}else if(INPUT_FORMAT_HALFWORD == data_format){
|
||||
REG16(CRC) = (uint16_t)sdata;
|
||||
}else{
|
||||
REG8(CRC) = (uint8_t)sdata;
|
||||
}
|
||||
|
||||
return(CRC_DATA);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief CRC calculate a data array
|
||||
\param[in] array: pointer to the input data array
|
||||
\param[in] size: size of the array
|
||||
\param[in] data_format: input data format
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg INPUT_FORMAT_WORD: input data in word format
|
||||
\arg INPUT_FORMAT_HALFWORD: input data in half-word format
|
||||
\arg INPUT_FORMAT_BYTE: input data in byte format
|
||||
\param[out] none
|
||||
\retval CRC calculate value
|
||||
*/
|
||||
uint32_t crc_block_data_calculate(void *array, uint32_t size, uint8_t data_format)
|
||||
{
|
||||
uint8_t *data8;
|
||||
uint16_t *data16;
|
||||
uint32_t *data32;
|
||||
uint32_t index;
|
||||
|
||||
if(INPUT_FORMAT_WORD == data_format){
|
||||
data32 = (uint32_t *)array;
|
||||
for(index = 0U; index < size; index++){
|
||||
REG32(CRC) = data32[index];
|
||||
}
|
||||
}else if(INPUT_FORMAT_HALFWORD == data_format){
|
||||
data16 = (uint16_t *)array;
|
||||
for(index = 0U; index < size; index++){
|
||||
REG16(CRC) = data16[index];
|
||||
}
|
||||
}else{
|
||||
data8 = (uint8_t *)array;
|
||||
for(index = 0U; index < size; index++){
|
||||
REG8(CRC) = data8[index];
|
||||
}
|
||||
}
|
||||
|
||||
return (CRC_DATA);
|
||||
}
|
138
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_dbg.c
Normal file
138
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_dbg.c
Normal file
@@ -0,0 +1,138 @@
|
||||
/*!
|
||||
\file gd32e23x_dbg.c
|
||||
\brief DBG driver
|
||||
|
||||
\version 2024-02-22, V2.1.0, firmware for GD32E23x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2024, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "gd32e23x_dbg.h"
|
||||
|
||||
#define DBG_RESET_VAL 0x00000000U
|
||||
|
||||
/*!
|
||||
\brief deinitialize the DBG
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dbg_deinit(void)
|
||||
{
|
||||
DBG_CTL0 = DBG_RESET_VAL;
|
||||
DBG_CTL1 = DBG_RESET_VAL;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief read DBG_ID code register
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval DBG_ID code
|
||||
*/
|
||||
uint32_t dbg_id_get(void)
|
||||
{
|
||||
return DBG_ID;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable low power behavior when the mcu is in debug mode
|
||||
\param[in] dbg_low_power:
|
||||
this parameter can be any combination of the following values:
|
||||
\arg DBG_LOW_POWER_SLEEP: keep debugger connection during sleep mode
|
||||
\arg DBG_LOW_POWER_DEEPSLEEP: keep debugger connection during deepsleep mode
|
||||
\arg DBG_LOW_POWER_STANDBY: keep debugger connection during standby mode
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dbg_low_power_enable(uint32_t dbg_low_power)
|
||||
{
|
||||
DBG_CTL0 |= dbg_low_power;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable low power behavior when the mcu is in debug mode
|
||||
\param[in] dbg_low_power:
|
||||
this parameter can be any combination of the following values:
|
||||
\arg DBG_LOW_POWER_SLEEP: donot keep debugger connection during sleep mode
|
||||
\arg DBG_LOW_POWER_DEEPSLEEP: donot keep debugger connection during deepsleep mode
|
||||
\arg DBG_LOW_POWER_STANDBY: donot keep debugger connection during standby mode
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dbg_low_power_disable(uint32_t dbg_low_power)
|
||||
{
|
||||
DBG_CTL0 &= ~dbg_low_power;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable peripheral behavior when the mcu is in debug mode
|
||||
\param[in] dbg_periph: DBG peripheral
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DBG_FWDGT_HOLD: debug FWDGT kept when core is halted
|
||||
\arg DBG_WWDGT_HOLD: debug WWDGT kept when core is halted
|
||||
\arg DBG_TIMER0_HOLD: TIMER0 counter kept when core is halted
|
||||
\arg DBG_TIMER2_HOLD: TIMER2 counter kept when core is halted
|
||||
\arg DBG_TIMER5_HOLD: hold TIMER5 counter when core is halted
|
||||
\arg DBG_TIMER13_HOLD: hold TIMER13 counter when core is halted
|
||||
\arg DBG_TIMER14_HOLD: hold TIMER14 counter when core is halted
|
||||
\arg DBG_TIMER15_HOLD: hold TIMER15 counter when core is halted
|
||||
\arg DBG_TIMER16_HOLD: hold TIMER16 counter when core is halted
|
||||
\arg DBG_I2C0_HOLD: hold I2C0 SMBUS when core is halted
|
||||
\arg DBG_I2C1_HOLD: hold I2C1 SMBUS when core is halted
|
||||
\arg DBG_RTC_HOLD: hold RTC calendar and wakeup counter when core is halted
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dbg_periph_enable(dbg_periph_enum dbg_periph)
|
||||
{
|
||||
DBG_REG_VAL(dbg_periph) |= BIT(DBG_BIT_POS(dbg_periph));
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable peripheral behavior when the mcu is in debug mode
|
||||
\param[in] dbg_periph: DBG peripheral
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DBG_FWDGT_HOLD: debug FWDGT kept when core is halted
|
||||
\arg DBG_WWDGT_HOLD: debug WWDGT kept when core is halted
|
||||
\arg DBG_TIMER0_HOLD: TIMER0 counter kept when core is halted
|
||||
\arg DBG_TIMER2_HOLD: TIMER2 counter kept when core is halted
|
||||
\arg DBG_TIMER5_HOLD: hold TIMER5 counter when core is halted
|
||||
\arg DBG_TIMER13_HOLD: hold TIMER13 counter when core is halted
|
||||
\arg DBG_TIMER14_HOLD: hold TIMER14 counter when core is halted
|
||||
\arg DBG_TIMER15_HOLD: hold TIMER15 counter when core is halted
|
||||
\arg DBG_TIMER16_HOLD: hold TIMER16 counter when core is halted
|
||||
\arg DBG_I2C0_HOLD: hold I2C0 SMBUS when core is halted
|
||||
\arg DBG_I2C1_HOLD: hold I2C1 SMBUS when core is halted
|
||||
\arg DBG_RTC_HOLD: hold RTC calendar and wakeup counter when core is halted
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dbg_periph_disable(dbg_periph_enum dbg_periph)
|
||||
{
|
||||
DBG_REG_VAL(dbg_periph) &= ~BIT(DBG_BIT_POS(dbg_periph));
|
||||
}
|
560
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_dma.c
Normal file
560
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_dma.c
Normal file
@@ -0,0 +1,560 @@
|
||||
/*!
|
||||
\file gd32e23x_dma.c
|
||||
\brief DMA driver
|
||||
|
||||
\version 2024-02-22, V2.1.0, firmware for GD32E23x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2024, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "gd32e23x_dma.h"
|
||||
|
||||
/*!
|
||||
\brief deinitialize DMA a channel registers
|
||||
\param[in] channelx: specify which DMA channel is deinitialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_deinit(dma_channel_enum channelx)
|
||||
{
|
||||
/* disable DMA a channel */
|
||||
DMA_CHCTL(channelx) &= ~DMA_CHXCTL_CHEN;
|
||||
/* reset DMA channel registers */
|
||||
DMA_CHCTL(channelx) = DMA_CHCTL_RESET_VALUE;
|
||||
DMA_CHCNT(channelx) = DMA_CHCNT_RESET_VALUE;
|
||||
DMA_CHPADDR(channelx) = DMA_CHPADDR_RESET_VALUE;
|
||||
DMA_CHMADDR(channelx) = DMA_CHMADDR_RESET_VALUE;
|
||||
DMA_INTC |= DMA_FLAG_ADD(DMA_CHINTF_RESET_VALUE, channelx);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief initialize the parameters of DMA struct with the default values
|
||||
\param[in] init_struct: the initialization data needed to initialize DMA channel
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_struct_para_init(dma_parameter_struct* init_struct)
|
||||
{
|
||||
/* set the DMA struct with the default values */
|
||||
init_struct->periph_addr = 0U;
|
||||
init_struct->periph_width = 0U;
|
||||
init_struct->periph_inc = (uint8_t)DMA_PERIPH_INCREASE_DISABLE;
|
||||
init_struct->memory_addr = 0U;
|
||||
init_struct->memory_width = 0U;
|
||||
init_struct->memory_inc = (uint8_t)DMA_MEMORY_INCREASE_DISABLE;
|
||||
init_struct->number = 0U;
|
||||
init_struct->direction = (uint8_t)DMA_PERIPHERAL_TO_MEMORY;
|
||||
init_struct->priority = (uint32_t)DMA_PRIORITY_LOW;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief initialize DMA channel
|
||||
\param[in] channelx: specify which DMA channel is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[in] init_struct: the data needed to initialize DMA channel
|
||||
periph_addr: peripheral base address
|
||||
periph_width: DMA_PERIPHERAL_WIDTH_8BIT,DMA_PERIPHERAL_WIDTH_16BIT,DMA_PERIPHERAL_WIDTH_32BIT
|
||||
periph_inc: DMA_PERIPH_INCREASE_ENABLE,DMA_PERIPH_INCREASE_DISABLE
|
||||
memory_addr: memory base address
|
||||
memory_width: DMA_MEMORY_WIDTH_8BIT,DMA_MEMORY_WIDTH_16BIT,DMA_MEMORY_WIDTH_32BIT
|
||||
memory_inc: DMA_MEMORY_INCREASE_ENABLE,DMA_MEMORY_INCREASE_DISABLE
|
||||
direction: DMA_PERIPHERAL_TO_MEMORY,DMA_MEMORY_TO_PERIPHERAL
|
||||
number: the number of remaining data to be transferred by the DMA
|
||||
priority: DMA_PRIORITY_LOW,DMA_PRIORITY_MEDIUM,DMA_PRIORITY_HIGH,DMA_PRIORITY_ULTRA_HIGH
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_init(dma_channel_enum channelx, dma_parameter_struct* init_struct)
|
||||
{
|
||||
uint32_t ctl;
|
||||
|
||||
dma_channel_disable(channelx);
|
||||
|
||||
/* configure peripheral base address */
|
||||
DMA_CHPADDR(channelx) = init_struct->periph_addr;
|
||||
|
||||
/* configure memory base address */
|
||||
DMA_CHMADDR(channelx) = init_struct->memory_addr;
|
||||
|
||||
/* configure the number of remaining data to be transferred */
|
||||
DMA_CHCNT(channelx) = (init_struct->number & DMA_CHANNEL_CNT_MASK);
|
||||
|
||||
/* configure peripheral transfer width,memory transfer width,channel priotity */
|
||||
ctl = DMA_CHCTL(channelx);
|
||||
ctl &= ~(DMA_CHXCTL_PWIDTH | DMA_CHXCTL_MWIDTH | DMA_CHXCTL_PRIO);
|
||||
ctl |= (init_struct->periph_width | init_struct->memory_width | init_struct->priority);
|
||||
DMA_CHCTL(channelx) = ctl;
|
||||
|
||||
/* configure peripheral increasing mode */
|
||||
if(DMA_PERIPH_INCREASE_ENABLE == init_struct->periph_inc){
|
||||
DMA_CHCTL(channelx) |= DMA_CHXCTL_PNAGA;
|
||||
}else{
|
||||
DMA_CHCTL(channelx) &= ~DMA_CHXCTL_PNAGA;
|
||||
}
|
||||
|
||||
/* configure memory increasing mode */
|
||||
if(DMA_MEMORY_INCREASE_ENABLE == init_struct->memory_inc){
|
||||
DMA_CHCTL(channelx) |= DMA_CHXCTL_MNAGA;
|
||||
}else{
|
||||
DMA_CHCTL(channelx) &= ~DMA_CHXCTL_MNAGA;
|
||||
}
|
||||
|
||||
/* configure the direction of data transfer */
|
||||
if(DMA_PERIPHERAL_TO_MEMORY == init_struct->direction){
|
||||
DMA_CHCTL(channelx) &= ~DMA_CHXCTL_DIR;
|
||||
}else{
|
||||
DMA_CHCTL(channelx) |= DMA_CHXCTL_DIR;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable DMA circulation mode
|
||||
\param[in] channelx: specify which DMA channel to set
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_circulation_enable(dma_channel_enum channelx)
|
||||
{
|
||||
DMA_CHCTL(channelx) |= DMA_CHXCTL_CMEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable DMA circulation mode
|
||||
\param[in] channelx: specify which DMA channel to set
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_circulation_disable(dma_channel_enum channelx)
|
||||
{
|
||||
DMA_CHCTL(channelx) &= ~DMA_CHXCTL_CMEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable memory to memory mode
|
||||
\param[in] channelx: specify which DMA channel to set
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_memory_to_memory_enable(dma_channel_enum channelx)
|
||||
{
|
||||
DMA_CHCTL(channelx) |= DMA_CHXCTL_M2M;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable memory to memory mode
|
||||
\param[in] channelx: specify which DMA channel to set
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_memory_to_memory_disable(dma_channel_enum channelx)
|
||||
{
|
||||
DMA_CHCTL(channelx) &= ~DMA_CHXCTL_M2M;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable DMA channel
|
||||
\param[in] channelx: specify which DMA channel to set
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_channel_enable(dma_channel_enum channelx)
|
||||
{
|
||||
DMA_CHCTL(channelx) |= DMA_CHXCTL_CHEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable DMA channel
|
||||
\param[in] channelx: specify which DMA channel to set
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_channel_disable(dma_channel_enum channelx)
|
||||
{
|
||||
DMA_CHCTL(channelx) &= ~DMA_CHXCTL_CHEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set DMA peripheral base address
|
||||
\param[in] channelx: specify which DMA channel to set peripheral base address
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[in] address: peripheral base address
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_periph_address_config(dma_channel_enum channelx, uint32_t address)
|
||||
{
|
||||
DMA_CHPADDR(channelx) = address;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set DMA memory base address
|
||||
\param[in] channelx: specify which DMA channel to set memory base address
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[in] address: memory base address
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_memory_address_config(dma_channel_enum channelx, uint32_t address)
|
||||
{
|
||||
DMA_CHMADDR(channelx) = address;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set the number of remaining data to be transferred by the DMA
|
||||
\param[in] channelx: specify which DMA channel to set number
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[in] number: the number of remaining data to be transferred by the DMA
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_transfer_number_config(dma_channel_enum channelx, uint32_t number)
|
||||
{
|
||||
DMA_CHCNT(channelx) = (number & DMA_CHANNEL_CNT_MASK);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get the number of remaining data to be transferred by the DMA
|
||||
\param[in] channelx: specify which DMA channel to set number
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[out] none
|
||||
\retval the number of remaining data to be transferred by the DMA
|
||||
*/
|
||||
uint32_t dma_transfer_number_get(dma_channel_enum channelx)
|
||||
{
|
||||
return (uint32_t)DMA_CHCNT(channelx);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure priority level of DMA channel
|
||||
\param[in] channelx: specify which DMA channel to set
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[in] priority: priority level of this channel
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_PRIORITY_LOW: low priority
|
||||
\arg DMA_PRIORITY_MEDIUM: medium priority
|
||||
\arg DMA_PRIORITY_HIGH: high priority
|
||||
\arg DMA_PRIORITY_ULTRA_HIGH: ultra high priority
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_priority_config(dma_channel_enum channelx, uint32_t priority)
|
||||
{
|
||||
uint32_t ctl;
|
||||
|
||||
/* acquire DMA_CHxCTL register */
|
||||
ctl = DMA_CHCTL(channelx);
|
||||
/* assign regiser */
|
||||
ctl &= ~DMA_CHXCTL_PRIO;
|
||||
ctl |= priority;
|
||||
DMA_CHCTL(channelx) = ctl;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure transfer data width of memory
|
||||
\param[in] channelx: specify which DMA channel to set
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[in] mwidth: transfer data width of memory
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_MEMORY_WIDTH_8BIT: transfer data width of memory is 8-bit
|
||||
\arg DMA_MEMORY_WIDTH_16BIT: transfer data width of memory is 16-bit
|
||||
\arg DMA_MEMORY_WIDTH_32BIT: transfer data width of memory is 32-bit
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_memory_width_config(dma_channel_enum channelx, uint32_t mwidth)
|
||||
{
|
||||
uint32_t ctl;
|
||||
|
||||
/* acquire DMA_CHxCTL register */
|
||||
ctl = DMA_CHCTL(channelx);
|
||||
/* assign regiser */
|
||||
ctl &= ~DMA_CHXCTL_MWIDTH;
|
||||
ctl |= mwidth;
|
||||
DMA_CHCTL(channelx) = ctl;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure transfer data width of peripheral
|
||||
\param[in] channelx: specify which DMA channel to set
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[in] pwidth: transfer data width of peripheral
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_PERIPHERAL_WIDTH_8BIT: transfer data width of peripheral is 8-bit
|
||||
\arg DMA_PERIPHERAL_WIDTH_16BIT: transfer data width of peripheral is 16-bit
|
||||
\arg DMA_PERIPHERAL_WIDTH_32BIT: transfer data width of peripheral is 32-bit
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_periph_width_config(dma_channel_enum channelx, uint32_t pwidth)
|
||||
{
|
||||
uint32_t ctl;
|
||||
|
||||
/* acquire DMA_CHxCTL register */
|
||||
ctl = DMA_CHCTL(channelx);
|
||||
/* assign regiser */
|
||||
ctl &= ~DMA_CHXCTL_PWIDTH;
|
||||
ctl |= pwidth;
|
||||
DMA_CHCTL(channelx) = ctl;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable next address increasement algorithm of memory
|
||||
\param[in] channelx: specify which DMA channel to set
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_memory_increase_enable(dma_channel_enum channelx)
|
||||
{
|
||||
DMA_CHCTL(channelx) |= DMA_CHXCTL_MNAGA;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable next address increasement algorithm of memory
|
||||
\param[in] channelx: specify which DMA channel to set
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_memory_increase_disable(dma_channel_enum channelx)
|
||||
{
|
||||
DMA_CHCTL(channelx) &= ~DMA_CHXCTL_MNAGA;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable next address increasement algorithm of peripheral
|
||||
\param[in] channelx: specify which DMA channel to set
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_periph_increase_enable(dma_channel_enum channelx)
|
||||
{
|
||||
DMA_CHCTL(channelx) |= DMA_CHXCTL_PNAGA;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable next address increasement algorithm of peripheral
|
||||
\param[in] channelx: specify which DMA channel to set
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_periph_increase_disable(dma_channel_enum channelx)
|
||||
{
|
||||
DMA_CHCTL(channelx) &= ~DMA_CHXCTL_PNAGA;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure the direction of data transfer on the channel
|
||||
\param[in] channelx: specify which DMA channel to set
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[in] direction: specify the direction of data transfer
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_PERIPHERAL_TO_MEMORY: read from peripheral and write to memory
|
||||
\arg DMA_MEMORY_TO_PERIPHERAL: read from memory and write to peripheral
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_transfer_direction_config(dma_channel_enum channelx, uint8_t direction)
|
||||
{
|
||||
if(DMA_PERIPHERAL_TO_MEMORY == direction){
|
||||
DMA_CHCTL(channelx) &= ~DMA_CHXCTL_DIR;
|
||||
} else {
|
||||
DMA_CHCTL(channelx) |= DMA_CHXCTL_DIR;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief check DMA flag is set or not
|
||||
\param[in] channelx: specify which DMA channel to get flag
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[in] flag: specify get which flag
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_FLAG_G: global interrupt flag of channel
|
||||
\arg DMA_FLAG_FTF: full transfer finish flag of channel
|
||||
\arg DMA_FLAG_HTF: half transfer finish flag of channel
|
||||
\arg DMA_FLAG_ERR: error flag of channel
|
||||
\param[out] none
|
||||
\retval FlagStatus: SET or RESET
|
||||
*/
|
||||
FlagStatus dma_flag_get(dma_channel_enum channelx, uint32_t flag)
|
||||
{
|
||||
FlagStatus reval;
|
||||
|
||||
if(RESET != (DMA_INTF & DMA_FLAG_ADD(flag, channelx))){
|
||||
reval = SET;
|
||||
}else{
|
||||
reval = RESET;
|
||||
}
|
||||
|
||||
return reval;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief clear DMA a channel flag
|
||||
\param[in] channelx: specify which DMA channel to clear flag
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[in] flag: specify get which flag
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_FLAG_G: global interrupt flag of channel
|
||||
\arg DMA_FLAG_FTF: full transfer finish flag of channel
|
||||
\arg DMA_FLAG_HTF: half transfer finish flag of channel
|
||||
\arg DMA_FLAG_ERR: error flag of channel
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_flag_clear(dma_channel_enum channelx, uint32_t flag)
|
||||
{
|
||||
DMA_INTC |= DMA_FLAG_ADD(flag, channelx);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief check DMA flag and interrupt enable bit is set or not
|
||||
\param[in] channelx: specify which DMA channel to get flag
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[in] flag: specify get which flag
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_INT_FLAG_FTF: transfer finish flag of channel
|
||||
\arg DMA_INT_FLAG_HTF: half transfer finish flag of channel
|
||||
\arg DMA_INT_FLAG_ERR: error flag of channel
|
||||
\param[out] none
|
||||
\retval FlagStatus: SET or RESET
|
||||
*/
|
||||
FlagStatus dma_interrupt_flag_get(dma_channel_enum channelx, uint32_t flag)
|
||||
{
|
||||
uint32_t interrupt_enable = 0U, interrupt_flag = 0U;
|
||||
|
||||
switch(flag){
|
||||
case DMA_INT_FLAG_FTF:
|
||||
interrupt_flag = DMA_INTF & DMA_FLAG_ADD(flag, channelx);
|
||||
interrupt_enable = DMA_CHCTL(channelx) & DMA_CHXCTL_FTFIE;
|
||||
break;
|
||||
case DMA_INT_FLAG_HTF:
|
||||
interrupt_flag = DMA_INTF & DMA_FLAG_ADD(flag, channelx);
|
||||
interrupt_enable = DMA_CHCTL(channelx) & DMA_CHXCTL_HTFIE;
|
||||
break;
|
||||
case DMA_INT_FLAG_ERR:
|
||||
interrupt_flag = DMA_INTF & DMA_FLAG_ADD(flag, channelx);
|
||||
interrupt_enable = DMA_CHCTL(channelx) & DMA_CHXCTL_ERRIE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(interrupt_flag && interrupt_enable){
|
||||
return SET;
|
||||
}else{
|
||||
return RESET;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief clear DMA a channel interrupt flag
|
||||
\param[in] channelx: specify which DMA channel to clear flag
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[in] flag: specify get which flag
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_INT_FLAG_G: global interrupt flag of channel
|
||||
\arg DMA_INT_FLAG_FTF: transfer finish flag of channel
|
||||
\arg DMA_INT_FLAG_HTF: half transfer finish flag of channel
|
||||
\arg DMA_INT_FLAG_ERR: error flag of channel
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_interrupt_flag_clear(dma_channel_enum channelx, uint32_t flag)
|
||||
{
|
||||
DMA_INTC |= DMA_FLAG_ADD(flag,channelx);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable DMA interrupt
|
||||
\param[in] channelx: specify which DMA channel to set
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[in] source: specify which interrupt to enable
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_INT_ERR: channel error interrupt
|
||||
\arg DMA_INT_HTF: channel half transfer finish interrupt
|
||||
\arg DMA_INT_FTF: channel full transfer finish interrupt
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_interrupt_enable(dma_channel_enum channelx, uint32_t source)
|
||||
{
|
||||
DMA_CHCTL(channelx) |= source;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable DMA interrupt
|
||||
\param[in] channelx: specify which DMA channel to set
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_CHx(x=0..4)
|
||||
\param[in] source: specify which interrupt to disable
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg DMA_INT_ERR: channel error interrupt
|
||||
\arg DMA_INT_HTF: channel half transfer finish interrupt
|
||||
\arg DMA_INT_FTF: channel full transfer finish interrupt
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_interrupt_disable(dma_channel_enum channelx, uint32_t source)
|
||||
{
|
||||
DMA_CHCTL(channelx) &= ~source;
|
||||
}
|
251
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_exti.c
Normal file
251
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_exti.c
Normal file
@@ -0,0 +1,251 @@
|
||||
/*!
|
||||
\file gd32e23x_exti.c
|
||||
\brief EXTI driver
|
||||
|
||||
\version 2024-02-22, V2.1.0, firmware for GD32E23x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2024, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "gd32e23x_exti.h"
|
||||
|
||||
#define EXTI_INTEN_RESET_VAL ((uint32_t)0x0F900000U)
|
||||
#define EXTI_REG_RESET_VAL ((uint32_t)0x00000000U)
|
||||
|
||||
|
||||
/*!
|
||||
\brief reset the value of all EXTI registers with initial values
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void exti_deinit(void)
|
||||
{
|
||||
/* reset the value of the EXTI registers */
|
||||
EXTI_INTEN = EXTI_INTEN_RESET_VAL;
|
||||
EXTI_EVEN = EXTI_REG_RESET_VAL;
|
||||
EXTI_RTEN = EXTI_REG_RESET_VAL;
|
||||
EXTI_FTEN = EXTI_REG_RESET_VAL;
|
||||
EXTI_SWIEV = EXTI_REG_RESET_VAL;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief initialize the EXTI line x
|
||||
\param[in] linex: EXTI line number, refer to exti_line_enum
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg EXTI_x (x=0..17,19,21): EXTI line x
|
||||
\param[in] mode: interrupt or event mode, refer to exti_mode_enum
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg EXTI_INTERRUPT: interrupt mode
|
||||
\arg EXTI_EVENT: event mode
|
||||
\param[in] trig_type: interrupt trigger type, refer to exti_trig_type_enum
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg EXTI_TRIG_RISING: rising edge trigger
|
||||
\arg EXTI_TRIG_FALLING: falling trigger
|
||||
\arg EXTI_TRIG_BOTH: rising and falling trigger
|
||||
\arg EXTI_TRIG_NONE: without rising edge or falling edge trigger
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void exti_init(exti_line_enum linex, exti_mode_enum mode, exti_trig_type_enum trig_type)
|
||||
{
|
||||
/* reset the EXTI line x */
|
||||
EXTI_INTEN &= ~(uint32_t)linex;
|
||||
EXTI_EVEN &= ~(uint32_t)linex;
|
||||
EXTI_RTEN &= ~(uint32_t)linex;
|
||||
EXTI_FTEN &= ~(uint32_t)linex;
|
||||
|
||||
/* set the EXTI mode and enable the interrupts or events from EXTI line x */
|
||||
switch(mode) {
|
||||
case EXTI_INTERRUPT:
|
||||
EXTI_INTEN |= (uint32_t)linex;
|
||||
break;
|
||||
case EXTI_EVENT:
|
||||
EXTI_EVEN |= (uint32_t)linex;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* set the EXTI trigger type */
|
||||
switch(trig_type) {
|
||||
case EXTI_TRIG_RISING:
|
||||
EXTI_RTEN |= (uint32_t)linex;
|
||||
EXTI_FTEN &= ~(uint32_t)linex;
|
||||
break;
|
||||
case EXTI_TRIG_FALLING:
|
||||
EXTI_RTEN &= ~(uint32_t)linex;
|
||||
EXTI_FTEN |= (uint32_t)linex;
|
||||
break;
|
||||
case EXTI_TRIG_BOTH:
|
||||
EXTI_RTEN |= (uint32_t)linex;
|
||||
EXTI_FTEN |= (uint32_t)linex;
|
||||
break;
|
||||
case EXTI_TRIG_NONE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable the interrupts from EXTI line x
|
||||
\param[in] linex: EXTI line number, refer to exti_line_enum
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg EXTI_x (x=0..27): EXTI line x
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void exti_interrupt_enable(exti_line_enum linex)
|
||||
{
|
||||
EXTI_INTEN |= (uint32_t)linex;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable the interrupts from EXTI line x
|
||||
\param[in] linex: EXTI line number, refer to exti_line_enum
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg EXTI_x (x=0..27): EXTI line x
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void exti_interrupt_disable(exti_line_enum linex)
|
||||
{
|
||||
EXTI_INTEN &= ~(uint32_t)linex;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable the events from EXTI line x
|
||||
\param[in] linex: EXTI line number, refer to exti_line_enum
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg EXTI_x (x=0..27): EXTI line x
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void exti_event_enable(exti_line_enum linex)
|
||||
{
|
||||
EXTI_EVEN |= (uint32_t)linex;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable the events from EXTI line x
|
||||
\param[in] linex: EXTI line number, refer to exti_line_enum
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg EXTI_x (x=0..27): EXTI line x
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void exti_event_disable(exti_line_enum linex)
|
||||
{
|
||||
EXTI_EVEN &= ~(uint32_t)linex;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable the software interrupt event from EXTI line x
|
||||
\param[in] linex: EXTI line number, refer to exti_line_enum
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg EXTI_x (x=0..17,19,21): EXTI line x
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void exti_software_interrupt_enable(exti_line_enum linex)
|
||||
{
|
||||
EXTI_SWIEV |= (uint32_t)linex;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable the software interrupt event from EXTI line x
|
||||
\param[in] linex: EXTI line number, refer to exti_line_enum
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg EXTI_x (x=0..17,19,21): EXTI line x
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void exti_software_interrupt_disable(exti_line_enum linex)
|
||||
{
|
||||
EXTI_SWIEV &= ~(uint32_t)linex;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get EXTI line x interrupt pending flag
|
||||
\param[in] linex: EXTI line number, refer to exti_line_enum
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg EXTI_x (x=0..17,19,21): EXTI line x
|
||||
\param[out] none
|
||||
\retval FlagStatus: status of flag (RESET or SET)
|
||||
*/
|
||||
FlagStatus exti_flag_get(exti_line_enum linex)
|
||||
{
|
||||
if(RESET != (EXTI_PD & (uint32_t)linex)) {
|
||||
return SET;
|
||||
} else {
|
||||
return RESET;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief clear EXTI line x interrupt pending flag
|
||||
\param[in] linex: EXTI line number, refer to exti_line_enum
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg EXTI_x (x=0..17,19,21): EXTI line x
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void exti_flag_clear(exti_line_enum linex)
|
||||
{
|
||||
EXTI_PD = (uint32_t)linex;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get EXTI line x interrupt pending flag
|
||||
\param[in] linex: EXTI line number, refer to exti_line_enum
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg EXTI_x (x=0..17,19,21): EXTI line x
|
||||
\param[out] none
|
||||
\retval FlagStatus: status of flag (RESET or SET)
|
||||
*/
|
||||
FlagStatus exti_interrupt_flag_get(exti_line_enum linex)
|
||||
{
|
||||
if(RESET != (EXTI_PD & (uint32_t)linex)) {
|
||||
return SET;
|
||||
} else {
|
||||
return RESET;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief clear EXTI line x interrupt pending flag
|
||||
\param[in] linex: EXTI line number, refer to exti_line_enum
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg EXTI_x (x=0..17,19,21): EXTI line x
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void exti_interrupt_flag_clear(exti_line_enum linex)
|
||||
{
|
||||
EXTI_PD = (uint32_t)linex;
|
||||
}
|
825
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_fmc.c
Normal file
825
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_fmc.c
Normal file
@@ -0,0 +1,825 @@
|
||||
/*!
|
||||
\file gd32e23x_fmc.c
|
||||
\brief FMC driver
|
||||
|
||||
\version 2024-02-22, V2.1.0, firmware for GD32E23x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2024, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "gd32e23x_fmc.h"
|
||||
|
||||
/* FMC register bit offset */
|
||||
#define OB_HIGH_WP_OFFSET ((uint32_t)8U)
|
||||
#define FMC_OBSTAT_USER_OFFSET ((uint32_t)8U)
|
||||
#define FMC_OBSTAT_DATA_OFFSET ((uint32_t)16U)
|
||||
|
||||
/*!
|
||||
\brief unlock the main FMC operation
|
||||
it is better to used in pairs with fmc_lock
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void fmc_unlock(void)
|
||||
{
|
||||
if((RESET != (FMC_CTL & FMC_CTL_LK))){
|
||||
/* write the FMC key */
|
||||
FMC_KEY = UNLOCK_KEY0;
|
||||
FMC_KEY = UNLOCK_KEY1;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief lock the main FMC operation
|
||||
it is better to used in pairs with fmc_unlock after an operation
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void fmc_lock(void)
|
||||
{
|
||||
/* set the LK bit*/
|
||||
FMC_CTL |= FMC_CTL_LK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set the wait state counter value
|
||||
\param[in] wscnt: wait state counter value
|
||||
\arg WS_WSCNT_0: 0 wait state added
|
||||
\arg WS_WSCNT_1: 1 wait state added
|
||||
\arg WS_WSCNT_2: 2 wait state added
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void fmc_wscnt_set(uint8_t wscnt)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
reg = FMC_WS;
|
||||
/* set the wait state counter value */
|
||||
reg &= ~FMC_WS_WSCNT;
|
||||
FMC_WS = (reg | wscnt);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief pre-fetch enable
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void fmc_prefetch_enable(void)
|
||||
{
|
||||
FMC_WS |= FMC_WS_PFEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief pre-fetch disable
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void fmc_prefetch_disable(void)
|
||||
{
|
||||
FMC_WS &= ~FMC_WS_PFEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief erase page
|
||||
\param[in] page_address: target page start address
|
||||
\param[out] none
|
||||
\retval fmc_state: state of FMC
|
||||
\arg FMC_READY: the operation has been completed
|
||||
\arg FMC_BUSY: the operation is in progress
|
||||
\arg FMC_PGERR: program error
|
||||
\arg FMC_PGAERR: program alignment error
|
||||
\arg FMC_WPERR: erase/program protection error
|
||||
\arg FMC_TOERR: timeout error
|
||||
\arg FMC_OB_HSPC: option byte security protection code high
|
||||
*/
|
||||
fmc_state_enum fmc_page_erase(uint32_t page_address)
|
||||
{
|
||||
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
||||
|
||||
if(FMC_READY == fmc_state){
|
||||
/* start page erase */
|
||||
FMC_CTL |= FMC_CTL_PER;
|
||||
FMC_ADDR = page_address;
|
||||
FMC_CTL |= FMC_CTL_START;
|
||||
|
||||
/* wait for the FMC ready */
|
||||
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
||||
|
||||
/* reset the PER bit */
|
||||
FMC_CTL &= ~FMC_CTL_PER;
|
||||
}
|
||||
|
||||
/* return the FMC state */
|
||||
return fmc_state;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief erase whole chip
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval fmc_state: state of FMC
|
||||
\arg FMC_READY: the operation has been completed
|
||||
\arg FMC_BUSY: the operation is in progress
|
||||
\arg FMC_PGERR: program error
|
||||
\arg FMC_PGAERR: program alignment error
|
||||
\arg FMC_WPERR: erase/program protection error
|
||||
\arg FMC_TOERR: timeout error
|
||||
\arg FMC_OB_HSPC: option byte security protection code high
|
||||
*/
|
||||
fmc_state_enum fmc_mass_erase(void)
|
||||
{
|
||||
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
||||
|
||||
if(FMC_READY == fmc_state){
|
||||
/* start chip erase */
|
||||
FMC_CTL |= FMC_CTL_MER;
|
||||
FMC_CTL |= FMC_CTL_START;
|
||||
|
||||
/* wait for the FMC ready */
|
||||
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
||||
|
||||
/* reset the MER bit */
|
||||
FMC_CTL &= ~FMC_CTL_MER;
|
||||
}
|
||||
|
||||
/* return the fmc state */
|
||||
return fmc_state;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief program a double word at the corresponding address in main flash, this
|
||||
function also applies to OTP(address 0x1FFF_7000~0x1FFF_73FF) programming
|
||||
\param[in] address: address to program
|
||||
\param[in] data: double word to program
|
||||
\param[out] none
|
||||
\retval fmc_state: state of FMC
|
||||
\arg FMC_READY: the operation has been completed
|
||||
\arg FMC_BUSY: the operation is in progress
|
||||
\arg FMC_PGERR: program error
|
||||
\arg FMC_PGAERR: program alignment error
|
||||
\arg FMC_WPERR: erase/program protection error
|
||||
\arg FMC_TOERR: timeout error
|
||||
\arg FMC_OB_HSPC: option byte security protection code high
|
||||
*/
|
||||
fmc_state_enum fmc_doubleword_program(uint32_t address, uint64_t data)
|
||||
{
|
||||
uint32_t data0, data1;
|
||||
|
||||
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
||||
|
||||
data0 = (uint32_t)(data & 0xFFFFFFFFU);
|
||||
data1 = (uint32_t)((data>>32U) & 0xFFFFFFFFU);
|
||||
|
||||
/* configure program width */
|
||||
FMC_WS |= FMC_WS_PGW;
|
||||
if(FMC_READY == fmc_state){
|
||||
/* set the PG bit to start program */
|
||||
FMC_CTL |= FMC_CTL_PG;
|
||||
REG32(address) = data0;
|
||||
REG32(address+4U) = data1;
|
||||
/* wait for the FMC ready */
|
||||
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
||||
|
||||
/* reset the PG bit */
|
||||
FMC_CTL &= ~FMC_CTL_PG;
|
||||
}
|
||||
FMC_WS &= ~(FMC_WS_PGW);
|
||||
|
||||
/* return the FMC state */
|
||||
return fmc_state;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief program a word at the corresponding address in main flash, this function
|
||||
also applies to OTP(address 0x1FFF_7000~0x1FFF_73FF) programming
|
||||
\param[in] address: address to program
|
||||
\param[in] data: word to program
|
||||
\param[out] none
|
||||
\retval fmc_state: state of FMC
|
||||
\arg FMC_READY: the operation has been completed
|
||||
\arg FMC_BUSY: the operation is in progress
|
||||
\arg FMC_PGERR: program error
|
||||
\arg FMC_PGAERR: program alignment error
|
||||
\arg FMC_WPERR: erase/program protection error
|
||||
\arg FMC_TOERR: timeout error
|
||||
\arg FMC_OB_HSPC: option byte security protection code high
|
||||
*/
|
||||
fmc_state_enum fmc_word_program(uint32_t address, uint32_t data)
|
||||
{
|
||||
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
||||
|
||||
if(FMC_READY == fmc_state){
|
||||
/* set the PG bit to start program */
|
||||
FMC_CTL |= FMC_CTL_PG;
|
||||
|
||||
REG32(address) = data;
|
||||
/* wait for the FMC ready */
|
||||
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
||||
|
||||
/* reset the PG bit */
|
||||
FMC_CTL &= ~FMC_CTL_PG;
|
||||
}
|
||||
|
||||
/* return the FMC state */
|
||||
return fmc_state;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief unlock the option byte operation
|
||||
it is better to used in pairs with ob_lock
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void ob_unlock(void)
|
||||
{
|
||||
if(RESET == (FMC_CTL & FMC_CTL_OBWEN)){
|
||||
/* write the FMC key */
|
||||
FMC_OBKEY = UNLOCK_KEY0;
|
||||
FMC_OBKEY = UNLOCK_KEY1;
|
||||
}
|
||||
/* wait until OBWEN bit is set by hardware */
|
||||
while(RESET == (FMC_CTL & FMC_CTL_OBWEN)){
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief lock the option byte operation
|
||||
it is better to used in pairs with ob_unlock after an operation
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void ob_lock(void)
|
||||
{
|
||||
/* reset the OBWE bit */
|
||||
FMC_CTL &= ~FMC_CTL_OBWEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief reload the option byte and generate a system reset
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void ob_reset(void)
|
||||
{
|
||||
/* set the OBRLD bit */
|
||||
FMC_CTL |= FMC_CTL_OBRLD;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get option byte value
|
||||
\param[in] addr: address of option byte
|
||||
\arg OB_SPC_USER_ADDRESS: address of option byte security protection and user
|
||||
\arg OB_DATA_ADDRESS: address of option byte data
|
||||
\arg OB_WP_ADDRESS: address of option byte write protection
|
||||
\param[out] option byte value
|
||||
*/
|
||||
uint32_t option_byte_value_get(uint32_t addr)
|
||||
{
|
||||
return *(volatile uint32_t *)(addr);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief erase the option byte
|
||||
programmer must ensure FMC & option byte are both unlocked before calling this function
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval fmc_state: state of FMC
|
||||
\arg FMC_READY: the operation has been completed
|
||||
\arg FMC_BUSY: the operation is in progress
|
||||
\arg FMC_PGERR: program error
|
||||
\arg FMC_PGAERR: program alignment error
|
||||
\arg FMC_WPERR: erase/program protection error
|
||||
\arg FMC_TOERR: timeout error
|
||||
\arg FMC_OB_HSPC: option byte security protection code high
|
||||
*/
|
||||
fmc_state_enum ob_erase(void)
|
||||
{
|
||||
uint16_t fmc_spc;
|
||||
uint32_t val;
|
||||
uint32_t fmc_plevel = ob_obstat_plevel_get();
|
||||
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
||||
|
||||
/* get the original option byte security protection code */
|
||||
if(OB_OBSTAT_PLEVEL_NO == fmc_plevel){
|
||||
fmc_spc = FMC_NSPC;
|
||||
}else if(OB_OBSTAT_PLEVEL_LOW == fmc_plevel){
|
||||
fmc_spc = FMC_LSPC;
|
||||
}else{
|
||||
fmc_spc = FMC_HSPC;
|
||||
fmc_state = FMC_OB_HSPC;
|
||||
}
|
||||
val = HIGH_16BITS_MASK | (uint32_t)fmc_spc;
|
||||
|
||||
if(FMC_READY == fmc_state){
|
||||
/* start erase the option byte */
|
||||
FMC_CTL |= FMC_CTL_OBER;
|
||||
FMC_CTL |= FMC_CTL_START;
|
||||
|
||||
/* wait for the FMC ready */
|
||||
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
||||
|
||||
if(FMC_READY == fmc_state){
|
||||
/* reset the OBER bit */
|
||||
FMC_CTL &= ~FMC_CTL_OBER;
|
||||
|
||||
/* set the OBPG bit */
|
||||
FMC_CTL |= FMC_CTL_OBPG;
|
||||
|
||||
/* restore the last get option byte security protection code */
|
||||
OB_SPC_USER = val;
|
||||
|
||||
/* wait for the FMC ready */
|
||||
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
||||
|
||||
if(FMC_TOERR != fmc_state){
|
||||
/* reset the OBPG bit */
|
||||
FMC_CTL &= ~FMC_CTL_OBPG;
|
||||
}
|
||||
}else{
|
||||
if(FMC_TOERR != fmc_state){
|
||||
/* reset the OBER bit */
|
||||
FMC_CTL &= ~FMC_CTL_OBER;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* return the FMC state */
|
||||
return fmc_state;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable option byte write protection (OB_WP)
|
||||
\param[in] ob_wp: write protection configuration data. Notice that set the
|
||||
bit to 1 if you want to protect the corresponding pages.
|
||||
\param[out] none
|
||||
\retval fmc_state: state of FMC
|
||||
\arg FMC_READY: the operation has been completed
|
||||
\arg FMC_BUSY: the operation is in progress
|
||||
\arg FMC_PGERR: program error
|
||||
\arg FMC_PGAERR: program alignment error
|
||||
\arg FMC_WPERR: erase/program protection error
|
||||
\arg FMC_TOERR: timeout error
|
||||
\arg FMC_OB_HSPC: option byte security protection code high
|
||||
*/
|
||||
fmc_state_enum ob_write_protection_enable(uint32_t ob_wp)
|
||||
{
|
||||
uint32_t ob_wrp_val = 0U;
|
||||
|
||||
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
||||
|
||||
ob_wp = ~ob_wp;
|
||||
ob_wrp_val |= (uint32_t)ob_wp&0x00FFU;
|
||||
ob_wrp_val |= (((uint32_t)ob_wp&0xFF00U)>>8U) << 16U;
|
||||
|
||||
if(FMC_READY == fmc_state){
|
||||
/* set the OBPG bit*/
|
||||
FMC_CTL |= FMC_CTL_OBPG;
|
||||
|
||||
if(0xFFFFFFFFU != ob_wrp_val){
|
||||
OB_WP = ob_wrp_val;
|
||||
|
||||
/* wait for the FMC ready */
|
||||
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
||||
}
|
||||
|
||||
ob_wrp_val |= (uint32_t)(ob_wp>>16)&0x00FFU;
|
||||
ob_wrp_val |= (((uint32_t)(ob_wp>>16)&0xFF00U)>>8U) << 16U;
|
||||
if(0xFFFFFFFFU != ob_wrp_val){
|
||||
REG32((OB) + 0x0CU) = ob_wrp_val;
|
||||
|
||||
/* wait for the FMC ready */
|
||||
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
||||
}
|
||||
|
||||
if(FMC_TOERR != fmc_state){
|
||||
/* reset the OBPG bit */
|
||||
FMC_CTL &= ~FMC_CTL_OBPG;
|
||||
}
|
||||
}
|
||||
/* return the FMC state */
|
||||
return fmc_state;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure security protection
|
||||
\param[in] ob_spc: specify security protection code
|
||||
\arg FMC_NSPC: no security protection
|
||||
\arg FMC_LSPC: low security protection
|
||||
\arg FMC_HSPC: high security protection
|
||||
\param[out] none
|
||||
\retval fmc_state: state of FMC
|
||||
\arg FMC_READY: the operation has been completed
|
||||
\arg FMC_BUSY: the operation is in progress
|
||||
\arg FMC_PGERR: program error
|
||||
\arg FMC_PGAERR: program alignment error
|
||||
\arg FMC_WPERR: erase/program protection error
|
||||
\arg FMC_TOERR: timeout error
|
||||
\arg FMC_OB_HSPC: option byte security protection code high
|
||||
*/
|
||||
fmc_state_enum ob_security_protection_config(uint16_t ob_spc)
|
||||
{
|
||||
uint32_t val;
|
||||
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
||||
|
||||
val = option_byte_value_get(OB_SPC_USER_ADDRESS);
|
||||
/* the OB_SPC byte cannot be reprogrammed if protection level is high */
|
||||
if(OB_OBSTAT_PLEVEL_HIGH == ob_obstat_plevel_get()){
|
||||
fmc_state = FMC_OB_HSPC;
|
||||
}
|
||||
|
||||
val &= ~LOW_16BITS_MASK;
|
||||
val |= (uint32_t)ob_spc;
|
||||
|
||||
if(FMC_READY == fmc_state){
|
||||
/* start erase the option byte */
|
||||
FMC_CTL |= FMC_CTL_OBER;
|
||||
FMC_CTL |= FMC_CTL_START;
|
||||
|
||||
/* wait for the FMC ready */
|
||||
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
||||
|
||||
if(FMC_READY == fmc_state){
|
||||
|
||||
/* reset the OBER bit */
|
||||
FMC_CTL &= ~FMC_CTL_OBER;
|
||||
|
||||
/* enable the option bytes programming */
|
||||
FMC_CTL |= FMC_CTL_OBPG;
|
||||
|
||||
OB_SPC_USER = val;
|
||||
|
||||
/* wait for the FMC ready */
|
||||
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
||||
|
||||
if(FMC_TOERR != fmc_state){
|
||||
/* reset the OBPG bit */
|
||||
FMC_CTL &= ~FMC_CTL_OBPG;
|
||||
}
|
||||
}else{
|
||||
if(FMC_TOERR != fmc_state){
|
||||
/* reset the OBER bit */
|
||||
FMC_CTL &= ~FMC_CTL_OBER;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* return the FMC state */
|
||||
return fmc_state;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief program the FMC user option byte
|
||||
this function can only clear the corresponding bits to be 0 rather than 1.
|
||||
the function ob_erase is used to set all the bits to be 1.
|
||||
\param[in] ob_user: user option byte
|
||||
one or more parameters (bitwise AND) can be selected which are shown as below:
|
||||
\arg OB_FWDGT_HW: hardware free watchdog timer
|
||||
\arg OB_DEEPSLEEP_RST: no reset when entering deepsleep mode
|
||||
\arg OB_STDBY_RST: no reset when entering standby mode
|
||||
\arg OB_BOOT1_SET_1: BOOT1 bit is 1
|
||||
\arg OB_VDDA_DISABLE: disable VDDA monitor
|
||||
\arg OB_SRAM_PARITY_ENABLE: enable sram parity check
|
||||
\param[out] none
|
||||
\retval fmc_state: state of FMC
|
||||
\arg FMC_READY: the operation has been completed
|
||||
\arg FMC_BUSY: the operation is in progress
|
||||
\arg FMC_PGERR: program error
|
||||
\arg FMC_PGAERR: program alignment error
|
||||
\arg FMC_WPERR: erase/program protection error
|
||||
\arg FMC_TOERR: timeout error
|
||||
\arg FMC_OB_HSPC: option byte security protection code high
|
||||
*/
|
||||
fmc_state_enum ob_user_write(uint8_t ob_user)
|
||||
{
|
||||
uint32_t val_spc_user;
|
||||
/* check whether FMC is ready or not */
|
||||
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
||||
|
||||
val_spc_user = option_byte_value_get(OB_SPC_USER_ADDRESS);
|
||||
|
||||
val_spc_user &= ~HIGH_16BITS_MASK;
|
||||
|
||||
val_spc_user |= ((uint32_t)ob_user<<16U);
|
||||
|
||||
if(FMC_READY == fmc_state){
|
||||
/* start erase the option byte */
|
||||
FMC_CTL |= FMC_CTL_OBER;
|
||||
FMC_CTL |= FMC_CTL_START;
|
||||
|
||||
/* wait for the FMC ready */
|
||||
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
||||
|
||||
if(FMC_READY == fmc_state){
|
||||
|
||||
/* reset the OBER bit */
|
||||
FMC_CTL &= ~FMC_CTL_OBER;
|
||||
|
||||
/* enable the option bytes programming */
|
||||
FMC_CTL |= FMC_CTL_OBPG;
|
||||
|
||||
OB_SPC_USER = val_spc_user;
|
||||
|
||||
/* wait for the FMC ready */
|
||||
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
||||
|
||||
if(FMC_TOERR != fmc_state){
|
||||
/* reset the OBPG bit */
|
||||
FMC_CTL &= ~FMC_CTL_OBPG;
|
||||
}
|
||||
}else{
|
||||
if(FMC_TOERR != fmc_state){
|
||||
/* reset the OBER bit */
|
||||
FMC_CTL &= ~FMC_CTL_OBER;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* return the FMC state */
|
||||
return fmc_state;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief program the FMC data option byte
|
||||
\param[in] data: the data to be programmed, OB_DATA[0:15]
|
||||
\param[out] none
|
||||
\retval fmc_state: state of FMC
|
||||
\arg FMC_READY: the operation has been completed
|
||||
\arg FMC_BUSY: the operation is in progress
|
||||
\arg FMC_PGERR: program error
|
||||
\arg FMC_PGAERR: program alignment error
|
||||
\arg FMC_WPERR: erase/program protection error
|
||||
\arg FMC_TOERR: timeout error
|
||||
\arg FMC_OB_HSPC: option byte security protection code high
|
||||
*/
|
||||
fmc_state_enum ob_data_program(uint16_t data)
|
||||
{
|
||||
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
||||
uint32_t val = 0U;
|
||||
|
||||
val |= (uint32_t)data&0x00FFU;
|
||||
val |= (((uint32_t)data&0xFF00U)>>8U) << 16U;
|
||||
|
||||
if(FMC_READY == fmc_state){
|
||||
/* set the OBPG bit */
|
||||
FMC_CTL |= FMC_CTL_OBPG;
|
||||
OB_DATA = val;
|
||||
|
||||
/* wait for the FMC ready */
|
||||
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
||||
|
||||
if(FMC_TOERR != fmc_state){
|
||||
/* reset the OBPG bit */
|
||||
FMC_CTL &= ~FMC_CTL_OBPG;
|
||||
}
|
||||
}
|
||||
/* return the FMC state */
|
||||
return fmc_state;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get OB_USER in register FMC_OBSTAT
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval ob_user
|
||||
*/
|
||||
uint8_t ob_user_get(void)
|
||||
{
|
||||
return (uint8_t)(FMC_OBSTAT >> FMC_OBSTAT_USER_OFFSET);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get OB_DATA in register FMC_OBSTAT
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval ob_data
|
||||
*/
|
||||
uint16_t ob_data_get(void)
|
||||
{
|
||||
return (uint16_t)(FMC_OBSTAT >> FMC_OBSTAT_DATA_OFFSET);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get the FMC option byte write protection (OB_WP) in register FMC_WP
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval OB_WP
|
||||
*/
|
||||
uint32_t ob_write_protection_get(void)
|
||||
{
|
||||
return (uint32_t)(FMC_WP);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get the value of FMC option byte security protection level (PLEVEL) in FMC_OBSTAT register
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval the value of PLEVEL
|
||||
\arg OB_OBSTAT_PLEVEL_NO: no security protection
|
||||
\arg OB_OBSTAT_PLEVEL_LOW: low security protection
|
||||
\arg OB_OBSTAT_PLEVEL_HIGH: high security protection
|
||||
*/
|
||||
uint32_t ob_obstat_plevel_get(void)
|
||||
{
|
||||
return (FMC_OBSTAT & (FMC_OBSTAT_PLEVEL_BIT0 | FMC_OBSTAT_PLEVEL_BIT1));
|
||||
}
|
||||
|
||||
/* FMC interrupts and flags management functions */
|
||||
/*!
|
||||
\brief enable FMC interrupt
|
||||
\param[in] interrupt: the FMC interrupt source
|
||||
\arg FMC_INTEN_END: FMC end of operation interrupt
|
||||
\arg FMC_INTEN_ERR: FMC error interrupt
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void fmc_interrupt_enable(uint32_t interrupt)
|
||||
{
|
||||
FMC_CTL |= interrupt;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable FMC interrupt
|
||||
\param[in] interrupt: the FMC interrupt source
|
||||
\arg FMC_INTEN_END: FMC end of operation interrupt
|
||||
\arg FMC_INTEN_ERR: FMC error interrupt
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void fmc_interrupt_disable(uint32_t interrupt)
|
||||
{
|
||||
FMC_CTL &= ~(uint32_t)interrupt;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get flag set or reset
|
||||
\param[in] flag: check FMC flag
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg FMC_FLAG_BUSY: FMC busy flag
|
||||
\arg FMC_FLAG_PGERR: FMC programming error flag
|
||||
\arg FMC_FLAG_PGAERR: FMC program alignment error flag
|
||||
\arg FMC_FLAG_WPERR: FMC write protection error flag
|
||||
\arg FMC_FLAG_END: FMC end of programming flag
|
||||
\param[out] none
|
||||
\retval FlagStatus: SET or RESET
|
||||
*/
|
||||
FlagStatus fmc_flag_get(uint32_t flag)
|
||||
{
|
||||
FlagStatus status = RESET;
|
||||
|
||||
if(FMC_STAT & flag){
|
||||
status = SET;
|
||||
}
|
||||
/* return the state of corresponding FMC flag */
|
||||
return status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief clear the FMC pending flag by writing 1
|
||||
\param[in] flag: clear FMC flag
|
||||
one or more parameters can be selected which is shown as below:
|
||||
\arg FMC_FLAG_PGERR: FMC programming error flag
|
||||
\arg FMC_FLAG_PGAERR: FMC program alignment error flag
|
||||
\arg FMC_FLAG_WPERR: FMC write protection error flag
|
||||
\arg FMC_FLAG_END: FMC end of programming flag
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void fmc_flag_clear(uint32_t flag)
|
||||
{
|
||||
/* clear the flags */
|
||||
FMC_STAT = flag;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get intrrupt flag set or reset
|
||||
\param[in] flag: check FMC flag
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg FMC_INT_FLAG_PGERR: FMC programming error flag
|
||||
\arg FMC_INT_FLAG_PGAERR: FMC program alignment error flag
|
||||
\arg FMC_INT_FLAG_WPERR: FMC write protection error flag
|
||||
\arg FMC_INT_FLAG_END: FMC end of programming flag
|
||||
\param[out] none
|
||||
\retval FlagStatus: SET or RESET
|
||||
*/
|
||||
FlagStatus fmc_interrupt_flag_get(uint32_t int_flag)
|
||||
{
|
||||
uint32_t intenable = 0U, flagstatus = 0U;
|
||||
|
||||
if(FMC_INT_FLAG_END == int_flag){
|
||||
/* get the interrupt enable bit status */
|
||||
intenable = FMC_CTL & FMC_INTEN_END;
|
||||
/* get the corresponding flag bit status */
|
||||
flagstatus = FMC_STAT & int_flag;
|
||||
if(intenable && flagstatus){
|
||||
return SET;
|
||||
}else{
|
||||
return RESET;
|
||||
}
|
||||
}else{
|
||||
/* get the interrupt enable bit status */
|
||||
intenable = FMC_CTL & FMC_INTEN_ERR;
|
||||
/* get the corresponding flag bit status */
|
||||
flagstatus = FMC_STAT & int_flag;
|
||||
if(intenable && flagstatus){
|
||||
return SET;
|
||||
}else{
|
||||
return RESET;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief clear the FMC interrupt pending flag by writing 1
|
||||
\param[in] flag: clear FMC flag
|
||||
one or more parameters can be selected which is shown as below:
|
||||
\arg FMC_INT_FLAG_PGERR: FMC programming error flag
|
||||
\arg FMC_INT_FLAG_PGAERR: FMC program alignment error flag
|
||||
\arg FMC_INT_FLAG_WPERR: FMC write protection error flag
|
||||
\arg FMC_INT_FLAG_END: FMC end of programming flag
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void fmc_interrupt_flag_clear(uint32_t int_flag)
|
||||
{
|
||||
/* clear the flags */
|
||||
FMC_STAT = int_flag;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get the FMC state
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval fmc_state
|
||||
*/
|
||||
fmc_state_enum fmc_state_get(void)
|
||||
{
|
||||
fmc_state_enum fmc_state = FMC_READY;
|
||||
|
||||
if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_BUSY)){
|
||||
fmc_state = FMC_BUSY;
|
||||
}else{
|
||||
if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_WPERR)){
|
||||
fmc_state = FMC_WPERR;
|
||||
}else{
|
||||
if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_PGERR)){
|
||||
fmc_state = FMC_PGERR;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* return the FMC state */
|
||||
return fmc_state;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief check whether FMC is ready or not
|
||||
\param[in] timeout: timeout count
|
||||
\param[out] none
|
||||
\retval fmc_state
|
||||
*/
|
||||
fmc_state_enum fmc_ready_wait(uint32_t timeout)
|
||||
{
|
||||
fmc_state_enum fmc_state = FMC_BUSY;
|
||||
|
||||
/* wait for FMC ready */
|
||||
do{
|
||||
/* get FMC state */
|
||||
fmc_state = fmc_state_get();
|
||||
timeout--;
|
||||
}while((FMC_BUSY == fmc_state) && (0U != timeout));
|
||||
|
||||
if(FMC_BUSY == fmc_state){
|
||||
fmc_state = FMC_TOERR;
|
||||
}
|
||||
/* return the FMC state */
|
||||
return fmc_state;
|
||||
}
|
245
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_fwdgt.c
Normal file
245
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_fwdgt.c
Normal file
@@ -0,0 +1,245 @@
|
||||
/*!
|
||||
\file gd32e23x_fwdgt.c
|
||||
\brief FWDGT driver
|
||||
|
||||
\version 2024-02-22, V2.1.0, firmware for GD32E23x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2024, GigaDevice Semiconductor Inc.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "gd32e23x_fwdgt.h"
|
||||
|
||||
/*!
|
||||
\brief enable write access to FWDGT_PSC and FWDGT_RLD and FWDGT_WND
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void fwdgt_write_enable(void)
|
||||
{
|
||||
FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable write access to FWDGT_PSC,FWDGT_RLD and FWDGT_WND
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void fwdgt_write_disable(void)
|
||||
{
|
||||
FWDGT_CTL = FWDGT_WRITEACCESS_DISABLE;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief start the free watchdog timer counter
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void fwdgt_enable(void)
|
||||
{
|
||||
FWDGT_CTL = FWDGT_KEY_ENABLE;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure the free watchdog timer counter prescaler value
|
||||
\param[in] prescaler_value: specify prescaler value
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg FWDGT_PSC_DIV4: FWDGT prescaler set to 4
|
||||
\arg FWDGT_PSC_DIV8: FWDGT prescaler set to 8
|
||||
\arg FWDGT_PSC_DIV16: FWDGT prescaler set to 16
|
||||
\arg FWDGT_PSC_DIV32: FWDGT prescaler set to 32
|
||||
\arg FWDGT_PSC_DIV64: FWDGT prescaler set to 64
|
||||
\arg FWDGT_PSC_DIV128: FWDGT prescaler set to 128
|
||||
\arg FWDGT_PSC_DIV256: FWDGT prescaler set to 256
|
||||
\param[out] none
|
||||
\retval ErrStatus: ERROR or SUCCESS
|
||||
*/
|
||||
ErrStatus fwdgt_prescaler_value_config(uint16_t prescaler_value)
|
||||
{
|
||||
uint32_t timeout = FWDGT_PSC_TIMEOUT;
|
||||
uint32_t flag_status = RESET;
|
||||
|
||||
/* enable write access to FWDGT_PSC */
|
||||
FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
|
||||
|
||||
/* wait until the PUD flag to be reset */
|
||||
do{
|
||||
flag_status = FWDGT_STAT & FWDGT_STAT_PUD;
|
||||
}while((--timeout > 0U) && ((uint32_t)RESET != flag_status));
|
||||
|
||||
if ((uint32_t)RESET != flag_status){
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/* configure FWDGT */
|
||||
FWDGT_PSC = (uint32_t)prescaler_value;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure the free watchdog timer counter reload value
|
||||
\param[in] reload_value: specify reload value(0x0000 - 0x0FFF)
|
||||
\param[out] none
|
||||
\retval ErrStatus: ERROR or SUCCESS
|
||||
*/
|
||||
ErrStatus fwdgt_reload_value_config(uint16_t reload_value)
|
||||
{
|
||||
uint32_t timeout = FWDGT_RLD_TIMEOUT;
|
||||
uint32_t flag_status = RESET;
|
||||
|
||||
/* enable write access to FWDGT_RLD */
|
||||
FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
|
||||
|
||||
/* wait until the RUD flag to be reset */
|
||||
do{
|
||||
flag_status = FWDGT_STAT & FWDGT_STAT_RUD;
|
||||
}while((--timeout > 0U) && ((uint32_t)RESET != flag_status));
|
||||
|
||||
if ((uint32_t)RESET != flag_status){
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
FWDGT_RLD = RLD_RLD(reload_value);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure the free watchdog timer counter window value
|
||||
\param[in] window_value: specify window value(0x0000 - 0x0FFF)
|
||||
\param[out] none
|
||||
\retval ErrStatus: ERROR or SUCCESS
|
||||
*/
|
||||
ErrStatus fwdgt_window_value_config(uint16_t window_value)
|
||||
{
|
||||
uint32_t time_index = FWDGT_WND_TIMEOUT;
|
||||
uint32_t flag_status = RESET;
|
||||
|
||||
/* enable write access to FWDGT_WND */
|
||||
FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
|
||||
|
||||
/* wait until the WUD flag to be reset */
|
||||
do{
|
||||
flag_status = FWDGT_STAT & FWDGT_STAT_WUD;
|
||||
}while((--time_index > 0U) && ((uint32_t)RESET != flag_status));
|
||||
|
||||
if ((uint32_t)RESET != flag_status){
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
FWDGT_WND = WND_WND(window_value);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief reload the counter of FWDGT
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void fwdgt_counter_reload(void)
|
||||
{
|
||||
FWDGT_CTL = FWDGT_KEY_RELOAD;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure counter reload value, and prescaler divider value
|
||||
\param[in] reload_value: specify reload value(0x0000 - 0x0FFF)
|
||||
\param[in] prescaler_div: FWDGT prescaler value
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg FWDGT_PSC_DIV4: FWDGT prescaler set to 4
|
||||
\arg FWDGT_PSC_DIV8: FWDGT prescaler set to 8
|
||||
\arg FWDGT_PSC_DIV16: FWDGT prescaler set to 16
|
||||
\arg FWDGT_PSC_DIV32: FWDGT prescaler set to 32
|
||||
\arg FWDGT_PSC_DIV64: FWDGT prescaler set to 64
|
||||
\arg FWDGT_PSC_DIV128: FWDGT prescaler set to 128
|
||||
\arg FWDGT_PSC_DIV256: FWDGT prescaler set to 256
|
||||
\param[out] none
|
||||
\retval ErrStatus: ERROR or SUCCESS
|
||||
*/
|
||||
ErrStatus fwdgt_config(uint16_t reload_value, uint8_t prescaler_div)
|
||||
{
|
||||
uint32_t timeout = FWDGT_PSC_TIMEOUT;
|
||||
uint32_t flag_status = RESET;
|
||||
|
||||
/* enable write access to FWDGT_PSC,and FWDGT_RLD */
|
||||
FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
|
||||
|
||||
/* wait until the PUD flag to be reset */
|
||||
do{
|
||||
flag_status = FWDGT_STAT & FWDGT_STAT_PUD;
|
||||
}while((--timeout > 0U) && ((uint32_t)RESET != flag_status));
|
||||
|
||||
if ((uint32_t)RESET != flag_status){
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/* configure FWDGT */
|
||||
FWDGT_PSC = (uint32_t)prescaler_div;
|
||||
|
||||
timeout = FWDGT_RLD_TIMEOUT;
|
||||
/* wait until the RUD flag to be reset */
|
||||
do{
|
||||
flag_status = FWDGT_STAT & FWDGT_STAT_RUD;
|
||||
}while((--timeout > 0U) && ((uint32_t)RESET != flag_status));
|
||||
|
||||
if ((uint32_t)RESET != flag_status){
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
FWDGT_RLD = RLD_RLD(reload_value);
|
||||
|
||||
/* reload the counter */
|
||||
FWDGT_CTL = FWDGT_KEY_RELOAD;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get flag state of FWDGT
|
||||
\param[in] flag: flag to get
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg FWDGT_FLAG_PUD: a write operation to FWDGT_PSC register is on going
|
||||
\arg FWDGT_FLAG_RUD: a write operation to FWDGT_RLD register is on going
|
||||
\arg FWDGT_FLAG_WUD: a write operation to FWDGT_WND register is on going
|
||||
\param[out] none
|
||||
\retval FlagStatus: SET or RESET
|
||||
*/
|
||||
FlagStatus fwdgt_flag_get(uint16_t flag)
|
||||
{
|
||||
if(RESET != (FWDGT_STAT & flag)){
|
||||
return SET;
|
||||
}
|
||||
return RESET;
|
||||
}
|
399
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_gpio.c
Normal file
399
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_gpio.c
Normal file
@@ -0,0 +1,399 @@
|
||||
/*!
|
||||
\file gd32e23x_gpio.c
|
||||
\brief GPIO driver
|
||||
|
||||
\version 2024-02-22, V2.1.0, firmware for GD32E23x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2024, GigaDevice Semiconductor Inc.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "gd32e23x_gpio.h"
|
||||
|
||||
/*!
|
||||
\brief reset GPIO port
|
||||
\param[in] gpio_periph: GPIOx(x = A,B,C,F)
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg GPIOx(x = A,B,C,F)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void gpio_deinit(uint32_t gpio_periph)
|
||||
{
|
||||
switch(gpio_periph){
|
||||
case GPIOA:
|
||||
/* reset GPIOA */
|
||||
rcu_periph_reset_enable(RCU_GPIOARST);
|
||||
rcu_periph_reset_disable(RCU_GPIOARST);
|
||||
break;
|
||||
case GPIOB:
|
||||
/* reset GPIOB */
|
||||
rcu_periph_reset_enable(RCU_GPIOBRST);
|
||||
rcu_periph_reset_disable(RCU_GPIOBRST);
|
||||
break;
|
||||
case GPIOC:
|
||||
/* reset GPIOC */
|
||||
rcu_periph_reset_enable(RCU_GPIOCRST);
|
||||
rcu_periph_reset_disable(RCU_GPIOCRST);
|
||||
break;
|
||||
case GPIOF:
|
||||
/* reset GPIOF */
|
||||
rcu_periph_reset_enable(RCU_GPIOFRST);
|
||||
rcu_periph_reset_disable(RCU_GPIOFRST);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set GPIO mode
|
||||
\param[in] gpio_periph: GPIOx(x = A,B,C,F)
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg GPIOx(x = A,B,C,F)
|
||||
\param[in] mode: gpio pin mode
|
||||
\arg GPIO_MODE_INPUT: input mode
|
||||
\arg GPIO_MODE_OUTPUT: output mode
|
||||
\arg GPIO_MODE_AF: alternate function mode
|
||||
\arg GPIO_MODE_ANALOG: analog mode
|
||||
\param[in] pull_up_down: gpio pin with pull-up or pull-down resistor
|
||||
\arg GPIO_PUPD_NONE: floating mode, no pull-up and pull-down resistors
|
||||
\arg GPIO_PUPD_PULLUP: with pull-up resistor
|
||||
\arg GPIO_PUPD_PULLDOWN:with pull-down resistor
|
||||
\param[in] pin: GPIO pin
|
||||
one or more parameters can be selected which are shown as below:
|
||||
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void gpio_mode_set(uint32_t gpio_periph, uint32_t mode, uint32_t pull_up_down, uint32_t pin)
|
||||
{
|
||||
uint16_t i;
|
||||
uint32_t ctl, pupd;
|
||||
|
||||
ctl = GPIO_CTL(gpio_periph);
|
||||
pupd = GPIO_PUD(gpio_periph);
|
||||
|
||||
for(i = 0U;i < 16U;i++){
|
||||
if((1U << i) & pin){
|
||||
/* clear the specified pin mode bits */
|
||||
ctl &= ~GPIO_MODE_MASK(i);
|
||||
/* set the specified pin mode bits */
|
||||
ctl |= GPIO_MODE_SET(i, mode);
|
||||
|
||||
/* clear the specified pin pupd bits */
|
||||
pupd &= ~GPIO_PUPD_MASK(i);
|
||||
/* set the specified pin pupd bits */
|
||||
pupd |= GPIO_PUPD_SET(i, pull_up_down);
|
||||
}
|
||||
}
|
||||
|
||||
GPIO_CTL(gpio_periph) = ctl;
|
||||
GPIO_PUD(gpio_periph) = pupd;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set GPIO output type and speed
|
||||
\param[in] gpio_periph: GPIOx(x = A,B,C,F)
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg GPIOx(x = A,B,C,F)
|
||||
\param[in] otype: gpio pin output mode
|
||||
\arg GPIO_OTYPE_PP: push pull mode
|
||||
\arg GPIO_OTYPE_OD: open drain mode
|
||||
\param[in] speed: gpio pin output max speed
|
||||
\arg GPIO_OSPEED_2MHZ: output max speed 2MHz
|
||||
\arg GPIO_OSPEED_10MHZ: output max speed 10MHz
|
||||
\arg GPIO_OSPEED_50MHZ: output max speed 50MHz
|
||||
\param[in] pin: GPIO pin
|
||||
one or more parameters can be selected which are shown as below:
|
||||
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void gpio_output_options_set(uint32_t gpio_periph, uint8_t otype, uint32_t speed, uint32_t pin)
|
||||
{
|
||||
uint16_t i;
|
||||
uint32_t ospeed;
|
||||
|
||||
if(GPIO_OTYPE_OD == otype){
|
||||
GPIO_OMODE(gpio_periph) |= (uint32_t)pin;
|
||||
}else{
|
||||
GPIO_OMODE(gpio_periph) &= (uint32_t)(~pin);
|
||||
}
|
||||
|
||||
/* get the specified pin output speed bits value */
|
||||
ospeed = GPIO_OSPD(gpio_periph);
|
||||
|
||||
for(i = 0U;i < 16U;i++){
|
||||
if((1U << i) & pin){
|
||||
/* clear the specified pin output speed bits */
|
||||
ospeed &= ~GPIO_OSPEED_MASK(i);
|
||||
/* set the specified pin output speed bits */
|
||||
ospeed |= GPIO_OSPEED_SET(i,speed);
|
||||
}
|
||||
}
|
||||
GPIO_OSPD(gpio_periph) = ospeed;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set GPIO pin bit
|
||||
\param[in] gpio_periph: GPIOx(x = A,B,C,F)
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg GPIOx(x = A,B,C,F)
|
||||
\param[in] pin: GPIO pin
|
||||
one or more parameters can be selected which are shown as below:
|
||||
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void gpio_bit_set(uint32_t gpio_periph, uint32_t pin)
|
||||
{
|
||||
GPIO_BOP(gpio_periph) = (uint32_t)pin;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief reset GPIO pin bit
|
||||
\param[in] gpio_periph: GPIOx(x = A,B,C,F)
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg GPIOx(x = A,B,C,F)
|
||||
\param[in] pin: GPIO pin
|
||||
one or more parameters can be selected which are shown as below:
|
||||
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void gpio_bit_reset(uint32_t gpio_periph, uint32_t pin)
|
||||
{
|
||||
GPIO_BC(gpio_periph) = (uint32_t)pin;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief write data to the specified GPIO pin
|
||||
\param[in] gpio_periph: GPIOx(x = A,B,C,F)
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg GPIOx(x = A,B,C,F)
|
||||
\param[in] pin: GPIO pin
|
||||
one or more parameters can be selected which are shown as below:
|
||||
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
|
||||
\param[in] bit_value: SET or RESET
|
||||
\arg RESET: clear the port pin
|
||||
\arg SET: set the port pin
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void gpio_bit_write(uint32_t gpio_periph, uint32_t pin, bit_status bit_value)
|
||||
{
|
||||
if(RESET != bit_value){
|
||||
GPIO_BOP(gpio_periph) = (uint32_t)pin;
|
||||
}else{
|
||||
GPIO_BC(gpio_periph) = (uint32_t)pin;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief write data to the specified GPIO port
|
||||
\param[in] gpio_periph: GPIOx(x = A,B,C,F)
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg GPIOx(x = A,B,C,F)
|
||||
\param[in] data: specify the value to be written to the port output control register
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void gpio_port_write(uint32_t gpio_periph, uint16_t data)
|
||||
{
|
||||
GPIO_OCTL(gpio_periph) = (uint32_t)data;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get GPIO pin input status
|
||||
\param[in] gpio_periph: GPIOx(x = A,B,C,F)
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg GPIOx(x = A,B,C,F)
|
||||
\param[in] pin: GPIO pin
|
||||
one or more parameters can be selected which are shown as below:
|
||||
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
|
||||
\param[out] none
|
||||
\retval SET or RESET
|
||||
*/
|
||||
FlagStatus gpio_input_bit_get(uint32_t gpio_periph, uint32_t pin)
|
||||
{
|
||||
if((uint32_t)RESET != (GPIO_ISTAT(gpio_periph)&(pin))){
|
||||
return SET;
|
||||
}else{
|
||||
return RESET;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get GPIO all pins input status
|
||||
\param[in] gpio_periph: GPIOx(x = A,B,C,F)
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg GPIOx(x = A,B,C,F)
|
||||
\param[out] none
|
||||
\retval state of GPIO all pins
|
||||
*/
|
||||
uint16_t gpio_input_port_get(uint32_t gpio_periph)
|
||||
{
|
||||
return (uint16_t)GPIO_ISTAT(gpio_periph);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get GPIO pin output status
|
||||
\param[in] gpio_periph: GPIOx(x = A,B,C,F)
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg GPIOx(x = A,B,C,F)
|
||||
\param[in] pin: GPIO pin
|
||||
one or more parameters can be selected which are shown as below:
|
||||
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
|
||||
\param[out] none
|
||||
\retval SET or RESET
|
||||
*/
|
||||
FlagStatus gpio_output_bit_get(uint32_t gpio_periph, uint32_t pin)
|
||||
{
|
||||
if((uint32_t)RESET != (GPIO_OCTL(gpio_periph)&(pin))){
|
||||
return SET;
|
||||
}else{
|
||||
return RESET;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get GPIO all pins output status
|
||||
\param[in] gpio_periph: GPIOx(x = A,B,C,F)
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg GPIOx(x = A,B,C,F)
|
||||
\param[out] none
|
||||
\retval state of GPIO all pins
|
||||
*/
|
||||
uint16_t gpio_output_port_get(uint32_t gpio_periph)
|
||||
{
|
||||
return (uint16_t)GPIO_OCTL(gpio_periph);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set GPIO alternate function
|
||||
\param[in] gpio_periph: GPIOx(x = A,B,C)
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg GPIOx(x = A,B,C)
|
||||
\param[in] alt_func_num: GPIO pin af function, please refer to specific device datasheet
|
||||
\arg GPIO_AF_0: TIMER13, TIMER14, TIMER16, SPI0, SPI1, I2S0, CK_OUT, USART0,
|
||||
I2C0, I2C1, SWDIO, SWCLK
|
||||
\arg GPIO_AF_1: USART0, USART1, TIMER2, TIMER14, I2C0, I2C1
|
||||
\arg GPIO_AF_2: TIMER0, TIMER1, TIMER15, TIMER16, I2S0
|
||||
\arg GPIO_AF_3: I2C0, TIMER14
|
||||
\arg GPIO_AF_4(port A,B only): USART1, I2C0, I2C1, TIMER13
|
||||
\arg GPIO_AF_5(port A,B only): TIMER15, TIMER16, I2S0
|
||||
\arg GPIO_AF_6(port A,B only): SPI1
|
||||
\arg GPIO_AF_7(port A,B only): CMP
|
||||
\param[in] pin: GPIO pin
|
||||
one or more parameters can be selected which are shown as below:
|
||||
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void gpio_af_set(uint32_t gpio_periph, uint32_t alt_func_num, uint32_t pin)
|
||||
{
|
||||
uint16_t i;
|
||||
uint32_t afrl, afrh;
|
||||
|
||||
afrl = GPIO_AFSEL0(gpio_periph);
|
||||
afrh = GPIO_AFSEL1(gpio_periph);
|
||||
|
||||
for(i = 0U;i < 8U;i++){
|
||||
if((1U << i) & pin){
|
||||
/* clear the specified pin alternate function bits */
|
||||
afrl &= ~GPIO_AFR_MASK(i);
|
||||
afrl |= GPIO_AFR_SET(i,alt_func_num);
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 8U;i < 16U;i++){
|
||||
if((1U << i) & pin){
|
||||
/* clear the specified pin alternate function bits */
|
||||
afrh &= ~GPIO_AFR_MASK(i - 8U);
|
||||
afrh |= GPIO_AFR_SET(i - 8U,alt_func_num);
|
||||
}
|
||||
}
|
||||
|
||||
GPIO_AFSEL0(gpio_periph) = afrl;
|
||||
GPIO_AFSEL1(gpio_periph) = afrh;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief lock GPIO pin bit
|
||||
\param[in] gpio_periph: GPIOx(x = A,B)
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg GPIOx(x = A,B)
|
||||
\param[in] pin: GPIO pin
|
||||
one or more parameters can be selected which are shown as below:
|
||||
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void gpio_pin_lock(uint32_t gpio_periph, uint32_t pin)
|
||||
{
|
||||
uint32_t lock = 0x00010000U;
|
||||
lock |= pin;
|
||||
|
||||
/* lock key writing sequence: write 1->write 0->write 1->read 0->read 1 */
|
||||
GPIO_LOCK(gpio_periph) = (uint32_t)lock;
|
||||
GPIO_LOCK(gpio_periph) = (uint32_t)pin;
|
||||
GPIO_LOCK(gpio_periph) = (uint32_t)lock;
|
||||
lock = GPIO_LOCK(gpio_periph);
|
||||
lock = GPIO_LOCK(gpio_periph);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief toggle GPIO pin status
|
||||
\param[in] gpio_periph: GPIOx(x = A,B,C,F)
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg GPIOx(x = A,B,C,F)
|
||||
\param[in] pin: GPIO pin
|
||||
one or more parameters can be selected which are shown as below:
|
||||
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void gpio_bit_toggle(uint32_t gpio_periph, uint32_t pin)
|
||||
{
|
||||
GPIO_TG(gpio_periph) = (uint32_t)pin;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief toggle GPIO port status
|
||||
\param[in] gpio_periph: GPIOx(x = A,B,C,F)
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg GPIOx(x = A,B,C,F)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void gpio_port_toggle(uint32_t gpio_periph)
|
||||
{
|
||||
GPIO_TG(gpio_periph) = 0x0000FFFFU;
|
||||
}
|
797
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_i2c.c
Normal file
797
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_i2c.c
Normal file
@@ -0,0 +1,797 @@
|
||||
/*!
|
||||
\file gd32e23x_i2c.c
|
||||
\brief I2C driver
|
||||
|
||||
\version 2024-02-22, V2.1.0, firmware for GD32E23x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2024, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "gd32e23x_i2c.h"
|
||||
|
||||
/* I2C register bit mask */
|
||||
#define I2CCLK_MAX ((uint32_t)0x0000007FU) /*!< i2cclk maximum value */
|
||||
#define I2CCLK_MIN ((uint32_t)0x00000002U) /*!< i2cclk minimum value */
|
||||
#define I2C_FLAG_MASK ((uint32_t)0x0000FFFFU) /*!< i2c flag mask */
|
||||
#define I2C_ADDRESS_MASK ((uint32_t)0x000003FFU) /*!< i2c address mask */
|
||||
#define I2C_ADDRESS2_MASK ((uint32_t)0x000000FEU) /*!< the second i2c address mask */
|
||||
|
||||
/* I2C register bit offset */
|
||||
#define STAT1_PECV_OFFSET ((uint32_t)0x00000008U) /* bit offset of PECV in I2C_STAT1 */
|
||||
|
||||
/*!
|
||||
\brief reset I2C
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_deinit(uint32_t i2c_periph)
|
||||
{
|
||||
switch(i2c_periph) {
|
||||
case I2C0:
|
||||
/* reset I2C0 */
|
||||
rcu_periph_reset_enable(RCU_I2C0RST);
|
||||
rcu_periph_reset_disable(RCU_I2C0RST);
|
||||
break;
|
||||
case I2C1:
|
||||
/* reset I2C1 */
|
||||
rcu_periph_reset_enable(RCU_I2C1RST);
|
||||
rcu_periph_reset_disable(RCU_I2C1RST);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure I2C clock
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[in] clkspeed: I2C clock speed, supports standard mode (up to 100 kHz), fast mode (up to 400 kHz)
|
||||
and fast mode plus (up to 1MHz)
|
||||
\param[in] dutycyc: duty cycle in fast mode or fast mode plus
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2C_DTCY_2: T_low/T_high = 2 in fast mode or fast mode plus
|
||||
\arg I2C_DTCY_16_9: T_low/T_high = 16/9 in fast mode or fast mode plus
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_clock_config(uint32_t i2c_periph, uint32_t clkspeed, uint32_t dutycyc)
|
||||
{
|
||||
uint32_t pclk1, clkc, freq, risetime;
|
||||
uint32_t temp;
|
||||
|
||||
pclk1 = rcu_clock_freq_get(CK_APB1);
|
||||
/* I2C peripheral clock frequency */
|
||||
freq = (uint32_t)(pclk1 / 1000000U);
|
||||
if(freq >= I2CCLK_MAX) {
|
||||
freq = I2CCLK_MAX;
|
||||
}
|
||||
temp = I2C_CTL1(i2c_periph);
|
||||
temp &= ~I2C_CTL1_I2CCLK;
|
||||
temp |= freq;
|
||||
|
||||
I2C_CTL1(i2c_periph) = temp;
|
||||
|
||||
if(100000U >= clkspeed) {
|
||||
/* the maximum SCL rise time is 1000ns in standard mode */
|
||||
risetime = (uint32_t)((pclk1 / 1000000U) + 1U);
|
||||
if(risetime >= I2CCLK_MAX) {
|
||||
I2C_RT(i2c_periph) = I2CCLK_MAX;
|
||||
} else if(risetime <= I2CCLK_MIN) {
|
||||
I2C_RT(i2c_periph) = I2CCLK_MIN;
|
||||
} else {
|
||||
I2C_RT(i2c_periph) = risetime;
|
||||
}
|
||||
clkc = (uint32_t)(pclk1 / (clkspeed * 2U));
|
||||
if(clkc < 0x04U) {
|
||||
/* the CLKC in standard mode minmum value is 4 */
|
||||
clkc = 0x04U;
|
||||
}
|
||||
|
||||
I2C_CKCFG(i2c_periph) |= (I2C_CKCFG_CLKC & clkc);
|
||||
|
||||
} else if(400000U >= clkspeed) {
|
||||
/* the maximum SCL rise time is 300ns in fast mode */
|
||||
I2C_RT(i2c_periph) = (uint32_t)(((freq * (uint32_t)300U) / (uint32_t)1000U) + (uint32_t)1U);
|
||||
if(I2C_DTCY_2 == dutycyc) {
|
||||
/* I2C duty cycle is 2 */
|
||||
clkc = (uint32_t)(pclk1 / (clkspeed * 3U));
|
||||
I2C_CKCFG(i2c_periph) &= ~I2C_CKCFG_DTCY;
|
||||
} else {
|
||||
/* I2C duty cycle is 16/9 */
|
||||
clkc = (uint32_t)(pclk1 / (clkspeed * 25U));
|
||||
I2C_CKCFG(i2c_periph) |= I2C_CKCFG_DTCY;
|
||||
}
|
||||
if(0U == (clkc & I2C_CKCFG_CLKC)) {
|
||||
/* the CLKC in fast mode minmum value is 1 */
|
||||
clkc |= 0x0001U;
|
||||
}
|
||||
I2C_CKCFG(i2c_periph) |= I2C_CKCFG_FAST;
|
||||
I2C_CKCFG(i2c_periph) |= clkc;
|
||||
} else {
|
||||
/* fast mode plus, the maximum SCL rise time is 120ns */
|
||||
I2C_RT(i2c_periph) = (uint32_t)(((freq * (uint32_t)120U) / (uint32_t)1000U) + (uint32_t)1U);
|
||||
if(I2C_DTCY_2 == dutycyc) {
|
||||
/* I2C duty cycle is 2 */
|
||||
clkc = (uint32_t)(pclk1 / (clkspeed * 3U));
|
||||
I2C_CKCFG(i2c_periph) &= ~I2C_CKCFG_DTCY;
|
||||
} else {
|
||||
/* I2C duty cycle is 16/9 */
|
||||
clkc = (uint32_t)(pclk1 / (clkspeed * 25U));
|
||||
I2C_CKCFG(i2c_periph) |= I2C_CKCFG_DTCY;
|
||||
}
|
||||
/* enable fast mode */
|
||||
I2C_CKCFG(i2c_periph) |= I2C_CKCFG_FAST;
|
||||
I2C_CKCFG(i2c_periph) |= clkc;
|
||||
/* enable I2C fast mode plus */
|
||||
I2C_FMPCFG(i2c_periph) = I2C_FMPCFG_FMPEN;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure I2C address
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[in] mode:
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2C_I2CMODE_ENABLE: I2C mode
|
||||
\arg I2C_SMBUSMODE_ENABLE: SMBus mode
|
||||
\param[in] addformat: 7bits or 10bits
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2C_ADDFORMAT_7BITS: address format is 7 bits
|
||||
\arg I2C_ADDFORMAT_10BITS: address format is 10 bits
|
||||
\param[in] addr: I2C address
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_mode_addr_config(uint32_t i2c_periph, uint32_t mode, uint32_t addformat, uint32_t addr)
|
||||
{
|
||||
/* SMBus/I2C mode selected */
|
||||
uint32_t ctl = 0U;
|
||||
|
||||
ctl = I2C_CTL0(i2c_periph);
|
||||
ctl &= ~(I2C_CTL0_SMBEN);
|
||||
ctl |= mode;
|
||||
I2C_CTL0(i2c_periph) = ctl;
|
||||
/* configure address */
|
||||
addr = addr & I2C_ADDRESS_MASK;
|
||||
I2C_SADDR0(i2c_periph) = (addformat | addr);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief select SMBus type
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[in] type:
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2C_SMBUS_DEVICE: SMBus mode device type
|
||||
\arg I2C_SMBUS_HOST: SMBus mode host type
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_smbus_type_config(uint32_t i2c_periph, uint32_t type)
|
||||
{
|
||||
if(I2C_SMBUS_HOST == type) {
|
||||
I2C_CTL0(i2c_periph) |= I2C_CTL0_SMBSEL;
|
||||
} else {
|
||||
I2C_CTL0(i2c_periph) &= ~(I2C_CTL0_SMBSEL);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief whether or not to send an ACK
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[in] ack:
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2C_ACK_ENABLE: ACK will be sent
|
||||
\arg I2C_ACK_DISABLE: ACK will not be sent
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_ack_config(uint32_t i2c_periph, uint32_t ack)
|
||||
{
|
||||
uint32_t ctl = 0U;
|
||||
|
||||
ctl = I2C_CTL0(i2c_periph);
|
||||
ctl &= ~(I2C_CTL0_ACKEN);
|
||||
ctl |= ack;
|
||||
I2C_CTL0(i2c_periph) = ctl;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure I2C POAP position
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[in] pos:
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2C_ACKPOS_CURRENT: ACKEN bit decides whether or not to send ACK or not for the current byte
|
||||
\arg I2C_ACKPOS_NEXT: ACKEN bit decides whether or not to send ACK for the next byte
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_ackpos_config(uint32_t i2c_periph, uint32_t pos)
|
||||
{
|
||||
uint32_t ctl = 0U;
|
||||
/* configure I2C POAP position */
|
||||
ctl = I2C_CTL0(i2c_periph);
|
||||
ctl &= ~(I2C_CTL0_POAP);
|
||||
ctl |= pos;
|
||||
I2C_CTL0(i2c_periph) = ctl;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief master sends slave address
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[in] addr: slave address
|
||||
\param[in] trandirection: transmitter or receiver
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2C_TRANSMITTER: transmitter
|
||||
\arg I2C_RECEIVER: receiver
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_master_addressing(uint32_t i2c_periph, uint32_t addr, uint32_t trandirection)
|
||||
{
|
||||
/* master is a transmitter or a receiver */
|
||||
if(I2C_TRANSMITTER == trandirection) {
|
||||
addr = addr & I2C_TRANSMITTER;
|
||||
} else {
|
||||
addr = addr | I2C_RECEIVER;
|
||||
}
|
||||
/* send slave address */
|
||||
I2C_DATA(i2c_periph) = addr;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable dual-address mode
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[in] addr: the second address in dual-address mode
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_dualaddr_enable(uint32_t i2c_periph, uint32_t addr)
|
||||
{
|
||||
/* configure address */
|
||||
addr = addr & I2C_ADDRESS2_MASK;
|
||||
I2C_SADDR1(i2c_periph) = (I2C_SADDR1_DUADEN | addr);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable dual-address mode
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_dualaddr_disable(uint32_t i2c_periph)
|
||||
{
|
||||
I2C_SADDR1(i2c_periph) &= ~(I2C_SADDR1_DUADEN);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable I2C
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_enable(uint32_t i2c_periph)
|
||||
{
|
||||
I2C_CTL0(i2c_periph) |= I2C_CTL0_I2CEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable I2C
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_disable(uint32_t i2c_periph)
|
||||
{
|
||||
I2C_CTL0(i2c_periph) &= ~(I2C_CTL0_I2CEN);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief generate a START condition on I2C bus
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_start_on_bus(uint32_t i2c_periph)
|
||||
{
|
||||
I2C_CTL0(i2c_periph) |= I2C_CTL0_START;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief generate a STOP condition on I2C bus
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_stop_on_bus(uint32_t i2c_periph)
|
||||
{
|
||||
I2C_CTL0(i2c_periph) |= I2C_CTL0_STOP;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief I2C transmit data function
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[in] data: data of transmission
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_data_transmit(uint32_t i2c_periph, uint8_t data)
|
||||
{
|
||||
I2C_DATA(i2c_periph) = DATA_TRANS(data);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief I2C receive data function
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[out] none
|
||||
\retval data of received
|
||||
*/
|
||||
uint8_t i2c_data_receive(uint32_t i2c_periph)
|
||||
{
|
||||
return (uint8_t)DATA_RECV(I2C_DATA(i2c_periph));
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure I2C DMA mode
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[in] dmastate:
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2C_DMA_ON: enable DMA mode
|
||||
\arg I2C_DMA_OFF: disable DMA mode
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_dma_config(uint32_t i2c_periph, uint32_t dmastate)
|
||||
{
|
||||
/* configure I2C DMA function */
|
||||
uint32_t ctl = 0U;
|
||||
|
||||
ctl = I2C_CTL1(i2c_periph);
|
||||
ctl &= ~(I2C_CTL1_DMAON);
|
||||
ctl |= dmastate;
|
||||
I2C_CTL1(i2c_periph) = ctl;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure whether next DMA EOT is DMA last transfer or not
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[in] dmalast:
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2C_DMALST_ON: next DMA EOT is the last transfer
|
||||
\arg I2C_DMALST_OFF: next DMA EOT is not the last transfer
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_dma_last_transfer_config(uint32_t i2c_periph, uint32_t dmalast)
|
||||
{
|
||||
/* configure DMA last transfer */
|
||||
uint32_t ctl = 0U;
|
||||
|
||||
ctl = I2C_CTL1(i2c_periph);
|
||||
ctl &= ~(I2C_CTL1_DMALST);
|
||||
ctl |= dmalast;
|
||||
I2C_CTL1(i2c_periph) = ctl;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief whether to stretch SCL low when data is not ready in slave mode
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[in] stretchpara:
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2C_SCLSTRETCH_ENABLE: enable SCL stretching
|
||||
\arg I2C_SCLSTRETCH_DISABLE: disable SCL stretching
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_stretch_scl_low_config(uint32_t i2c_periph, uint32_t stretchpara)
|
||||
{
|
||||
/* configure I2C SCL strerching */
|
||||
uint32_t ctl = 0U;
|
||||
|
||||
ctl = I2C_CTL0(i2c_periph);
|
||||
ctl &= ~(I2C_CTL0_SS);
|
||||
ctl |= stretchpara;
|
||||
I2C_CTL0(i2c_periph) = ctl;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief whether or not to response to a general call
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[in] gcallpara:
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2C_GCEN_ENABLE: slave will response to a general call
|
||||
\arg I2C_GCEN_DISABLE: slave will not response to a general call
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_slave_response_to_gcall_config(uint32_t i2c_periph, uint32_t gcallpara)
|
||||
{
|
||||
/* configure slave response to a general call enable or disable */
|
||||
uint32_t ctl = 0U;
|
||||
|
||||
ctl = I2C_CTL0(i2c_periph);
|
||||
ctl &= ~(I2C_CTL0_GCEN);
|
||||
ctl |= gcallpara;
|
||||
I2C_CTL0(i2c_periph) = ctl;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure software reset of I2C
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[in] sreset:
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2C_SRESET_SET: I2C is under reset
|
||||
\arg I2C_SRESET_RESET: I2C is not under reset
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_software_reset_config(uint32_t i2c_periph, uint32_t sreset)
|
||||
{
|
||||
/* modify CTL0 and configure software reset I2C state */
|
||||
uint32_t ctl = 0U;
|
||||
|
||||
ctl = I2C_CTL0(i2c_periph);
|
||||
ctl &= ~(I2C_CTL0_SRESET);
|
||||
ctl |= sreset;
|
||||
I2C_CTL0(i2c_periph) = ctl;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure I2C PEC calculation
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[in] pecstate:
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2C_PEC_ENABLE: PEC calculation on
|
||||
\arg I2C_PEC_DISABLE: PEC calculation off
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_pec_config(uint32_t i2c_periph, uint32_t pecstate)
|
||||
{
|
||||
/* on/off PEC calculation */
|
||||
uint32_t ctl = 0U;
|
||||
|
||||
ctl = I2C_CTL0(i2c_periph);
|
||||
ctl &= ~(I2C_CTL0_PECEN);
|
||||
ctl |= pecstate;
|
||||
I2C_CTL0(i2c_periph) = ctl;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure whether to transfer PEC value
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[in] pecpara:
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2C_PECTRANS_ENABLE: transfer PEC value
|
||||
\arg I2C_PECTRANS_DISABLE: not transfer PEC value
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_pec_transfer_config(uint32_t i2c_periph, uint32_t pecpara)
|
||||
{
|
||||
/* whether to transfer PEC */
|
||||
uint32_t ctl = 0U;
|
||||
|
||||
ctl = I2C_CTL0(i2c_periph);
|
||||
ctl &= ~(I2C_CTL0_PECTRANS);
|
||||
ctl |= pecpara;
|
||||
I2C_CTL0(i2c_periph) = ctl;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get packet error checking value
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[out] none
|
||||
\retval PEC value
|
||||
*/
|
||||
uint8_t i2c_pec_value_get(uint32_t i2c_periph)
|
||||
{
|
||||
return (uint8_t)((I2C_STAT1(i2c_periph) & I2C_STAT1_PECV) >> STAT1_PECV_OFFSET);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure I2C alert through SMBA pin
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[in] smbuspara:
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2C_SALTSEND_ENABLE: issue alert through SMBA pin
|
||||
\arg I2C_SALTSEND_DISABLE: not issue alert through SMBA pin
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_smbus_alert_config(uint32_t i2c_periph, uint32_t smbuspara)
|
||||
{
|
||||
/* configure smubus alert through SMBA pin */
|
||||
uint32_t ctl = 0U;
|
||||
|
||||
ctl = I2C_CTL0(i2c_periph);
|
||||
ctl &= ~(I2C_CTL0_SALT);
|
||||
ctl |= smbuspara;
|
||||
I2C_CTL0(i2c_periph) = ctl;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure I2C ARP protocol in SMBus
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[in] arpstate:
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2C_ARP_ENABLE: enable ARP
|
||||
\arg I2C_ARP_DISABLE: disable ARP
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_smbus_arp_config(uint32_t i2c_periph, uint32_t arpstate)
|
||||
{
|
||||
/* enable or disable I2C ARP protocol*/
|
||||
uint32_t ctl = 0U;
|
||||
|
||||
ctl = I2C_CTL0(i2c_periph);
|
||||
ctl &= ~(I2C_CTL0_ARPEN);
|
||||
ctl |= arpstate;
|
||||
I2C_CTL0(i2c_periph) = ctl;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable SAM_V interface
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_sam_enable(uint32_t i2c_periph)
|
||||
{
|
||||
I2C_SAMCS(i2c_periph) |= I2C_SAMCS_SAMEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable SAM_V interface
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_sam_disable(uint32_t i2c_periph)
|
||||
{
|
||||
I2C_SAMCS(i2c_periph) &= ~(I2C_SAMCS_SAMEN);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable SAM_V interface timeout detect
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_sam_timeout_enable(uint32_t i2c_periph)
|
||||
{
|
||||
I2C_SAMCS(i2c_periph) |= I2C_SAMCS_STOEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable SAM_V interface timeout detect
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_sam_timeout_disable(uint32_t i2c_periph)
|
||||
{
|
||||
I2C_SAMCS(i2c_periph) &= ~(I2C_SAMCS_STOEN);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get I2C flag status
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[in] flag: I2C flags, refer to i2c_flag_enum
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2C_FLAG_SBSEND: start condition sent out in master mode
|
||||
\arg I2C_FLAG_ADDSEND: address is sent in master mode or received and matches in slave mode
|
||||
\arg I2C_FLAG_BTC: byte transmission finishes
|
||||
\arg I2C_FLAG_ADD10SEND: header of 10-bit address is sent in master mode
|
||||
\arg I2C_FLAG_STPDET: stop condition detected in slave mode
|
||||
\arg I2C_FLAG_RBNE: I2C_DATA is not empty during receiving
|
||||
\arg I2C_FLAG_TBE: I2C_DATA is empty during transmitting
|
||||
\arg I2C_FLAG_BERR: a bus error occurs indication a unexpected start or stop condition on I2C bus
|
||||
\arg I2C_FLAG_LOSTARB: arbitration lost in master mode
|
||||
\arg I2C_FLAG_AERR: acknowledge error
|
||||
\arg I2C_FLAG_OUERR: over-run or under-run situation occurs in slave mode
|
||||
\arg I2C_FLAG_PECERR: PEC error when receiving data
|
||||
\arg I2C_FLAG_SMBTO: timeout signal in SMBus mode
|
||||
\arg I2C_FLAG_SMBALT: SMBus alert status
|
||||
\arg I2C_FLAG_MASTER: a flag indicating whether I2C block is in master or slave mode
|
||||
\arg I2C_FLAG_I2CBSY: busy flag
|
||||
\arg I2C_FLAG_TR: whether the I2C is a transmitter or a receiver
|
||||
\arg I2C_FLAG_RXGC: general call address (00h) received
|
||||
\arg I2C_FLAG_DEFSMB: default address of SMBus device
|
||||
\arg I2C_FLAG_HSTSMB: SMBus host header detected in slave mode
|
||||
\arg I2C_FLAG_DUMOD: dual flag in slave mode indicating which address is matched in dual-address mode
|
||||
\arg I2C_FLAG_TFF: txframe fall flag
|
||||
\arg I2C_FLAG_TFR: txframe rise flag
|
||||
\arg I2C_FLAG_RFF: rxframe fall flag
|
||||
\arg I2C_FLAG_RFR: rxframe rise flag
|
||||
\param[out] none
|
||||
\retval FlagStatus: SET or RESET
|
||||
*/
|
||||
FlagStatus i2c_flag_get(uint32_t i2c_periph, i2c_flag_enum flag)
|
||||
{
|
||||
if(RESET != (I2C_REG_VAL(i2c_periph, flag) & BIT(I2C_BIT_POS(flag)))) {
|
||||
return SET;
|
||||
} else {
|
||||
return RESET;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief clear I2C flag status
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[in] flag: I2C flags, refer to i2c_flag_enum
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2C_FLAG_SMBALT: SMBus alert status
|
||||
\arg I2C_FLAG_SMBTO: timeout signal in SMBus mode
|
||||
\arg I2C_FLAG_PECERR: PEC error when receiving data
|
||||
\arg I2C_FLAG_OUERR: over-run or under-run situation occurs in slave mode
|
||||
\arg I2C_FLAG_AERR: acknowledge error
|
||||
\arg I2C_FLAG_LOSTARB: arbitration lost in master mode
|
||||
\arg I2C_FLAG_BERR: a bus error occurs indication a unexpected start or stop condition on I2C bus
|
||||
\arg I2C_FLAG_ADDSEND: address is sent in master mode or received and matches in slave mode
|
||||
\arg I2C_FLAG_TFF: txframe fall flag
|
||||
\arg I2C_FLAG_TFR: txframe rise flag
|
||||
\arg I2C_FLAG_RFF: rxframe fall flag
|
||||
\arg I2C_FLAG_RFR: rxframe rise flag
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_flag_clear(uint32_t i2c_periph, i2c_flag_enum flag)
|
||||
{
|
||||
if(I2C_FLAG_ADDSEND == flag) {
|
||||
/* read I2C_STAT0 and then read I2C_STAT1 to clear ADDSEND */
|
||||
I2C_STAT0(i2c_periph);
|
||||
I2C_STAT1(i2c_periph);
|
||||
} else {
|
||||
I2C_REG_VAL(i2c_periph, flag) &= ~BIT(I2C_BIT_POS(flag));
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable I2C interrupt
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[in] interrupt: I2C interrupts, refer to i2c_interrupt_enum
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2C_INT_ERR: error interrupt
|
||||
\arg I2C_INT_EV: event interrupt
|
||||
\arg I2C_INT_BUF: buffer interrupt
|
||||
\arg I2C_INT_TFF: txframe fall interrupt
|
||||
\arg I2C_INT_TFR: txframe rise interrupt
|
||||
\arg I2C_INT_RFF: rxframe fall interrupt
|
||||
\arg I2C_INT_RFR: rxframe rise interrupt
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_interrupt_enable(uint32_t i2c_periph, i2c_interrupt_enum interrupt)
|
||||
{
|
||||
I2C_REG_VAL(i2c_periph, interrupt) |= BIT(I2C_BIT_POS(interrupt));
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable I2C interrupt
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[in] interrupt: I2C interrupts, refer to i2c_interrupt_enum
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2C_INT_ERR: error interrupt
|
||||
\arg I2C_INT_EV: event interrupt
|
||||
\arg I2C_INT_BUF: buffer interrupt
|
||||
\arg I2C_INT_TFF: txframe fall interrupt
|
||||
\arg I2C_INT_TFR: txframe rise interrupt
|
||||
\arg I2C_INT_RFF: rxframe fall interrupt
|
||||
\arg I2C_INT_RFR: rxframe rise interrupt
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_interrupt_disable(uint32_t i2c_periph, i2c_interrupt_enum interrupt)
|
||||
{
|
||||
I2C_REG_VAL(i2c_periph, interrupt) &= ~BIT(I2C_BIT_POS(interrupt));
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get I2C interrupt flag status
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[in] int_flag: I2C interrupt flags, refer to i2c_interrupt_flag_enum
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2C_INT_FLAG_SBSEND: start condition sent out in master mode interrupt flag
|
||||
\arg I2C_INT_FLAG_ADDSEND: address is sent in master mode or received and matches in slave mode interrupt flag
|
||||
\arg I2C_INT_FLAG_BTC: byte transmission finishes interrupt flag
|
||||
\arg I2C_INT_FLAG_ADD10SEND: header of 10-bit address is sent in master mode interrupt flag
|
||||
\arg I2C_INT_FLAG_STPDET: stop condition detected in slave mode interrupt flag
|
||||
\arg I2C_INT_FLAG_RBNE: I2C_DATA is not Empty during receiving interrupt flag
|
||||
\arg I2C_INT_FLAG_TBE: I2C_DATA is empty during transmitting interrupt flag
|
||||
\arg I2C_INT_FLAG_BERR: a bus error occurs indication a unexpected start or stop condition on I2C bus interrupt flag
|
||||
\arg I2C_INT_FLAG_LOSTARB: arbitration lost in master mode interrupt flag
|
||||
\arg I2C_INT_FLAG_AERR: acknowledge error interrupt flag
|
||||
\arg I2C_INT_FLAG_OUERR: over-run or under-run situation occurs in slave mode interrupt flag
|
||||
\arg I2C_INT_FLAG_PECERR: PEC error when receiving data interrupt flag
|
||||
\arg I2C_INT_FLAG_SMBTO: timeout signal in SMBus mode interrupt flag
|
||||
\arg I2C_INT_FLAG_SMBALT: SMBus alert status interrupt flag
|
||||
\arg I2C_INT_FLAG_TFF: txframe fall interrupt flag
|
||||
\arg I2C_INT_FLAG_TFR: txframe rise interrupt flag
|
||||
\arg I2C_INT_FLAG_RFF: rxframe fall interrupt flag
|
||||
\arg I2C_INT_FLAG_RFR: rxframe rise interrupt flag
|
||||
\param[out] none
|
||||
\retval FlagStatus: SET or RESET
|
||||
*/
|
||||
FlagStatus i2c_interrupt_flag_get(uint32_t i2c_periph, i2c_interrupt_flag_enum int_flag)
|
||||
{
|
||||
uint32_t intenable = 0U, flagstatus = 0U, bufie;
|
||||
|
||||
/* check BUFIE */
|
||||
bufie = I2C_CTL1(i2c_periph)&I2C_CTL1_BUFIE;
|
||||
|
||||
/* get the interrupt enable bit status */
|
||||
intenable = (I2C_REG_VAL(i2c_periph, int_flag) & BIT(I2C_BIT_POS(int_flag)));
|
||||
/* get the corresponding flag bit status */
|
||||
flagstatus = (I2C_REG_VAL2(i2c_periph, int_flag) & BIT(I2C_BIT_POS2(int_flag)));
|
||||
|
||||
if((I2C_INT_FLAG_RBNE == int_flag) || (I2C_INT_FLAG_TBE == int_flag)) {
|
||||
if(intenable && bufie) {
|
||||
intenable = 1U;
|
||||
} else {
|
||||
intenable = 0U;
|
||||
}
|
||||
}
|
||||
if((0U != flagstatus) && (0U != intenable)) {
|
||||
return SET;
|
||||
} else {
|
||||
return RESET;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief clear I2C interrupt flag status
|
||||
\param[in] i2c_periph: I2Cx(x=0,1)
|
||||
\param[in] int_flag: I2C interrupt flags, refer to i2c_interrupt_flag_enum
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2C_INT_FLAG_ADDSEND: address is sent in master mode or received and matches in slave mode interrupt flag
|
||||
\arg I2C_INT_FLAG_BERR: a bus error occurs indication a unexpected start or stop condition on I2C bus interrupt flag
|
||||
\arg I2C_INT_FLAG_LOSTARB: arbitration lost in master mode interrupt flag
|
||||
\arg I2C_INT_FLAG_AERR: acknowledge error interrupt flag
|
||||
\arg I2C_INT_FLAG_OUERR: over-run or under-run situation occurs in slave mode interrupt flag
|
||||
\arg I2C_INT_FLAG_PECERR: PEC error when receiving data interrupt flag
|
||||
\arg I2C_INT_FLAG_SMBTO: timeout signal in SMBus mode interrupt flag
|
||||
\arg I2C_INT_FLAG_SMBALT: SMBus alert status interrupt flag
|
||||
\arg I2C_INT_FLAG_TFF: txframe fall interrupt flag
|
||||
\arg I2C_INT_FLAG_TFR: txframe rise interrupt flag
|
||||
\arg I2C_INT_FLAG_RFF: rxframe fall interrupt flag
|
||||
\arg I2C_INT_FLAG_RFR: rxframe rise interrupt flag
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_interrupt_flag_clear(uint32_t i2c_periph, i2c_interrupt_flag_enum int_flag)
|
||||
{
|
||||
if(I2C_INT_FLAG_ADDSEND == int_flag) {
|
||||
/* read I2C_STAT0 and then read I2C_STAT1 to clear ADDSEND */
|
||||
I2C_STAT0(i2c_periph);
|
||||
I2C_STAT1(i2c_periph);
|
||||
} else {
|
||||
I2C_REG_VAL2(i2c_periph, int_flag) &= ~BIT(I2C_BIT_POS2(int_flag));
|
||||
}
|
||||
}
|
141
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_misc.c
Normal file
141
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_misc.c
Normal file
@@ -0,0 +1,141 @@
|
||||
/*!
|
||||
\file gd32e23x_misc.c
|
||||
\brief MISC driver
|
||||
|
||||
\version 2024-02-22, V2.1.0, firmware for GD32E23x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2024, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "gd32e23x_misc.h"
|
||||
|
||||
/*!
|
||||
\brief enable NVIC request
|
||||
\param[in] nvic_irq: the NVIC interrupt request, detailed in IRQn_Type
|
||||
\param[in] nvic_irq_priority: the priority needed to set (0-3)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void nvic_irq_enable(uint8_t nvic_irq,
|
||||
uint8_t nvic_irq_priority)
|
||||
{
|
||||
/* set the priority and enable the selected IRQ */
|
||||
NVIC_SetPriority((IRQn_Type)nvic_irq, (uint32_t)nvic_irq_priority);
|
||||
NVIC_EnableIRQ((IRQn_Type)nvic_irq);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable NVIC request
|
||||
\param[in] nvic_irq: the NVIC interrupt request, detailed in IRQn_Type
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void nvic_irq_disable(uint8_t nvic_irq)
|
||||
{
|
||||
/* disable the selected IRQ.*/
|
||||
NVIC_DisableIRQ((IRQn_Type)nvic_irq);
|
||||
}
|
||||
|
||||
/* */
|
||||
/*!
|
||||
\brief initiates a system reset request to reset the MCU
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void nvic_system_reset(void)
|
||||
{
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set the NVIC vector table base address
|
||||
\param[in] nvic_vict_tab: the RAM or FLASH base address
|
||||
\arg NVIC_VECTTAB_RAM: RAM base address
|
||||
\arg NVIC_VECTTAB_FLASH: Flash base address
|
||||
\param[in] offset: Vector Table offset
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void nvic_vector_table_set(uint32_t nvic_vict_tab, uint32_t offset)
|
||||
{
|
||||
SCB->VTOR = nvic_vict_tab | (offset & NVIC_VECTTAB_OFFSET_MASK);
|
||||
__DSB();
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set the state of the low power mode
|
||||
\param[in] lowpower_mode: the low power mode state
|
||||
\arg SCB_LPM_SLEEP_EXIT_ISR: if chose this para, the system always enter low power
|
||||
mode by exiting from ISR
|
||||
\arg SCB_LPM_DEEPSLEEP: if chose this para, the system will enter the DEEPSLEEP mode
|
||||
\arg SCB_LPM_WAKE_BY_ALL_INT: if chose this para, the lowpower mode can be woke up
|
||||
by all the enable and disable interrupts
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void system_lowpower_set(uint8_t lowpower_mode)
|
||||
{
|
||||
SCB->SCR |= (uint32_t)lowpower_mode;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief reset the state of the low power mode
|
||||
\param[in] lowpower_mode: the low power mode state
|
||||
\arg SCB_LPM_SLEEP_EXIT_ISR: if chose this para, the system will exit low power
|
||||
mode by exiting from ISR
|
||||
\arg SCB_LPM_DEEPSLEEP: if chose this para, the system will enter the SLEEP mode
|
||||
\arg SCB_LPM_WAKE_BY_ALL_INT: if chose this para, the lowpower mode only can be
|
||||
woke up by the enable interrupts
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void system_lowpower_reset(uint8_t lowpower_mode)
|
||||
{
|
||||
SCB->SCR &= (~(uint32_t)lowpower_mode);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set the systick clock source
|
||||
\param[in] systick_clksource: the systick clock source needed to choose
|
||||
\arg SYSTICK_CLKSOURCE_HCLK: systick clock source is from HCLK
|
||||
\arg SYSTICK_CLKSOURCE_HCLK_DIV8: systick clock source is from HCLK/8
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
|
||||
void systick_clksource_set(uint32_t systick_clksource)
|
||||
{
|
||||
if(SYSTICK_CLKSOURCE_HCLK == systick_clksource ){
|
||||
/* set the systick clock source from HCLK */
|
||||
SysTick->CTRL |= SYSTICK_CLKSOURCE_HCLK;
|
||||
}else{
|
||||
/* set the systick clock source from HCLK/8 */
|
||||
SysTick->CTRL &= SYSTICK_CLKSOURCE_HCLK_DIV8;
|
||||
}
|
||||
}
|
289
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_pmu.c
Normal file
289
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_pmu.c
Normal file
@@ -0,0 +1,289 @@
|
||||
/*!
|
||||
\file gd32e23x_pmu.c
|
||||
\brief PMU driver
|
||||
|
||||
\version 2023-09-04, V2.0.1, firmware for GD32E23x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2024, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "gd32e23x_pmu.h"
|
||||
|
||||
/*!
|
||||
\brief reset PMU register
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void pmu_deinit(void)
|
||||
{
|
||||
/* reset PMU */
|
||||
rcu_periph_reset_enable(RCU_PMURST);
|
||||
rcu_periph_reset_disable(RCU_PMURST);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief select low voltage detector threshold
|
||||
\param[in] lvdt_n:
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg PMU_LVDT_0: voltage threshold is 2.1V
|
||||
\arg PMU_LVDT_1: voltage threshold is 2.3V
|
||||
\arg PMU_LVDT_2: voltage threshold is 2.4V
|
||||
\arg PMU_LVDT_3: voltage threshold is 2.6V
|
||||
\arg PMU_LVDT_4: voltage threshold is 2.7V
|
||||
\arg PMU_LVDT_5: voltage threshold is 2.9V
|
||||
\arg PMU_LVDT_6: voltage threshold is 3.0V
|
||||
\arg PMU_LVDT_7: voltage threshold is 3.1V
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void pmu_lvd_select(uint32_t lvdt_n)
|
||||
{
|
||||
/* disable LVD */
|
||||
PMU_CTL &= ~PMU_CTL_LVDEN;
|
||||
/* clear LVDT bits */
|
||||
PMU_CTL &= ~PMU_CTL_LVDT;
|
||||
/* set LVDT bits according to lvdt_n */
|
||||
PMU_CTL |= lvdt_n;
|
||||
/* enable LVD */
|
||||
PMU_CTL |= PMU_CTL_LVDEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief select LDO output voltage
|
||||
these bits set by software when the main PLL closed
|
||||
\param[in] ldo_output:
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg PMU_LDOVS_LOW: LDO output voltage low mode
|
||||
\arg PMU_LDOVS_HIGH: LDO output voltage high mode
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void pmu_ldo_output_select(uint32_t ldo_output)
|
||||
{
|
||||
PMU_CTL &= ~PMU_CTL_LDOVS;
|
||||
PMU_CTL |= ldo_output;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable PMU lvd
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void pmu_lvd_disable(void)
|
||||
{
|
||||
/* disable LVD */
|
||||
PMU_CTL &= ~PMU_CTL_LVDEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief PMU work at sleep mode
|
||||
\param[in] sleepmodecmd:
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg WFI_CMD: use WFI command
|
||||
\arg WFE_CMD: use WFE command
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void pmu_to_sleepmode(uint8_t sleepmodecmd)
|
||||
{
|
||||
/* clear sleepdeep bit of Cortex-M23 system control register */
|
||||
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
|
||||
|
||||
/* select WFI or WFE command to enter sleep mode */
|
||||
if(WFI_CMD == sleepmodecmd){
|
||||
__WFI();
|
||||
}else{
|
||||
__WFE();
|
||||
__WFE();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief PMU work at deepsleep mode
|
||||
\param[in] ldo:
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg PMU_LDO_NORMAL: LDO operates normally when pmu enter deepsleep mode
|
||||
\arg PMU_LDO_LOWPOWER: LDO work at low power mode when pmu enter deepsleep mode
|
||||
\param[in] deepsleepmodecmd:
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg WFI_CMD: use WFI command
|
||||
\arg WFE_CMD: use WFE command
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void pmu_to_deepsleepmode(uint32_t ldo,uint8_t deepsleepmodecmd)
|
||||
{
|
||||
/* clear stbmod and ldolp bits */
|
||||
PMU_CTL &= ~((uint32_t)(PMU_CTL_STBMOD | PMU_CTL_LDOLP));
|
||||
|
||||
/* set ldolp bit according to pmu_ldo */
|
||||
PMU_CTL |= ldo;
|
||||
|
||||
/* set sleepdeep bit of Cortex-M23 system control register */
|
||||
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
|
||||
|
||||
/* select WFI or WFE command to enter deepsleep mode */
|
||||
if(WFI_CMD == deepsleepmodecmd){
|
||||
__WFI();
|
||||
}else{
|
||||
__SEV();
|
||||
__WFE();
|
||||
__WFE();
|
||||
}
|
||||
|
||||
/* reset sleepdeep bit of Cortex-M23 system control register */
|
||||
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief pmu work at standby mode
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void pmu_to_standbymode(void)
|
||||
{
|
||||
/* switch to IRC8M clock as system clock, close HXTAL */
|
||||
RCU_CFG0 &= ~RCU_CFG0_SCS;
|
||||
RCU_CTL0 &= ~RCU_CTL0_HXTALEN;
|
||||
|
||||
/* set stbmod bit */
|
||||
PMU_CTL |= PMU_CTL_STBMOD;
|
||||
|
||||
/* reset wakeup flag */
|
||||
PMU_CTL |= PMU_CTL_WURST;
|
||||
|
||||
/* set sleepdeep bit of Cortex-M23 system control register */
|
||||
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
|
||||
|
||||
REG32( 0xE000E010U ) &= 0x00010004U;
|
||||
REG32( 0xE000E180U ) = 0XFFFFFFFBU;
|
||||
REG32( 0xE000E184U ) = 0XFFFFFFFFU;
|
||||
REG32( 0xE000E188U ) = 0xFFFFFFFFU;
|
||||
|
||||
/* select WFI command to enter standby mode */
|
||||
__WFI();
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable wakeup pin
|
||||
\param[in] wakeup_pin:
|
||||
one or more parameters can be selected which are shown as below:
|
||||
\arg PMU_WAKEUP_PIN0: WKUP Pin 0 (PA0)
|
||||
\arg PMU_WAKEUP_PIN1: WKUP Pin 1 (PC13)
|
||||
\arg PMU_WAKEUP_PIN5: WKUP Pin 5 (PB5)
|
||||
\arg PMU_WAKEUP_PIN6: WKUP Pin 6 (PB15)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void pmu_wakeup_pin_enable(uint32_t wakeup_pin)
|
||||
{
|
||||
PMU_CS |= wakeup_pin;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable wakeup pin
|
||||
\param[in] wakeup_pin:
|
||||
one or more parameters can be selected which are shown as below:
|
||||
\arg PMU_WAKEUP_PIN0: WKUP Pin 0 (PA0)
|
||||
\arg PMU_WAKEUP_PIN1: WKUP Pin 1 (PC13)
|
||||
\arg PMU_WAKEUP_PIN5: WKUP Pin 5 (PB5)
|
||||
\arg PMU_WAKEUP_PIN6: WKUP Pin 6 (PB15)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void pmu_wakeup_pin_disable(uint32_t wakeup_pin)
|
||||
{
|
||||
PMU_CS &= ~(wakeup_pin);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable backup domain write
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void pmu_backup_write_enable(void)
|
||||
{
|
||||
PMU_CTL |= PMU_CTL_BKPWEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable backup domain write
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void pmu_backup_write_disable(void)
|
||||
{
|
||||
PMU_CTL &= ~PMU_CTL_BKPWEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get flag state
|
||||
\param[in] flag:
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg PMU_FLAG_WAKEUP: wakeup flag
|
||||
\arg PMU_FLAG_STANDBY: standby flag
|
||||
\arg PMU_FLAG_LVD: lvd flag
|
||||
\param[out] none
|
||||
\retval FlagStatus SET or RESET
|
||||
*/
|
||||
FlagStatus pmu_flag_get(uint32_t flag)
|
||||
{
|
||||
FlagStatus ret_status = RESET;
|
||||
|
||||
if(PMU_CS & flag){
|
||||
ret_status = SET;
|
||||
}
|
||||
|
||||
return ret_status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief clear flag bit
|
||||
\param[in] flag:
|
||||
one or more parameters can be selected which are shown as below:
|
||||
\arg PMU_FLAG_RESET_WAKEUP: reset wakeup flag
|
||||
\arg PMU_FLAG_RESET_STANDBY: reset standby flag
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void pmu_flag_clear(uint32_t flag)
|
||||
{
|
||||
if(RESET != (flag & PMU_FLAG_RESET_WAKEUP)){
|
||||
/* reset wakeup flag */
|
||||
PMU_CTL |= PMU_CTL_WURST;
|
||||
}
|
||||
if(RESET != (flag & PMU_FLAG_RESET_STANDBY)){
|
||||
/* reset standby flag */
|
||||
PMU_CTL |= PMU_CTL_STBRST;
|
||||
}
|
||||
}
|
1058
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_rcu.c
Normal file
1058
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_rcu.c
Normal file
File diff suppressed because it is too large
Load Diff
962
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_rtc.c
Normal file
962
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_rtc.c
Normal file
@@ -0,0 +1,962 @@
|
||||
/*!
|
||||
\file gd32e23x_rtc.c
|
||||
\brief RTC driver
|
||||
|
||||
\version 2024-02-22, V2.1.0, firmware for GD32E23x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2024, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "gd32e23x_rtc.h"
|
||||
|
||||
/*!
|
||||
\brief reset most of the RTC registers
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval ErrStatus: ERROR or SUCCESS
|
||||
*/
|
||||
ErrStatus rtc_deinit(void)
|
||||
{
|
||||
ErrStatus error_status = ERROR;
|
||||
|
||||
/* RTC_TAMP register is not under write protection */
|
||||
RTC_TAMP = RTC_REGISTER_RESET;
|
||||
|
||||
/* disable the write protection */
|
||||
RTC_WPK = RTC_UNLOCK_KEY1;
|
||||
RTC_WPK = RTC_UNLOCK_KEY2;
|
||||
|
||||
/* reset RTC_CTL register, this can be done without the init mode */
|
||||
RTC_CTL &= RTC_REGISTER_RESET;
|
||||
|
||||
/* enter init mode */
|
||||
error_status = rtc_init_mode_enter();
|
||||
|
||||
if(ERROR != error_status){
|
||||
/* before reset RTC_TIME and RTC_DATE, BPSHAD bit in RTC_CTL should be reset as the condition.
|
||||
in order to read calendar from shadow register, not the real registers being reset */
|
||||
RTC_TIME = RTC_REGISTER_RESET;
|
||||
RTC_DATE = RTC_DATE_RESET;
|
||||
|
||||
RTC_PSC = RTC_PSC_RESET;
|
||||
|
||||
/* reset RTC_STAT register, also exit init mode.
|
||||
at the same time, RTC_STAT_SOPF bit is reset, as the condition to reset RTC_SHIFTCTL register later */
|
||||
RTC_STAT = RTC_STAT_RESET;
|
||||
|
||||
/* to write RTC_ALRM0SS register, ALRM0EN bit in RTC_CTL register should be reset as the condition */
|
||||
RTC_ALRM0TD = RTC_REGISTER_RESET;
|
||||
RTC_ALRM0SS = RTC_REGISTER_RESET;
|
||||
|
||||
/* reset RTC_SHIFTCTL and RTC_HRFC register, this can be done without the init mode */
|
||||
RTC_SHIFTCTL = RTC_REGISTER_RESET;
|
||||
RTC_HRFC = RTC_REGISTER_RESET;
|
||||
|
||||
error_status = rtc_register_sync_wait();
|
||||
}
|
||||
|
||||
/* enable the write protection */
|
||||
RTC_WPK = RTC_LOCK_KEY;
|
||||
|
||||
return error_status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief initialize RTC registers
|
||||
\param[in] rtc_initpara_struct: pointer to a rtc_parameter_struct structure which contains
|
||||
parameters for initialization of the rtc peripheral
|
||||
members of the structure and the member values are shown as below:
|
||||
rtc_year: 0x0 - 0x99(BCD format)
|
||||
rtc_month: RTC_JAN, RTC_FEB, RTC_MAR, RTC_APR, RTC_MAY, RTC_JUN,
|
||||
RTC_JUL, RTC_AUG, RTC_SEP, RTC_OCT, RTC_NOV, RTC_DEC
|
||||
rtc_date: 0x1 - 0x31(BCD format)
|
||||
rtc_day_of_week: RTC_MONDAY, RTC_TUESDAY, RTC_WEDSDAY, RTC_THURSDAY
|
||||
RTC_FRIDAY, RTC_SATURDAY, RTC_SUNDAY
|
||||
rtc_hour: 0x0 - 0x12(BCD format) or 0x0 - 0x23(BCD format) depending on the rtc_display_format chose
|
||||
rtc_minute: 0x0 - 0x59(BCD format)
|
||||
rtc_second: 0x0 - 0x59(BCD format)
|
||||
rtc_factor_asyn: 0x0 - 0x7F
|
||||
rtc_factor_syn: 0x0 - 0x7FFF
|
||||
rtc_am_pm: RTC_AM, RTC_PM
|
||||
rtc_display_format: RTC_24HOUR, RTC_12HOUR
|
||||
\param[out] none
|
||||
\retval ErrStatus: ERROR or SUCCESS
|
||||
*/
|
||||
ErrStatus rtc_init(rtc_parameter_struct* rtc_initpara_struct)
|
||||
{
|
||||
ErrStatus error_status = ERROR;
|
||||
uint32_t reg_time = 0x00U, reg_date = 0x00U;
|
||||
|
||||
reg_date = (DATE_YR(rtc_initpara_struct->rtc_year) | \
|
||||
DATE_DOW(rtc_initpara_struct->rtc_day_of_week) | \
|
||||
DATE_MON(rtc_initpara_struct->rtc_month) | \
|
||||
DATE_DAY(rtc_initpara_struct->rtc_date));
|
||||
|
||||
reg_time = (rtc_initpara_struct->rtc_am_pm| \
|
||||
TIME_HR(rtc_initpara_struct->rtc_hour) | \
|
||||
TIME_MN(rtc_initpara_struct->rtc_minute) | \
|
||||
TIME_SC(rtc_initpara_struct->rtc_second));
|
||||
|
||||
/* 1st: disable the write protection */
|
||||
RTC_WPK = RTC_UNLOCK_KEY1;
|
||||
RTC_WPK = RTC_UNLOCK_KEY2;
|
||||
|
||||
/* 2nd: enter init mode */
|
||||
error_status = rtc_init_mode_enter();
|
||||
|
||||
if(ERROR != error_status){
|
||||
RTC_PSC = (uint32_t)(PSC_FACTOR_A(rtc_initpara_struct->rtc_factor_asyn)| \
|
||||
PSC_FACTOR_S(rtc_initpara_struct->rtc_factor_syn));
|
||||
|
||||
RTC_TIME = (uint32_t)reg_time;
|
||||
RTC_DATE = (uint32_t)reg_date;
|
||||
|
||||
RTC_CTL &= (uint32_t)(~RTC_CTL_CS);
|
||||
RTC_CTL |= rtc_initpara_struct->rtc_display_format;
|
||||
|
||||
/* 3rd: exit init mode */
|
||||
rtc_init_mode_exit();
|
||||
|
||||
/* 4th: wait the RSYNF flag to set */
|
||||
error_status = rtc_register_sync_wait();
|
||||
}
|
||||
|
||||
/* 5th: enable the write protection */
|
||||
RTC_WPK = RTC_LOCK_KEY;
|
||||
|
||||
return error_status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enter RTC init mode
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval ErrStatus: ERROR or SUCCESS
|
||||
*/
|
||||
ErrStatus rtc_init_mode_enter(void)
|
||||
{
|
||||
uint32_t time_index = RTC_INITM_TIMEOUT;
|
||||
uint32_t flag_status = RESET;
|
||||
ErrStatus error_status = ERROR;
|
||||
|
||||
/* check whether it has been in init mode */
|
||||
if((uint32_t)RESET == (RTC_STAT & RTC_STAT_INITF)){
|
||||
RTC_STAT |= RTC_STAT_INITM;
|
||||
|
||||
/* wait until the INITF flag to be set */
|
||||
do{
|
||||
flag_status = RTC_STAT & RTC_STAT_INITF;
|
||||
}while((--time_index > 0x00U) && ((uint32_t)RESET == flag_status));
|
||||
|
||||
if((uint32_t)RESET != flag_status){
|
||||
error_status = SUCCESS;
|
||||
}
|
||||
}else{
|
||||
error_status = SUCCESS;
|
||||
}
|
||||
return error_status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief exit RTC init mode
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void rtc_init_mode_exit(void)
|
||||
{
|
||||
RTC_STAT &= (uint32_t)(~RTC_STAT_INITM);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief wait until RTC_TIME and RTC_DATE registers are synchronized with APB clock, and the shadow
|
||||
registers are updated
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval ErrStatus: ERROR or SUCCESS
|
||||
*/
|
||||
ErrStatus rtc_register_sync_wait(void)
|
||||
{
|
||||
volatile uint32_t time_index = RTC_RSYNF_TIMEOUT;
|
||||
uint32_t flag_status = RESET;
|
||||
ErrStatus error_status = ERROR;
|
||||
|
||||
if((uint32_t)RESET == (RTC_CTL & RTC_CTL_BPSHAD)){
|
||||
/* disable the write protection */
|
||||
RTC_WPK = RTC_UNLOCK_KEY1;
|
||||
RTC_WPK = RTC_UNLOCK_KEY2;
|
||||
|
||||
/* firstly clear RSYNF flag */
|
||||
RTC_STAT &= (uint32_t)(~RTC_STAT_RSYNF);
|
||||
|
||||
/* wait until RSYNF flag to be set */
|
||||
do{
|
||||
flag_status = RTC_STAT & RTC_STAT_RSYNF;
|
||||
}while((--time_index > 0x00U) && ((uint32_t)RESET == flag_status));
|
||||
|
||||
if((uint32_t)RESET != flag_status){
|
||||
error_status = SUCCESS;
|
||||
}
|
||||
|
||||
/* enable the write protection */
|
||||
RTC_WPK = RTC_LOCK_KEY;
|
||||
}else{
|
||||
error_status = SUCCESS;
|
||||
}
|
||||
|
||||
return error_status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get current time and date
|
||||
\param[in] none
|
||||
\param[out] rtc_initpara_struct: pointer to a rtc_parameter_struct structure which contains
|
||||
parameters for initialization of the rtc peripheral
|
||||
members of the structure and the member values are shown as below:
|
||||
rtc_year: 0x0 - 0x99(BCD format)
|
||||
rtc_month: RTC_JAN, RTC_FEB, RTC_MAR, RTC_APR, RTC_MAY, RTC_JUN,
|
||||
RTC_JUL, RTC_AUG, RTC_SEP, RTC_OCT, RTC_NOV, RTC_DEC
|
||||
rtc_date: 0x1 - 0x31(BCD format)
|
||||
rtc_day_of_week: RTC_MONDAY, RTC_TUESDAY, RTC_WEDSDAY, RTC_THURSDAY
|
||||
RTC_FRIDAY, RTC_SATURDAY, RTC_SUNDAY
|
||||
rtc_hour: 0x0 - 0x12(BCD format) or 0x0 - 0x23(BCD format) depending on the rtc_display_format chose
|
||||
rtc_minute: 0x0 - 0x59(BCD format)
|
||||
rtc_second: 0x0 - 0x59(BCD format)
|
||||
rtc_factor_asyn: 0x0 - 0x7F
|
||||
rtc_factor_syn: 0x0 - 0x7FFF
|
||||
rtc_am_pm: RTC_AM, RTC_PM
|
||||
rtc_display_format: RTC_24HOUR, RTC_12HOUR
|
||||
\retval none
|
||||
*/
|
||||
void rtc_current_time_get(rtc_parameter_struct* rtc_initpara_struct)
|
||||
{
|
||||
uint32_t temp_tr = 0x00U, temp_dr = 0x00U, temp_pscr = 0x00U, temp_ctlr = 0x00U;
|
||||
|
||||
temp_tr = (uint32_t)RTC_TIME;
|
||||
temp_dr = (uint32_t)RTC_DATE;
|
||||
temp_pscr = (uint32_t)RTC_PSC;
|
||||
temp_ctlr = (uint32_t)RTC_CTL;
|
||||
|
||||
/* get current time and construct rtc_parameter_struct structure */
|
||||
rtc_initpara_struct->rtc_year = (uint8_t)GET_DATE_YR(temp_dr);
|
||||
rtc_initpara_struct->rtc_month = (uint8_t)GET_DATE_MON(temp_dr);
|
||||
rtc_initpara_struct->rtc_date = (uint8_t)GET_DATE_DAY(temp_dr);
|
||||
rtc_initpara_struct->rtc_day_of_week = (uint8_t)GET_DATE_DOW(temp_dr);
|
||||
rtc_initpara_struct->rtc_hour = (uint8_t)GET_TIME_HR(temp_tr);
|
||||
rtc_initpara_struct->rtc_minute = (uint8_t)GET_TIME_MN(temp_tr);
|
||||
rtc_initpara_struct->rtc_second = (uint8_t)GET_TIME_SC(temp_tr);
|
||||
rtc_initpara_struct->rtc_factor_asyn = (uint16_t)GET_PSC_FACTOR_A(temp_pscr);
|
||||
rtc_initpara_struct->rtc_factor_syn = (uint16_t)GET_PSC_FACTOR_S(temp_pscr);
|
||||
rtc_initpara_struct->rtc_am_pm = (uint32_t)(temp_tr & RTC_TIME_PM);
|
||||
rtc_initpara_struct->rtc_display_format = (uint32_t)(temp_ctlr & RTC_CTL_CS);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get current subsecond value
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval current subsecond value
|
||||
*/
|
||||
uint32_t rtc_subsecond_get(void)
|
||||
{
|
||||
uint32_t reg = 0x00U;
|
||||
/* if BPSHAD bit is reset, reading RTC_SS will lock RTC_TIME and RTC_DATE automatically */
|
||||
reg = (uint32_t)RTC_SS;
|
||||
/* read RTC_DATE to unlock the 3 shadow registers */
|
||||
(void) (RTC_DATE);
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure RTC alarm
|
||||
\param[in] rtc_alarm_time: pointer to a rtc_alarm_struct structure which contains
|
||||
parameters for RTC alarm configuration
|
||||
members of the structure and the member values are shown as below:
|
||||
rtc_alarm_mask: RTC_ALARM_NONE_MASK, RTC_ALARM_DATE_MASK, RTC_ALARM_HOUR_MASK
|
||||
RTC_ALARM_MINUTE_MASK, RTC_ALARM_SECOND_MASK, RTC_ALARM_ALL_MASK
|
||||
rtc_weekday_or_date: RTC_ALARM_DATE_SELECTED, RTC_ALARM_WEEKDAY_SELECTED
|
||||
rtc_alarm_day: 1) 0x1 - 0x31(BCD format) if RTC_ALARM_DATE_SELECTED is set
|
||||
2) RTC_MONDAY, RTC_TUESDAY, RTC_WEDSDAY, RTC_THURSDAY, RTC_FRIDAY,
|
||||
RTC_SATURDAY, RTC_SUNDAY if RTC_ALARM_WEEKDAY_SELECTED is set
|
||||
rtc_alarm_hour: 0x0 - 0x12(BCD format) or 0x0 - 0x23(BCD format) depending on the rtc_display_format
|
||||
rtc_alarm_minute: 0x0 - 0x59(BCD format)
|
||||
rtc_alarm_second: 0x0 - 0x59(BCD format)
|
||||
rtc_am_pm: RTC_AM, RTC_PM
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void rtc_alarm_config(rtc_alarm_struct* rtc_alarm_time)
|
||||
{
|
||||
uint32_t reg_alrm0td = 0x00U;
|
||||
|
||||
reg_alrm0td = (rtc_alarm_time->rtc_alarm_mask | \
|
||||
rtc_alarm_time->rtc_weekday_or_date | \
|
||||
rtc_alarm_time->rtc_am_pm | \
|
||||
ALRM0TD_DAY(rtc_alarm_time->rtc_alarm_day) | \
|
||||
ALRM0TD_HR(rtc_alarm_time->rtc_alarm_hour) | \
|
||||
ALRM0TD_MN(rtc_alarm_time->rtc_alarm_minute) | \
|
||||
ALRM0TD_SC(rtc_alarm_time->rtc_alarm_second));
|
||||
|
||||
/* disable the write protection */
|
||||
RTC_WPK = RTC_UNLOCK_KEY1;
|
||||
RTC_WPK = RTC_UNLOCK_KEY2;
|
||||
|
||||
RTC_ALRM0TD = (uint32_t)reg_alrm0td;
|
||||
|
||||
/* enable the write protection */
|
||||
RTC_WPK = RTC_LOCK_KEY;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure subsecond of RTC alarm
|
||||
\param[in] mask_subsecond: alarm subsecond mask
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg RTC_MASKSSC_0_14: mask alarm subsecond configuration
|
||||
\arg RTC_MASKSSC_1_14: mask RTC_ALRM0SS_SSC[14:1], and RTC_ALRM0SS_SSC[0] is to be compared
|
||||
\arg RTC_MASKSSC_2_14: mask RTC_ALRM0SS_SSC[14:2], and RTC_ALRM0SS_SSC[1:0] is to be compared
|
||||
\arg RTC_MASKSSC_3_14: mask RTC_ALRM0SS_SSC[14:3], and RTC_ALRM0SS_SSC[2:0] is to be compared
|
||||
\arg RTC_MASKSSC_4_14: mask RTC_ALRM0SS_SSC[14:4], and RTC_ALRM0SS_SSC[3:0] is to be compared
|
||||
\arg RTC_MASKSSC_5_14: mask RTC_ALRM0SS_SSC[14:5], and RTC_ALRM0SS_SSC[4:0] is to be compared
|
||||
\arg RTC_MASKSSC_6_14: mask RTC_ALRM0SS_SSC[14:6], and RTC_ALRM0SS_SSC[5:0] is to be compared
|
||||
\arg RTC_MASKSSC_7_14: mask RTC_ALRM0SS_SSC[14:7], and RTC_ALRM0SS_SSC[6:0] is to be compared
|
||||
\arg RTC_MASKSSC_8_14: mask RTC_ALRM0SS_SSC[14:8], and RTC_ALRM0SS_SSC[7:0] is to be compared
|
||||
\arg RTC_MASKSSC_9_14: mask RTC_ALRM0SS_SSC[14:9], and RTC_ALRM0SS_SSC[8:0] is to be compared
|
||||
\arg RTC_MASKSSC_10_14: mask RTC_ALRM0SS_SSC[14:10], and RTC_ALRM0SS_SSC[9:0] is to be compared
|
||||
\arg RTC_MASKSSC_11_14: mask RTC_ALRM0SS_SSC[14:11], and RTC_ALRM0SS_SSC[10:0] is to be compared
|
||||
\arg RTC_MASKSSC_12_14: mask RTC_ALRM0SS_SSC[14:12], and RTC_ALRM0SS_SSC[11:0] is to be compared
|
||||
\arg RTC_MASKSSC_13_14: mask RTC_ALRM0SS_SSC[14:13], and RTC_ALRM0SS_SSC[12:0] is to be compared
|
||||
\arg RTC_MASKSSC_14: mask RTC_ALRM0SS_SSC[14], and RTC_ALRM0SS_SSC[13:0] is to be compared
|
||||
\arg RTC_MASKSSC_NONE: mask none, and RTC_ALRM0SS_SSC[14:0] is to be compared
|
||||
\param[in] subsecond: alarm subsecond value(0x000 - 0x7FFF)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void rtc_alarm_subsecond_config(uint32_t mask_subsecond, uint32_t subsecond)
|
||||
{
|
||||
/* disable the write protection */
|
||||
RTC_WPK = RTC_UNLOCK_KEY1;
|
||||
RTC_WPK = RTC_UNLOCK_KEY2;
|
||||
|
||||
RTC_ALRM0SS = mask_subsecond | subsecond;
|
||||
|
||||
/* enable the write protection */
|
||||
RTC_WPK = RTC_LOCK_KEY;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable RTC alarm
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void rtc_alarm_enable(void)
|
||||
{
|
||||
/* disable the write protection */
|
||||
RTC_WPK = RTC_UNLOCK_KEY1;
|
||||
RTC_WPK = RTC_UNLOCK_KEY2;
|
||||
|
||||
RTC_CTL |= RTC_CTL_ALRM0EN;
|
||||
|
||||
/* enable the write protection */
|
||||
RTC_WPK = RTC_LOCK_KEY;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable RTC alarm
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval ErrStatus: ERROR or SUCCESS
|
||||
*/
|
||||
ErrStatus rtc_alarm_disable(void)
|
||||
{
|
||||
volatile uint32_t time_index = RTC_ALRM0WF_TIMEOUT;
|
||||
ErrStatus error_status = ERROR;
|
||||
uint32_t flag_status = RESET;
|
||||
|
||||
/* disable the write protection */
|
||||
RTC_WPK = RTC_UNLOCK_KEY1;
|
||||
RTC_WPK = RTC_UNLOCK_KEY2;
|
||||
|
||||
/* clear the state of alarm */
|
||||
RTC_CTL &= (uint32_t)(~RTC_CTL_ALRM0EN);
|
||||
|
||||
/* wait until ALRM0WF flag to be set after the alarm is disabled */
|
||||
do{
|
||||
flag_status = RTC_STAT & RTC_STAT_ALRM0WF;
|
||||
}while((--time_index > 0x00U) && ((uint32_t)RESET == flag_status));
|
||||
|
||||
if((uint32_t)RESET != flag_status){
|
||||
error_status = SUCCESS;
|
||||
}
|
||||
|
||||
/* enable the write protection */
|
||||
RTC_WPK = RTC_LOCK_KEY;
|
||||
|
||||
return error_status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get RTC alarm
|
||||
\param[in] none
|
||||
\param[out] rtc_alarm_time: pointer to a rtc_alarm_struct structure which contains
|
||||
parameters for RTC alarm configuration
|
||||
members of the structure and the member values are shown as below:
|
||||
rtc_alarm_mask: RTC_ALARM_NONE_MASK, RTC_ALARM_DATE_MASK, RTC_ALARM_HOUR_MASK
|
||||
RTC_ALARM_MINUTE_MASK, RTC_ALARM_SECOND_MASK, RTC_ALARM_ALL_MASK
|
||||
rtc_weekday_or_date: RTC_ALARM_DATE_SELECTED, RTC_ALARM_WEEKDAY_SELECTED
|
||||
rtc_alarm_day: 1) 0x1 - 0x31(BCD format) if RTC_ALARM_DATE_SELECTED is set
|
||||
2) RTC_MONDAY, RTC_TUESDAY, RTC_WEDSDAY, RTC_THURSDAY, RTC_FRIDAY,
|
||||
RTC_SATURDAY, RTC_SUNDAY if RTC_ALARM_WEEKDAY_SELECTED is set
|
||||
rtc_alarm_hour: 0x0 - 0x12(BCD format) or 0x0 - 0x23(BCD format) depending on the rtc_display_format
|
||||
rtc_alarm_minute: 0x0 - 0x59(BCD format)
|
||||
rtc_alarm_second: 0x0 - 0x59(BCD format)
|
||||
rtc_am_pm: RTC_AM, RTC_PM
|
||||
\retval none
|
||||
*/
|
||||
void rtc_alarm_get(rtc_alarm_struct* rtc_alarm_time)
|
||||
{
|
||||
uint32_t reg_alrm0td = 0x00U;
|
||||
|
||||
/* get the value of RTC_ALRM0TD register */
|
||||
reg_alrm0td = RTC_ALRM0TD;
|
||||
|
||||
/* get alarm parameters and construct the rtc_alarm_struct structure */
|
||||
rtc_alarm_time->rtc_alarm_mask = reg_alrm0td & RTC_ALARM_ALL_MASK;
|
||||
rtc_alarm_time->rtc_am_pm = (uint32_t)(reg_alrm0td & RTC_ALRM0TD_PM);
|
||||
rtc_alarm_time->rtc_weekday_or_date = (uint32_t)(reg_alrm0td & RTC_ALRM0TD_DOWS);
|
||||
rtc_alarm_time->rtc_alarm_day = (uint8_t)GET_ALRM0TD_DAY(reg_alrm0td);
|
||||
rtc_alarm_time->rtc_alarm_hour = (uint8_t)GET_ALRM0TD_HR(reg_alrm0td);
|
||||
rtc_alarm_time->rtc_alarm_minute = (uint8_t)GET_ALRM0TD_MN(reg_alrm0td);
|
||||
rtc_alarm_time->rtc_alarm_second = (uint8_t)GET_ALRM0TD_SC(reg_alrm0td);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get RTC alarm subsecond
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval RTC alarm subsecond value
|
||||
*/
|
||||
uint32_t rtc_alarm_subsecond_get(void)
|
||||
{
|
||||
return ((uint32_t)(RTC_ALRM0SS & RTC_ALRM0SS_SSC));
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable RTC time-stamp
|
||||
\param[in] edge: specify which edge to detect of time-stamp
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg RTC_TIMESTAMP_RISING_EDGE: rising edge is valid event edge for timestamp event
|
||||
\arg RTC_TIMESTAMP_FALLING_EDGE: falling edge is valid event edge for timestamp event
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void rtc_timestamp_enable(uint32_t edge)
|
||||
{
|
||||
uint32_t reg_ctl = 0x00U;
|
||||
|
||||
/* clear the bits to be configured in RTC_CTL */
|
||||
reg_ctl = (uint32_t)(RTC_CTL & (uint32_t)(~(RTC_CTL_TSEG | RTC_CTL_TSEN)));
|
||||
|
||||
/* new configuration */
|
||||
reg_ctl |= (uint32_t)(edge | RTC_CTL_TSEN);
|
||||
|
||||
/* disable the write protection */
|
||||
RTC_WPK = RTC_UNLOCK_KEY1;
|
||||
RTC_WPK = RTC_UNLOCK_KEY2;
|
||||
|
||||
RTC_CTL = (uint32_t)reg_ctl;
|
||||
|
||||
/* enable the write protection */
|
||||
RTC_WPK = RTC_LOCK_KEY;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable RTC time-stamp
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void rtc_timestamp_disable(void)
|
||||
{
|
||||
/* disable the write protection */
|
||||
RTC_WPK = RTC_UNLOCK_KEY1;
|
||||
RTC_WPK = RTC_UNLOCK_KEY2;
|
||||
|
||||
/* clear the TSEN bit */
|
||||
RTC_CTL &= (uint32_t)(~ RTC_CTL_TSEN);
|
||||
|
||||
/* enable the write protection */
|
||||
RTC_WPK = RTC_LOCK_KEY;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get RTC timestamp time and date
|
||||
\param[in] none
|
||||
\param[out] rtc_timestamp: pointer to a rtc_timestamp_struct structure which contains
|
||||
parameters for RTC time-stamp configuration
|
||||
members of the structure and the member values are shown as below:
|
||||
rtc_timestamp_month: RTC_JAN, RTC_FEB, RTC_MAR, RTC_APR, RTC_MAY, RTC_JUN,
|
||||
RTC_JUL, RTC_AUG, RTC_SEP, RTC_OCT, RTC_NOV, RTC_DEC
|
||||
rtc_timestamp_date: 0x1 - 0x31(BCD format)
|
||||
rtc_timestamp_day: RTC_MONDAY, RTC_TUESDAY, RTC_WEDSDAY, RTC_THURSDAY, RTC_FRIDAY,
|
||||
RTC_SATURDAY, RTC_SUNDAY if RTC_ALARM_WEEKDAY_SELECTED is set
|
||||
rtc_timestamp_hour: 0x0 - 0x12(BCD format) or 0x0 - 0x23(BCD format) depending on the rtc_display_format
|
||||
rtc_timestamp_minute: 0x0 - 0x59(BCD format)
|
||||
rtc_timestamp_second: 0x0 - 0x59(BCD format)
|
||||
rtc_am_pm: RTC_AM, RTC_PM
|
||||
\retval none
|
||||
*/
|
||||
void rtc_timestamp_get(rtc_timestamp_struct* rtc_timestamp)
|
||||
{
|
||||
uint32_t temp_tts = 0x00U, temp_dts = 0x00U;
|
||||
|
||||
/* get the value of time_stamp registers */
|
||||
temp_tts = (uint32_t)RTC_TTS;
|
||||
temp_dts = (uint32_t)RTC_DTS;
|
||||
|
||||
/* get timestamp time and construct the rtc_timestamp_struct structure */
|
||||
rtc_timestamp->rtc_am_pm = (uint32_t)(temp_tts & RTC_TTS_PM);
|
||||
rtc_timestamp->rtc_timestamp_month = (uint8_t)GET_DTS_MON(temp_dts);
|
||||
rtc_timestamp->rtc_timestamp_date = (uint8_t)GET_DTS_DAY(temp_dts);
|
||||
rtc_timestamp->rtc_timestamp_day = (uint8_t)GET_DTS_DOW(temp_dts);
|
||||
rtc_timestamp->rtc_timestamp_hour = (uint8_t)GET_TTS_HR(temp_tts);
|
||||
rtc_timestamp->rtc_timestamp_minute = (uint8_t)GET_TTS_MN(temp_tts);
|
||||
rtc_timestamp->rtc_timestamp_second = (uint8_t)GET_TTS_SC(temp_tts);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get RTC time-stamp subsecond
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval RTC time-stamp subsecond value
|
||||
*/
|
||||
uint32_t rtc_timestamp_subsecond_get(void)
|
||||
{
|
||||
return ((uint32_t)RTC_SSTS);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\brief enable RTC tamper
|
||||
\param[in] rtc_tamper: pointer to a rtc_tamper_struct structure which contains
|
||||
parameters for RTC tamper configuration
|
||||
members of the structure and the member values are shown as below:
|
||||
rtc_tamper_source: RTC_TAMPER0, RTC_TAMPER1
|
||||
rtc_tamper_trigger: RTC_TAMPER_TRIGGER_EDGE_RISING, RTC_TAMPER_TRIGGER_EDGE_FALLING
|
||||
RTC_TAMPER_TRIGGER_LEVEL_LOW, RTC_TAMPER_TRIGGER_LEVEL_HIGH
|
||||
rtc_tamper_filter: RTC_FLT_EDGE, RTC_FLT_2S, RTC_FLT_4S, RTC_FLT_8S
|
||||
rtc_tamper_sample_frequency: RTC_FREQ_DIV32768, RTC_FREQ_DIV16384, RTC_FREQ_DIV8192,
|
||||
RTC_FREQ_DIV4096, RTC_FREQ_DIV2048, RTC_FREQ_DIV1024,
|
||||
RTC_FREQ_DIV512, RTC_FREQ_DIV256
|
||||
rtc_tamper_precharge_enable: DISABLE, ENABLE
|
||||
rtc_tamper_precharge_time: RTC_PRCH_1C, RTC_PRCH_2C, RTC_PRCH_4C, RTC_PRCH_8C
|
||||
rtc_tamper_with_timestamp: DISABLE, ENABLE
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void rtc_tamper_enable(rtc_tamper_struct* rtc_tamper)
|
||||
{
|
||||
/* disable tamper */
|
||||
RTC_TAMP &= (uint32_t)~(rtc_tamper->rtc_tamper_source);
|
||||
|
||||
/* tamper filter must be used when the tamper source is voltage level detection */
|
||||
RTC_TAMP &= (uint32_t)~RTC_TAMP_FLT;
|
||||
|
||||
/* the tamper source is voltage level detection */
|
||||
if(rtc_tamper->rtc_tamper_filter != RTC_FLT_EDGE ){
|
||||
RTC_TAMP &= (uint32_t)~(RTC_TAMP_DISPU | RTC_TAMP_PRCH | RTC_TAMP_FREQ | RTC_TAMP_FLT);
|
||||
|
||||
/* check if the tamper pin need precharge, if need, then configure the precharge time */
|
||||
if(DISABLE == rtc_tamper->rtc_tamper_precharge_enable){
|
||||
RTC_TAMP |= (uint32_t)RTC_TAMP_DISPU;
|
||||
}else{
|
||||
RTC_TAMP |= (uint32_t)(rtc_tamper->rtc_tamper_precharge_time);
|
||||
}
|
||||
|
||||
RTC_TAMP |= (uint32_t)(rtc_tamper->rtc_tamper_sample_frequency);
|
||||
RTC_TAMP |= (uint32_t)(rtc_tamper->rtc_tamper_filter);
|
||||
}
|
||||
RTC_TAMP &= (uint32_t)~RTC_TAMP_TPTS;
|
||||
|
||||
if(DISABLE != rtc_tamper->rtc_tamper_with_timestamp){
|
||||
/* the tamper event also cause a time-stamp event */
|
||||
RTC_TAMP |= (uint32_t)RTC_TAMP_TPTS;
|
||||
}
|
||||
/* configure the tamper trigger */
|
||||
RTC_TAMP &= ((uint32_t)~((rtc_tamper->rtc_tamper_source) << RTC_TAMPER_TRIGGER_POS));
|
||||
if(RTC_TAMPER_TRIGGER_EDGE_RISING != rtc_tamper->rtc_tamper_trigger){
|
||||
RTC_TAMP |= (uint32_t)((rtc_tamper->rtc_tamper_source)<< RTC_TAMPER_TRIGGER_POS);
|
||||
}
|
||||
/* enable tamper */
|
||||
RTC_TAMP |= (uint32_t)(rtc_tamper->rtc_tamper_source);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable RTC tamper
|
||||
\param[in] source: specify which tamper source to be disabled
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg RTC_TAMPER0
|
||||
\arg RTC_TAMPER1
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void rtc_tamper_disable(uint32_t source)
|
||||
{
|
||||
/* disable tamper */
|
||||
RTC_TAMP &= (uint32_t)~source;
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable specified RTC interrupt
|
||||
\param[in] interrupt: specify which interrupt source to be enabled
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg RTC_INT_TIMESTAMP: timestamp interrupt
|
||||
\arg RTC_INT_ALARM: alarm interrupt
|
||||
\arg RTC_INT_TAMP: tamp interrupt
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void rtc_interrupt_enable(uint32_t interrupt)
|
||||
{
|
||||
/* disable the write protection */
|
||||
RTC_WPK = RTC_UNLOCK_KEY1;
|
||||
RTC_WPK = RTC_UNLOCK_KEY2;
|
||||
|
||||
/* enable the interrupts in RTC_CTL register */
|
||||
RTC_CTL |= (uint32_t)(interrupt & (uint32_t)~RTC_TAMP_TPIE);
|
||||
/* enable the interrupts in RTC_TAMP register */
|
||||
RTC_TAMP |= (uint32_t)(interrupt & RTC_TAMP_TPIE);
|
||||
|
||||
/* enable the write protection */
|
||||
RTC_WPK = RTC_LOCK_KEY;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disble specified RTC interrupt
|
||||
\param[in] interrupt: specify which interrupt source to be disabled
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg RTC_INT_TIMESTAMP: timestamp interrupt
|
||||
\arg RTC_INT_ALARM: alarm interrupt
|
||||
\arg RTC_INT_TAMP: tamp interrupt
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void rtc_interrupt_disable(uint32_t interrupt)
|
||||
{
|
||||
/* disable the write protection */
|
||||
RTC_WPK = RTC_UNLOCK_KEY1;
|
||||
RTC_WPK = RTC_UNLOCK_KEY2;
|
||||
|
||||
/* disable the interrupts in RTC_CTL register */
|
||||
RTC_CTL &= (uint32_t)~(interrupt & (uint32_t)~RTC_TAMP_TPIE);
|
||||
/* disable the interrupts in RTC_TAMP register */
|
||||
RTC_TAMP &= (uint32_t)~(interrupt & RTC_TAMP_TPIE);
|
||||
|
||||
/* enable the write protection */
|
||||
RTC_WPK = RTC_LOCK_KEY;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief check specified flag
|
||||
\param[in] flag: specify which flag to check
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg RTC_FLAG_RECALIBRATION: recalibration pending flag
|
||||
\arg RTC_FLAG_TAMP1: tamper 1 event flag
|
||||
\arg RTC_FLAG_TAMP0: tamper 0 event flag
|
||||
\arg RTC_FLAG_TIMESTAMP_OVERFLOW: time-stamp overflow event flag
|
||||
\arg RTC_FLAG_TIMESTAMP: time-stamp event flag
|
||||
\arg RTC_FLAG_ALARM0: alarm event flag
|
||||
\arg RTC_FLAG_INIT: init mode event flag
|
||||
\arg RTC_FLAG_RSYN: time and date registers synchronized event flag
|
||||
\arg RTC_FLAG_YCM: year parameter configured event flag
|
||||
\arg RTC_FLAG_SHIFT: shift operation pending flag
|
||||
\arg RTC_FLAG_ALARM0_WRITTEN: alarm writen available flag
|
||||
\param[out] none
|
||||
\retval FlagStatus: SET or RESET
|
||||
*/
|
||||
FlagStatus rtc_flag_get(uint32_t flag)
|
||||
{
|
||||
FlagStatus flag_state = RESET;
|
||||
|
||||
if((uint32_t)RESET != (RTC_STAT & flag)){
|
||||
flag_state = SET;
|
||||
}
|
||||
return flag_state;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief clear specified flag
|
||||
\param[in] flag: specify which flag to clear
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg RTC_FLAG_TAMP1: tamper 1 event flag
|
||||
\arg RTC_FLAG_TAMP0: tamper 0 event flag
|
||||
\arg RTC_FLAG_TIMESTAMP_OVERFLOW: time-stamp overflow event flag
|
||||
\arg RTC_FLAG_TIMESTAMP: time-stamp event flag
|
||||
\arg RTC_FLAG_ALARM0: alarm event flag
|
||||
\arg RTC_FLAG_RSYN: time and date registers synchronized event flag
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void rtc_flag_clear(uint32_t flag)
|
||||
{
|
||||
RTC_STAT &= (uint32_t)(~flag);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure rtc alternate output source
|
||||
\param[in] source: specify signal to output
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg RTC_CALIBRATION_512HZ: when the LXTAL freqency is 32768Hz and the RTC_PSC
|
||||
is the default value, output 512Hz signal
|
||||
\arg RTC_CALIBRATION_1HZ: when the LXTAL freqency is 32768Hz and the RTC_PSC
|
||||
is the default value, output 512Hz signal
|
||||
\arg RTC_ALARM_HIGH: when the alarm flag is set, the output pin is high
|
||||
\arg RTC_ALARM_LOW: when the Alarm flag is set, the output pin is low
|
||||
\param[in] mode: specify the output pin (PC13) mode when output alarm signal
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg RTC_ALARM_OUTPUT_OD: open drain mode
|
||||
\arg RTC_ALARM_OUTPUT_PP: push pull mode
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void rtc_alter_output_config(uint32_t source, uint32_t mode)
|
||||
{
|
||||
/* disable the write protection */
|
||||
RTC_WPK = RTC_UNLOCK_KEY1;
|
||||
RTC_WPK = RTC_UNLOCK_KEY2;
|
||||
|
||||
RTC_CTL &= (uint32_t)~(RTC_CTL_COEN | RTC_CTL_OS | RTC_CTL_OPOL | RTC_CTL_COS);
|
||||
|
||||
RTC_CTL |= (uint32_t)(source);
|
||||
|
||||
/* alarm output */
|
||||
if((uint32_t)RESET != (source & RTC_OS_ENABLE)){
|
||||
RTC_TAMP &= (uint32_t)~(RTC_TAMP_PC13VAL);
|
||||
RTC_TAMP |= (uint32_t)(mode);
|
||||
}
|
||||
|
||||
/* enable the write protection */
|
||||
RTC_WPK = RTC_LOCK_KEY;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure RTC calibration register
|
||||
\param[in] window: select calibration window
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg RTC_CALIBRATION_WINDOW_32S: 2exp20 RTCCLK cycles, 32s if RTCCLK = 32768 Hz
|
||||
\arg RTC_CALIBRATION_WINDOW_16S: 2exp19 RTCCLK cycles, 16s if RTCCLK = 32768 Hz
|
||||
\arg RTC_CALIBRATION_WINDOW_8S: 2exp18 RTCCLK cycles, 8s if RTCCLK = 32768 Hz
|
||||
\param[in] plus: add RTC clock or not
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg RTC_CALIBRATION_PLUS_SET: add one RTC clock every 2048 rtc clock
|
||||
\arg RTC_CALIBRATION_PLUS_RESET: no effect
|
||||
\param[in] minus: the RTC clock to minus during the calibration window(0x0 - 0x1FF)
|
||||
\param[out] none
|
||||
\retval ErrStatus: ERROR or SUCCESS
|
||||
*/
|
||||
ErrStatus rtc_calibration_config(uint32_t window, uint32_t plus, uint32_t minus)
|
||||
{
|
||||
uint32_t time_index = RTC_HRFC_TIMEOUT;
|
||||
ErrStatus error_status = ERROR;
|
||||
uint32_t flag_status = RESET;
|
||||
|
||||
/* disable the write protection */
|
||||
RTC_WPK = RTC_UNLOCK_KEY1;
|
||||
RTC_WPK = RTC_UNLOCK_KEY2;
|
||||
|
||||
/* check if a calibration operation is ongoing */
|
||||
do{
|
||||
flag_status = RTC_STAT & RTC_STAT_SCPF;
|
||||
}while((--time_index > 0x00U) && ((uint32_t)RESET != flag_status));
|
||||
|
||||
if((uint32_t)RESET == flag_status){
|
||||
RTC_HRFC = (uint32_t)(window | plus | HRFC_CMSK(minus));
|
||||
error_status = SUCCESS;
|
||||
}
|
||||
|
||||
/* enable the write protection */
|
||||
RTC_WPK = RTC_LOCK_KEY;
|
||||
|
||||
return error_status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief adjust the daylight saving time by adding or substracting one hour from the current time
|
||||
\param[in] operation: hour ajustment operation
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg RTC_CTL_A1H: add one hour
|
||||
\arg RTC_CTL_S1H: substract one hour
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void rtc_hour_adjust(uint32_t operation)
|
||||
{
|
||||
/* disable the write protection */
|
||||
RTC_WPK = RTC_UNLOCK_KEY1;
|
||||
RTC_WPK = RTC_UNLOCK_KEY2;
|
||||
|
||||
RTC_CTL |= (uint32_t)(operation);
|
||||
|
||||
/* enable the write protection */
|
||||
RTC_WPK = RTC_LOCK_KEY;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief adjust RTC second or subsecond value of current time
|
||||
\param[in] add: add 1s to current time or not
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg RTC_SHIFT_ADD1S_RESET: no effect
|
||||
\arg RTC_SHIFT_ADD1S_SET: add 1s to current time
|
||||
\param[in] minus: number of subsecond to minus from current time(0x0 - 0x7FFF)
|
||||
\param[out] none
|
||||
\retval ErrStatus: ERROR or SUCCESS
|
||||
*/
|
||||
ErrStatus rtc_second_adjust(uint32_t add, uint32_t minus)
|
||||
{
|
||||
uint32_t time_index = RTC_SHIFTCTL_TIMEOUT;
|
||||
ErrStatus error_status = ERROR;
|
||||
uint32_t flag_status = RESET;
|
||||
uint32_t temp=0U;
|
||||
|
||||
/* disable the write protection */
|
||||
RTC_WPK = RTC_UNLOCK_KEY1;
|
||||
RTC_WPK = RTC_UNLOCK_KEY2;
|
||||
|
||||
/* check if a shift operation is ongoing */
|
||||
do{
|
||||
flag_status = RTC_STAT & RTC_STAT_SOPF;
|
||||
}while((--time_index > 0x00U) && ((uint32_t)RESET != flag_status));
|
||||
|
||||
temp = RTC_CTL & RTC_CTL_REFEN;
|
||||
/* check if the function of reference clock detection is disabled */
|
||||
if(((uint32_t)RESET == flag_status) && (RESET == temp)){
|
||||
RTC_SHIFTCTL = (uint32_t)(add | SHIFTCTL_SFS(minus));
|
||||
error_status = rtc_register_sync_wait();
|
||||
}
|
||||
|
||||
/* enable the write protection */
|
||||
RTC_WPK = RTC_LOCK_KEY;
|
||||
|
||||
return error_status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable RTC bypass shadow registers function
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void rtc_bypass_shadow_enable(void)
|
||||
{
|
||||
/* disable the write protection */
|
||||
RTC_WPK = RTC_UNLOCK_KEY1;
|
||||
RTC_WPK = RTC_UNLOCK_KEY2;
|
||||
|
||||
RTC_CTL |= (uint8_t)RTC_CTL_BPSHAD;
|
||||
|
||||
/* enable the write protection */
|
||||
RTC_WPK = RTC_LOCK_KEY;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable RTC bypass shadow registers function
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void rtc_bypass_shadow_disable(void)
|
||||
{
|
||||
/* disable the write protection */
|
||||
RTC_WPK = RTC_UNLOCK_KEY1;
|
||||
RTC_WPK = RTC_UNLOCK_KEY2;
|
||||
|
||||
RTC_CTL &= (uint8_t)~RTC_CTL_BPSHAD;
|
||||
|
||||
/* enable the write protection */
|
||||
RTC_WPK = RTC_LOCK_KEY;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable RTC reference clock detection function
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval ErrStatus: ERROR or SUCCESS
|
||||
*/
|
||||
ErrStatus rtc_refclock_detection_enable(void)
|
||||
{
|
||||
ErrStatus error_status = ERROR;
|
||||
|
||||
/* disable the write protection */
|
||||
RTC_WPK = RTC_UNLOCK_KEY1;
|
||||
RTC_WPK = RTC_UNLOCK_KEY2;
|
||||
|
||||
/* enter init mode */
|
||||
error_status = rtc_init_mode_enter();
|
||||
|
||||
if(ERROR != error_status){
|
||||
RTC_CTL |= (uint32_t)RTC_CTL_REFEN;
|
||||
/* exit init mode */
|
||||
rtc_init_mode_exit();
|
||||
}
|
||||
|
||||
/* enable the write protection */
|
||||
RTC_WPK = RTC_LOCK_KEY;
|
||||
|
||||
return error_status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable RTC reference clock detection function
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval ErrStatus: ERROR or SUCCESS
|
||||
*/
|
||||
ErrStatus rtc_refclock_detection_disable(void)
|
||||
{
|
||||
ErrStatus error_status = ERROR;
|
||||
|
||||
/* disable the write protection */
|
||||
RTC_WPK = RTC_UNLOCK_KEY1;
|
||||
RTC_WPK = RTC_UNLOCK_KEY2;
|
||||
|
||||
/* enter init mode */
|
||||
error_status = rtc_init_mode_enter();
|
||||
|
||||
if(ERROR != error_status){
|
||||
RTC_CTL &= (uint32_t)~RTC_CTL_REFEN;
|
||||
/* exit init mode */
|
||||
rtc_init_mode_exit();
|
||||
}
|
||||
|
||||
/* enable the write protection */
|
||||
RTC_WPK = RTC_LOCK_KEY;
|
||||
|
||||
return error_status;
|
||||
}
|
965
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_spi.c
Normal file
965
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_spi.c
Normal file
@@ -0,0 +1,965 @@
|
||||
/*!
|
||||
\file gd32e23x_spi.c
|
||||
\brief SPI driver
|
||||
|
||||
\version 2024-02-22, V2.1.0, firmware for GD32E23x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2024, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "gd32e23x_spi.h"
|
||||
|
||||
/* SPI/I2S parameter initialization mask */
|
||||
#define SPI_INIT_MASK ((uint32_t)0x00003040U) /*!< SPI0 parameter initialization mask */
|
||||
#define SPI_FIFO_INIT_MASK1 ((uint32_t)0x00003840U) /*!< SPI1 parameter initialization mask1 */
|
||||
#define SPI_FIFO_INIT_MASK2 ((uint32_t)0x0000F0FFU) /*!< SPI1 parameter initialization mask2*/
|
||||
#define I2S_INIT_MASK ((uint32_t)0x0000F047U) /*!< I2S parameter initialization mask */
|
||||
|
||||
#define SPI_FRAMESIZE_MASK ((uint32_t)0x00000800U) /*!< SPI0 frame size mask */
|
||||
#define SPI_BYTEN_MASK ((uint32_t)0x00001000U) /*!< SPI1 access to FIFO mask */
|
||||
#define SPI_TXLVL_EMPTY_MASK ((uint32_t)0x00001800U) /*!< SPI1 TXFIFO empty mask */
|
||||
#define SPI_RXLVL_EMPTY_MASK ((uint32_t)0x00000600U) /*!< SPI1 RXFIFO empty mask */
|
||||
|
||||
/* I2S clock source selection, multiplication and division mask */
|
||||
#define SPI_I2SPSC_RESET ((uint32_t)0x00000002U) /*!< I2S clock prescaler register reset value */
|
||||
|
||||
/*!
|
||||
\brief reset SPI and I2S
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_i2s_deinit(uint32_t spi_periph)
|
||||
{
|
||||
switch(spi_periph) {
|
||||
case SPI0:
|
||||
/* reset SPI0 and I2S0 */
|
||||
rcu_periph_reset_enable(RCU_SPI0RST);
|
||||
rcu_periph_reset_disable(RCU_SPI0RST);
|
||||
break;
|
||||
case SPI1:
|
||||
/* reset SPI1 */
|
||||
rcu_periph_reset_enable(RCU_SPI1RST);
|
||||
rcu_periph_reset_disable(RCU_SPI1RST);
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief initialize the parameters of SPI structure with the default values
|
||||
\param[in] none
|
||||
\param[out] spi_parameter_struct: the initialized structure spi_parameter_struct pointer
|
||||
\retval none
|
||||
*/
|
||||
void spi_struct_para_init(spi_parameter_struct *spi_struct)
|
||||
{
|
||||
/* configure the SPI structure with the default values */
|
||||
spi_struct->device_mode = SPI_SLAVE;
|
||||
spi_struct->trans_mode = SPI_TRANSMODE_FULLDUPLEX;
|
||||
spi_struct->frame_size = SPI_FRAMESIZE_8BIT;
|
||||
spi_struct->nss = SPI_NSS_HARD;
|
||||
spi_struct->endian = SPI_ENDIAN_MSB;
|
||||
spi_struct->clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
|
||||
spi_struct->prescale = SPI_PSC_2;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief initialize SPI parameters
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[in] spi_struct: SPI parameter initialization stuct members of the structure
|
||||
and the member values are shown as below:
|
||||
device_mode: SPI_MASTER, SPI_SLAVE
|
||||
trans_mode: SPI_TRANSMODE_FULLDUPLEX, SPI_TRANSMODE_RECEIVEONLY,
|
||||
SPI_TRANSMODE_BDRECEIVE, SPI_TRANSMODE_BDTRANSMIT
|
||||
frame_size: SPI_FRAMESIZE_4BIT, SPI_FRAMESIZE_5BIT
|
||||
SPI_FRAMESIZE_6BIT, SPI_FRAMESIZE_7BIT
|
||||
SPI_FRAMESIZE_8BIT, SPI_FRAMESIZE_9BIT
|
||||
SPI_FRAMESIZE_10BIT, SPI_FRAMESIZE_11BIT
|
||||
SPI_FRAMESIZE_12BIT, SPI_FRAMESIZE_13BIT
|
||||
SPI_FRAMESIZE_14BIT, SPI_FRAMESIZE_15BIT
|
||||
SPI_FRAMESIZE_16BIT
|
||||
nss: SPI_NSS_SOFT, SPI_NSS_HARD
|
||||
endian: SPI_ENDIAN_MSB, SPI_ENDIAN_LSB
|
||||
clock_polarity_phase: SPI_CK_PL_LOW_PH_1EDGE, SPI_CK_PL_HIGH_PH_1EDGE
|
||||
SPI_CK_PL_LOW_PH_2EDGE, SPI_CK_PL_HIGH_PH_2EDGE
|
||||
prescale: SPI_PSC_n (n=2,4,8,16,32,64,128,256)
|
||||
\param[out] none
|
||||
\retval ErrStatus: ERROR or SUCCESS
|
||||
*/
|
||||
ErrStatus spi_init(uint32_t spi_periph, spi_parameter_struct *spi_struct)
|
||||
{
|
||||
uint32_t reg1 = 0, reg2 = 0U, reg3 = 0U;
|
||||
|
||||
reg1 = SPI_CTL0(spi_periph);
|
||||
reg1 &= SPI_INIT_MASK;
|
||||
|
||||
reg2 = SPI_CTL0(spi_periph);
|
||||
reg2 &= SPI_FIFO_INIT_MASK1;
|
||||
|
||||
reg3 = SPI_CTL1(spi_periph);
|
||||
reg3 &= SPI_FIFO_INIT_MASK2;
|
||||
|
||||
if(SPI0 == spi_periph) {
|
||||
/* select SPI as master or slave */
|
||||
reg1 |= spi_struct->device_mode;
|
||||
/* select SPI transfer mode */
|
||||
reg1 |= spi_struct->trans_mode;
|
||||
/* select SPI NSS use hardware or software */
|
||||
reg1 |= spi_struct->nss;
|
||||
/* select SPI LSB or MSB */
|
||||
reg1 |= spi_struct->endian;
|
||||
/* select SPI polarity and phase */
|
||||
reg1 |= spi_struct->clock_polarity_phase;
|
||||
/* select SPI prescaler to adjust transmit speed */
|
||||
reg1 |= spi_struct->prescale;
|
||||
/* select SPI frame size */
|
||||
/* check SPI0 frame size is 8bits/16bits or not*/
|
||||
if((SPI_FRAMESIZE_8BIT != spi_struct->frame_size) && (SPI_FRAMESIZE_16BIT != spi_struct->frame_size)) {
|
||||
return ERROR;
|
||||
} else {
|
||||
reg1 |= (spi_struct->frame_size & SPI_FRAMESIZE_MASK);
|
||||
}
|
||||
|
||||
/* write to SPI_CTL0 register */
|
||||
SPI_CTL0(spi_periph) = (uint32_t)reg1;
|
||||
|
||||
} else {
|
||||
/* select SPI as master or slave */
|
||||
reg2 |= spi_struct->device_mode;
|
||||
/* select SPI transfer mode */
|
||||
reg2 |= spi_struct->trans_mode;
|
||||
/* select SPI NSS use hardware or software */
|
||||
reg2 |= spi_struct->nss;
|
||||
/* select SPI LSB or MSB */
|
||||
reg2 |= spi_struct->endian;
|
||||
/* select SPI polarity and phase */
|
||||
reg2 |= spi_struct->clock_polarity_phase;
|
||||
/* select SPI prescaler to adjust transmit speed */
|
||||
reg2 |= spi_struct->prescale;
|
||||
/* write to SPI_CTL0 register */
|
||||
SPI_CTL0(spi_periph) = (uint32_t)reg2;
|
||||
|
||||
/* select SPI data size */
|
||||
reg3 |= spi_struct->frame_size;
|
||||
/* write to SPI_CTL0 register */
|
||||
SPI_CTL1(spi_periph) = (uint32_t)reg3;
|
||||
}
|
||||
|
||||
/* select SPI mode */
|
||||
SPI_I2SCTL(spi_periph) &= (uint32_t)(~SPI_I2SCTL_I2SSEL);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable SPI
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_enable(uint32_t spi_periph)
|
||||
{
|
||||
SPI_CTL0(spi_periph) |= (uint32_t)SPI_CTL0_SPIEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable SPI
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_disable(uint32_t spi_periph)
|
||||
{
|
||||
SPI_CTL0(spi_periph) &= (uint32_t)(~SPI_CTL0_SPIEN);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief initialize I2S parameters
|
||||
\param[in] spi_periph: SPIx(x=0)
|
||||
\param[in] mode: I2S operation mode
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2S_MODE_SLAVETX: I2S slave transmit mode
|
||||
\arg I2S_MODE_SLAVERX: I2S slave receive mode
|
||||
\arg I2S_MODE_MASTERTX: I2S master transmit mode
|
||||
\arg I2S_MODE_MASTERRX: I2S master receive mode
|
||||
\param[in] standard: I2S standard
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2S_STD_PHILLIPS: I2S phillips standard
|
||||
\arg I2S_STD_MSB: I2S MSB standard
|
||||
\arg I2S_STD_LSB: I2S LSB standard
|
||||
\arg I2S_STD_PCMSHORT: I2S PCM short standard
|
||||
\arg I2S_STD_PCMLONG: I2S PCM long standard
|
||||
\param[in] ckpl: I2S idle state clock polarity
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2S_CKPL_LOW: I2S clock polarity low level
|
||||
\arg I2S_CKPL_HIGH: I2S clock polarity high level
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2s_init(uint32_t spi_periph, uint32_t mode, uint32_t standard, uint32_t ckpl)
|
||||
{
|
||||
uint32_t reg = 0U;
|
||||
reg = SPI_I2SCTL(spi_periph);
|
||||
reg &= I2S_INIT_MASK;
|
||||
|
||||
/* enable I2S mode */
|
||||
reg |= (uint32_t)SPI_I2SCTL_I2SSEL;
|
||||
/* select I2S mode */
|
||||
reg |= (uint32_t)mode;
|
||||
/* select I2S standard */
|
||||
reg |= (uint32_t)standard;
|
||||
/* select I2S polarity */
|
||||
reg |= (uint32_t)ckpl;
|
||||
|
||||
/* write to SPI_I2SCTL register */
|
||||
SPI_I2SCTL(spi_periph) = (uint32_t)reg;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure I2S prescaler
|
||||
\param[in] spi_periph: SPIx(x=0)
|
||||
\param[in] audiosample: I2S audio sample rate
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2S_AUDIOSAMPLE_8K: audio sample rate is 8KHz
|
||||
\arg I2S_AUDIOSAMPLE_11K: audio sample rate is 11KHz
|
||||
\arg I2S_AUDIOSAMPLE_16K: audio sample rate is 16KHz
|
||||
\arg I2S_AUDIOSAMPLE_22K: audio sample rate is 22KHz
|
||||
\arg I2S_AUDIOSAMPLE_32K: audio sample rate is 32KHz
|
||||
\arg I2S_AUDIOSAMPLE_44K: audio sample rate is 44KHz
|
||||
\arg I2S_AUDIOSAMPLE_48K: audio sample rate is 48KHz
|
||||
\arg I2S_AUDIOSAMPLE_96K: audio sample rate is 96KHz
|
||||
\arg I2S_AUDIOSAMPLE_192K: audio sample rate is 192KHz
|
||||
\param[in] frameformat: I2S data length and channel length
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2S_FRAMEFORMAT_DT16B_CH16B: I2S data length is 16 bit and channel length is 16 bit
|
||||
\arg I2S_FRAMEFORMAT_DT16B_CH32B: I2S data length is 16 bit and channel length is 32 bit
|
||||
\arg I2S_FRAMEFORMAT_DT24B_CH32B: I2S data length is 24 bit and channel length is 32 bit
|
||||
\arg I2S_FRAMEFORMAT_DT32B_CH32B: I2S data length is 32 bit and channel length is 32 bit
|
||||
\param[in] mckout: I2S master clock output
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg I2S_MCKOUT_ENABLE: enable I2S master clock output
|
||||
\arg I2S_MCKOUT_DISABLE: disable 2S master clock output
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2s_psc_config(uint32_t spi_periph, uint32_t audiosample, uint32_t frameformat, uint32_t mckout)
|
||||
{
|
||||
uint32_t i2sdiv = 2U, i2sof = 0U;
|
||||
uint32_t clks = 0U;
|
||||
uint32_t i2sclock = 0U;
|
||||
|
||||
/* deinitialize SPI_I2SPSC register */
|
||||
SPI_I2SPSC(spi_periph) = SPI_I2SPSC_RESET;
|
||||
|
||||
/* get system clock */
|
||||
i2sclock = rcu_clock_freq_get(CK_SYS);
|
||||
|
||||
/* configure the prescaler depending on the mclk output state, the frame format and audio sample rate */
|
||||
if(I2S_MCKOUT_ENABLE == mckout) {
|
||||
clks = (uint32_t)(((i2sclock / 256U) * 10U) / audiosample);
|
||||
} else {
|
||||
if(I2S_FRAMEFORMAT_DT16B_CH16B == frameformat) {
|
||||
clks = (uint32_t)(((i2sclock / 32U) * 10U) / audiosample);
|
||||
} else {
|
||||
clks = (uint32_t)(((i2sclock / 64U) * 10U) / audiosample);
|
||||
}
|
||||
}
|
||||
|
||||
/* remove the floating point */
|
||||
clks = (clks + 5U) / 10U;
|
||||
i2sof = (clks & 0x00000001U);
|
||||
i2sdiv = ((clks - i2sof) / 2U);
|
||||
i2sof = (i2sof << 8U);
|
||||
|
||||
/* set the default values */
|
||||
if((i2sdiv < 2U) || (i2sdiv > 255U)) {
|
||||
i2sdiv = 2U;
|
||||
i2sof = 0U;
|
||||
}
|
||||
|
||||
/* configure SPI_I2SPSC */
|
||||
SPI_I2SPSC(spi_periph) = (uint32_t)(i2sdiv | i2sof | mckout);
|
||||
|
||||
/* clear SPI_I2SCTL_DTLEN and SPI_I2SCTL_CHLEN bits */
|
||||
SPI_I2SCTL(spi_periph) &= (uint32_t)(~(SPI_I2SCTL_DTLEN | SPI_I2SCTL_CHLEN));
|
||||
|
||||
/* configure data frame format */
|
||||
SPI_I2SCTL(spi_periph) |= (uint32_t)frameformat;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\brief enable I2S
|
||||
\param[in] spi_periph: SPIx(x=0)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2s_enable(uint32_t spi_periph)
|
||||
{
|
||||
SPI_I2SCTL(spi_periph) |= (uint32_t)SPI_I2SCTL_I2SEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable I2S
|
||||
\param[in] spi_periph: SPIx(x=0)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2s_disable(uint32_t spi_periph)
|
||||
{
|
||||
SPI_I2SCTL(spi_periph) &= (uint32_t)(~SPI_I2SCTL_I2SEN);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable SPI NSS output
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_nss_output_enable(uint32_t spi_periph)
|
||||
{
|
||||
SPI_CTL1(spi_periph) |= (uint32_t)SPI_CTL1_NSSDRV;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable SPI NSS output
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_nss_output_disable(uint32_t spi_periph)
|
||||
{
|
||||
SPI_CTL1(spi_periph) &= (uint32_t)(~SPI_CTL1_NSSDRV);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief SPI NSS pin high level in software mode
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_nss_internal_high(uint32_t spi_periph)
|
||||
{
|
||||
SPI_CTL0(spi_periph) |= (uint32_t)SPI_CTL0_SWNSS;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief SPI NSS pin low level in software mode
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_nss_internal_low(uint32_t spi_periph)
|
||||
{
|
||||
SPI_CTL0(spi_periph) &= (uint32_t)(~SPI_CTL0_SWNSS);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable SPI DMA send or receive
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[in] dma: SPI DMA mode
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SPI_DMA_TRANSMIT: SPI transmit data using DMA
|
||||
\arg SPI_DMA_RECEIVE: SPI receive data using DMA
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_dma_enable(uint32_t spi_periph, uint8_t dma)
|
||||
{
|
||||
if(SPI_DMA_TRANSMIT == dma) {
|
||||
SPI_CTL1(spi_periph) |= (uint32_t)SPI_CTL1_DMATEN;
|
||||
} else {
|
||||
SPI_CTL1(spi_periph) |= (uint32_t)SPI_CTL1_DMAREN;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable SPI DMA send or receive
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[in] dma: SPI DMA mode
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SPI_DMA_TRANSMIT: SPI transmit data using DMA
|
||||
\arg SPI_DMA_RECEIVE: SPI receive data using DMA
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_dma_disable(uint32_t spi_periph, uint8_t dma)
|
||||
{
|
||||
if(SPI_DMA_TRANSMIT == dma) {
|
||||
SPI_CTL1(spi_periph) &= (uint32_t)(~SPI_CTL1_DMATEN);
|
||||
} else {
|
||||
SPI_CTL1(spi_periph) &= (uint32_t)(~SPI_CTL1_DMAREN);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure SPI total number of data to be transmitted by DMA is odd or not
|
||||
\param[in] spi_periph: SPIx(x=1)
|
||||
\param[in] odd: odd bytes in TX DMA channel
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SPI_TXDMA_EVEN: number of byte in TX DMA channel is even
|
||||
\arg SPI_TXDMA_ODD: number of byte in TX DMA channel is odd
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_transmit_odd_config(uint32_t spi_periph, uint16_t odd)
|
||||
{
|
||||
/* clear SPI_CTL1_TXDMA_ODD bit */
|
||||
SPI_CTL1(spi_periph) &= (uint32_t)(~SPI_CTL1_TXDMA_ODD);
|
||||
/* configure SPI_CTL1_TXDMA_ODD bit */
|
||||
SPI_CTL1(spi_periph) |= (uint32_t)odd;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure SPI total number of data to be received by DMA is odd or not
|
||||
\param[in] spi_periph: SPIx(x=1)
|
||||
\param[in] odd: odd bytes in RX DMA channel
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SPI_RXDMA_EVEN: number of bytes in RX DMA channel is even
|
||||
\arg SPI_RXDMA_ODD: number of bytes in RX DMA channel is odd
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_receive_odd_config(uint32_t spi_periph, uint16_t odd)
|
||||
{
|
||||
/* clear SPI_CTL1_RXDMA_ODD bit */
|
||||
SPI_CTL1(spi_periph) &= (uint32_t)(~SPI_CTL1_RXDMA_ODD);
|
||||
/* configure SPI_CTL1_RXDMA_ODD bit */
|
||||
SPI_CTL1(spi_periph) |= (uint32_t)odd;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure SPI data frame format
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[in] frame_format: SPI frame size
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SPI_FRAMESIZE_xBIT(x=4,5..16, for SPI1, x=8,16, for SPI0):SPI frame size is x bits
|
||||
\param[out] none
|
||||
\retval ErrStatus: ERROR or SUCCESS
|
||||
*/
|
||||
ErrStatus spi_i2s_data_frame_format_config(uint32_t spi_periph, uint16_t frame_format)
|
||||
{
|
||||
uint32_t reg;
|
||||
if(SPI0 == spi_periph) {
|
||||
/* check SPI0 frame size is 8bits/16bits or not*/
|
||||
if((SPI_FRAMESIZE_8BIT != frame_format) && (SPI_FRAMESIZE_16BIT != frame_format)) {
|
||||
return ERROR;
|
||||
} else {
|
||||
/* clear SPI_CTL0_FF16 bit */
|
||||
SPI_CTL0(spi_periph) &= (uint32_t)(~SPI_CTL0_FF16);
|
||||
/* configure SPI_CTL0_FF16 bit */
|
||||
SPI_CTL0(spi_periph) |= ((uint32_t)frame_format & SPI_FRAMESIZE_MASK);
|
||||
}
|
||||
} else {
|
||||
reg = SPI_CTL1(spi_periph);
|
||||
/* clear SPI_CTL1_DZ bits */
|
||||
reg &= (uint32_t)(~SPI_CTL1_DZ);
|
||||
reg |= (uint32_t)frame_format;
|
||||
/* configure SPI_CTL1_DZ bits */
|
||||
SPI_CTL1(spi_periph) = reg;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure SPI access size to FIFO(8-bit or 16-bit)
|
||||
\param[in] spi_periph: SPIx(x=1)
|
||||
\param[in] fifo_access_size: byte access enable
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SPI_HALFWORD_ACCESS: half-word access to FIFO
|
||||
\arg SPI_BYTE_ACCESS: byte access to FIFO
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_fifo_access_size_config(uint32_t spi_periph, uint16_t fifo_access_size)
|
||||
{
|
||||
/* clear SPI_CTL1_BYTEN bit */
|
||||
SPI_CTL1(spi_periph) &= (uint32_t)(~SPI_CTL1_BYTEN);
|
||||
/* confige SPI_CTL1_BYTEN bit */
|
||||
SPI_CTL1(spi_periph) |= (uint32_t)fifo_access_size;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure SPI bidirectional transfer direction
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[in] transfer_direction: SPI transfer direction
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SPI_BIDIRECTIONAL_TRANSMIT: SPI work in transmit-only mode
|
||||
\arg SPI_BIDIRECTIONAL_RECEIVE: SPI work in receive-only mode
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_bidirectional_transfer_config(uint32_t spi_periph, uint32_t transfer_direction)
|
||||
{
|
||||
if(SPI_BIDIRECTIONAL_TRANSMIT == transfer_direction) {
|
||||
/* set the transmit-only mode */
|
||||
SPI_CTL0(spi_periph) |= (uint32_t)SPI_BIDIRECTIONAL_TRANSMIT;
|
||||
} else {
|
||||
/* set the receive-only mode */
|
||||
SPI_CTL0(spi_periph) &= SPI_BIDIRECTIONAL_RECEIVE;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief SPI transmit data
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[in] data: 16-bit data
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_i2s_data_transmit(uint32_t spi_periph, uint16_t data)
|
||||
{
|
||||
uint32_t reg, byten;
|
||||
if(SPI0 == spi_periph) {
|
||||
SPI_DATA(spi_periph) = (uint32_t)data;
|
||||
} else {
|
||||
/* get the access size to FIFO */
|
||||
byten = SPI_CTL1(spi_periph) & SPI_BYTEN_MASK;
|
||||
if(RESET != byten) {
|
||||
reg = spi_periph + 0x0CU;
|
||||
*(uint8_t *)(reg) = (uint8_t)data;
|
||||
} else {
|
||||
SPI_DATA(spi_periph) = (uint16_t)data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief SPI receive data
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[out] none
|
||||
\retval 16-bit data
|
||||
*/
|
||||
uint16_t spi_i2s_data_receive(uint32_t spi_periph)
|
||||
{
|
||||
uint32_t reg, byten;
|
||||
if(SPI0 == spi_periph) {
|
||||
return ((uint16_t)SPI_DATA(spi_periph));
|
||||
} else {
|
||||
/* get the access size to FIFO */
|
||||
byten = SPI_CTL1(spi_periph) & SPI_BYTEN_MASK;
|
||||
if(RESET != byten) {
|
||||
reg = spi_periph + 0x0CU;
|
||||
return (uint16_t)(*(uint8_t *)(reg));
|
||||
} else {
|
||||
return ((uint16_t)SPI_DATA(spi_periph));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief clear SPI/I2S format error flag status
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[in] flag: SPI/I2S frame format error flag
|
||||
\arg SPI_FLAG_FERR: only for SPI work in TI mode
|
||||
\arg I2S_FLAG_FERR: for I2S
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_i2s_format_error_clear(uint32_t spi_periph, uint32_t flag)
|
||||
{
|
||||
SPI_STAT(spi_periph) = (uint32_t)(~flag);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set SPI CRC polynomial
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[in] crc_poly: CRC polynomial value
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_crc_polynomial_set(uint32_t spi_periph, uint16_t crc_poly)
|
||||
{
|
||||
/* enable SPI CRC */
|
||||
SPI_CTL0(spi_periph) |= (uint32_t)SPI_CTL0_CRCEN;
|
||||
/* set SPI CRC polynomial */
|
||||
SPI_CRCPOLY(spi_periph) = (uint32_t)crc_poly;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get SPI CRC polynomial
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[out] none
|
||||
\retval 16-bit CRC polynomial
|
||||
*/
|
||||
uint16_t spi_crc_polynomial_get(uint32_t spi_periph)
|
||||
{
|
||||
return ((uint16_t)SPI_CRCPOLY(spi_periph));
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set CRC length
|
||||
\param[in] spi_periph: SPIx(x=1)
|
||||
\param[in] crc_length: CRC length
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SPI_CRC_8BIT: CRC length is 8 bits
|
||||
\arg SPI_CRC_16BIT: CRC length is 16 bits
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_crc_length_set(uint32_t spi_periph, uint16_t crc_length)
|
||||
{
|
||||
/* clear SPI_CTL0_CRCL bit */
|
||||
SPI_CTL0(spi_periph) &= (uint32_t)(~SPI_CTL0_CRCL);
|
||||
/* confige SPI_CTL0_CRCL bit */
|
||||
SPI_CTL0(spi_periph) |= (uint32_t)crc_length;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief turn on CRC function
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_crc_on(uint32_t spi_periph)
|
||||
{
|
||||
SPI_CTL0(spi_periph) |= (uint32_t)SPI_CTL0_CRCEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief turn off CRC function
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_crc_off(uint32_t spi_periph)
|
||||
{
|
||||
SPI_CTL0(spi_periph) &= (uint32_t)(~SPI_CTL0_CRCEN);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief SPI next data is CRC value
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_crc_next(uint32_t spi_periph)
|
||||
{
|
||||
SPI_CTL0(spi_periph) |= (uint32_t)SPI_CTL0_CRCNT;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get SPI CRC send value or receive value
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[in] crc: SPI crc value
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SPI_CRC_TX: get transmit crc value
|
||||
\arg SPI_CRC_RX: get receive crc value
|
||||
\param[out] none
|
||||
\retval 16-bit CRC value
|
||||
*/
|
||||
uint16_t spi_crc_get(uint32_t spi_periph, uint8_t crc)
|
||||
{
|
||||
if(SPI_CRC_TX == crc) {
|
||||
return ((uint16_t)(SPI_TCRC(spi_periph)));
|
||||
} else {
|
||||
return ((uint16_t)(SPI_RCRC(spi_periph)));
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief clear SPI CRC error flag status
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_crc_error_clear(uint32_t spi_periph)
|
||||
{
|
||||
SPI_STAT(spi_periph) = (uint32_t)(~SPI_FLAG_CRCERR);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable SPI TI mode
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_ti_mode_enable(uint32_t spi_periph)
|
||||
{
|
||||
SPI_CTL1(spi_periph) |= (uint32_t)SPI_CTL1_TMOD;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable SPI TI mode
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_ti_mode_disable(uint32_t spi_periph)
|
||||
{
|
||||
SPI_CTL1(spi_periph) &= (uint32_t)(~SPI_CTL1_TMOD);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable SPI NSS pulse mode
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_nssp_mode_enable(uint32_t spi_periph)
|
||||
{
|
||||
SPI_CTL1(spi_periph) |= (uint32_t)SPI_CTL1_NSSP;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable SPI NSS pulse mode
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_nssp_mode_disable(uint32_t spi_periph)
|
||||
{
|
||||
SPI_CTL1(spi_periph) &= (uint32_t)(~SPI_CTL1_NSSP);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable quad wire SPI
|
||||
\param[in] spi_periph: SPIx(x=1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_quad_enable(uint32_t spi_periph)
|
||||
{
|
||||
SPI_QCTL(spi_periph) |= (uint32_t)SPI_QCTL_QMOD;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable quad wire SPI
|
||||
\param[in] spi_periph: SPIx(x=1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_quad_disable(uint32_t spi_periph)
|
||||
{
|
||||
SPI_QCTL(spi_periph) &= (uint32_t)(~SPI_QCTL_QMOD);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable quad wire SPI write
|
||||
\param[in] spi_periph: SPIx(x=1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_quad_write_enable(uint32_t spi_periph)
|
||||
{
|
||||
SPI_QCTL(spi_periph) &= (uint32_t)(~SPI_QCTL_QRD);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable quad wire SPI read
|
||||
\param[in] spi_periph: SPIx(x=1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_quad_read_enable(uint32_t spi_periph)
|
||||
{
|
||||
SPI_QCTL(spi_periph) |= (uint32_t)SPI_QCTL_QRD;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable SPI_IO2 and SPI_IO3 pin output
|
||||
\param[in] spi_periph: SPIx(x=1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_quad_io23_output_enable(uint32_t spi_periph)
|
||||
{
|
||||
SPI_QCTL(spi_periph) |= (uint32_t)SPI_QCTL_IO23_DRV;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable SPI_IO2 and SPI_IO3 pin output
|
||||
\param[in] spi_periph: SPIx(x=1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_quad_io23_output_disable(uint32_t spi_periph)
|
||||
{
|
||||
SPI_QCTL(spi_periph) &= (uint32_t)(~SPI_QCTL_IO23_DRV);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get SPI and I2S flag status
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[in] flag: SPI/I2S flag status
|
||||
only one parameter can be selected which are shown as below:
|
||||
\arg SPI_FLAG_TBE: transmit buffer empty flag
|
||||
\arg SPI_FLAG_RBNE: receive buffer not empty flag
|
||||
\arg SPI_FLAG_TRANS: transmit on-going flag
|
||||
\arg SPI_FLAG_RXORERR: receive overrun error flag
|
||||
\arg SPI_FLAG_CONFERR: mode config error flag
|
||||
\arg SPI_FLAG_CRCERR: CRC error flag
|
||||
\arg SPI_FLAG_FERR: SPI format error interrupt flag
|
||||
\arg I2S_FLAG_TBE: transmit buffer empty flag
|
||||
\arg I2S_FLAG_RBNE: receive buffer not empty flag
|
||||
\arg I2S_FLAG_TRANS: transmit on-going flag
|
||||
\arg I2S_FLAG_RXORERR: overrun error flag
|
||||
\arg I2S_FLAG_TXURERR: underrun error flag
|
||||
\arg I2S_FLAG_CH: channel side flag
|
||||
\arg I2S_FLAG_FERR: I2S format error interrupt flag
|
||||
only for SPI1:
|
||||
\arg SPI_TXLVL_EMPTY: SPI TXFIFO is empty
|
||||
\arg SPI_TXLVL_QUARTER_FULL: SPI TXFIFO is a quarter of full
|
||||
\arg SPI_TXLVL_HAlF_FULL: SPI TXFIFO is a half of full
|
||||
\arg SPI_TXLVL_FULL: SPI TXFIFO is full
|
||||
\arg SPI_RXLVL_EMPTY: SPI RXFIFO is empty
|
||||
\arg SPI_RXLVL_QUARTER_FULL: SPI RXFIFO is a quarter of full
|
||||
\arg SPI_RXLVL_HAlF_FULL: SPI RXFIFO is a half of full
|
||||
\arg SPI_RXLVL_FULL: SPI RXFIFO is full
|
||||
\param[out] none
|
||||
\retval FlagStatus: SET or RESET
|
||||
*/
|
||||
FlagStatus spi_i2s_flag_get(uint32_t spi_periph, uint32_t flag)
|
||||
{
|
||||
if(RESET != (SPI_STAT(spi_periph) & flag)) {
|
||||
return SET;
|
||||
} else {
|
||||
if(SPI1 == spi_periph) {
|
||||
/* check TXFIFO is empty or not */
|
||||
if(SPI_TXLVL_EMPTY == flag) {
|
||||
if(RESET != (SPI_STAT(spi_periph) & SPI_TXLVL_EMPTY_MASK)) {
|
||||
return RESET;
|
||||
} else {
|
||||
return SET;
|
||||
}
|
||||
}
|
||||
/* check RXFIFO is empty or not */
|
||||
if(SPI_RXLVL_EMPTY == flag) {
|
||||
if(RESET != (SPI_STAT(spi_periph) & SPI_RXLVL_EMPTY_MASK)) {
|
||||
return RESET;
|
||||
} else {
|
||||
return SET;
|
||||
}
|
||||
}
|
||||
}
|
||||
return RESET;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable SPI and I2S interrupt
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[in] interrupt: SPI/I2S interrupt
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SPI_I2S_INT_TBE: transmit buffer empty interrupt
|
||||
\arg SPI_I2S_INT_RBNE: receive buffer not empty interrupt
|
||||
\arg SPI_I2S_INT_ERR: CRC error, configuration error, reception overrun error,
|
||||
transmission underrun error and format error interrupt
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_i2s_interrupt_enable(uint32_t spi_periph, uint8_t interrupt)
|
||||
{
|
||||
SPI_CTL1(spi_periph) |= (uint32_t)interrupt;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable SPI and I2S interrupt
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[in] interrupt: SPI/I2S interrupt
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SPI_I2S_INT_TBE: transmit buffer empty interrupt
|
||||
\arg SPI_I2S_INT_RBNE: receive buffer not empty interrupt
|
||||
\arg SPI_I2S_INT_ERR: CRC error, configuration error, reception overrun error,
|
||||
transmission underrun error and format error interrupt
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_i2s_interrupt_disable(uint32_t spi_periph, uint8_t interrupt)
|
||||
{
|
||||
SPI_CTL1(spi_periph) &= ~(uint32_t)interrupt;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get SPI and I2S interrupt flag status
|
||||
\param[in] spi_periph: SPIx(x=0,1)
|
||||
\param[in] interrupt: SPI/I2S interrupt flag status
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SPI_I2S_INT_FLAG_TBE: transmit buffer empty interrupt flag
|
||||
\arg SPI_I2S_INT_FLAG_RBNE: receive buffer not empty interrupt flag
|
||||
\arg SPI_I2S_INT_FLAG_RXORERR: overrun interrupt flag
|
||||
\arg SPI_INT_FLAG_CONFERR: config error interrupt flag
|
||||
\arg SPI_INT_FLAG_CRCERR: CRC error interrupt flag
|
||||
\arg I2S_INT_FLAG_TXURERR: underrun error interrupt flag
|
||||
\arg SPI_I2S_INT_FLAG_FERR: format error interrupt flag
|
||||
\param[out] none
|
||||
\retval FlagStatus: SET or RESET
|
||||
*/
|
||||
FlagStatus spi_i2s_interrupt_flag_get(uint32_t spi_periph, uint8_t interrupt)
|
||||
{
|
||||
uint32_t reg1 = SPI_STAT(spi_periph);
|
||||
uint32_t reg2 = SPI_CTL1(spi_periph);
|
||||
|
||||
switch(interrupt) {
|
||||
/* SPI/I2S transmit buffer empty interrupt */
|
||||
case SPI_I2S_INT_FLAG_TBE:
|
||||
reg1 = reg1 & SPI_STAT_TBE;
|
||||
reg2 = reg2 & SPI_CTL1_TBEIE;
|
||||
break;
|
||||
/* SPI/I2S receive buffer not empty interrupt */
|
||||
case SPI_I2S_INT_FLAG_RBNE:
|
||||
reg1 = reg1 & SPI_STAT_RBNE;
|
||||
reg2 = reg2 & SPI_CTL1_RBNEIE;
|
||||
break;
|
||||
/* SPI/I2S overrun interrupt */
|
||||
case SPI_I2S_INT_FLAG_RXORERR:
|
||||
reg1 = reg1 & SPI_STAT_RXORERR;
|
||||
reg2 = reg2 & SPI_CTL1_ERRIE;
|
||||
break;
|
||||
/* SPI config error interrupt */
|
||||
case SPI_INT_FLAG_CONFERR:
|
||||
reg1 = reg1 & SPI_STAT_CONFERR;
|
||||
reg2 = reg2 & SPI_CTL1_ERRIE;
|
||||
break;
|
||||
/* SPI CRC error interrupt */
|
||||
case SPI_INT_FLAG_CRCERR:
|
||||
reg1 = reg1 & SPI_STAT_CRCERR;
|
||||
reg2 = reg2 & SPI_CTL1_ERRIE;
|
||||
break;
|
||||
/* I2S underrun error interrupt */
|
||||
case I2S_INT_FLAG_TXURERR:
|
||||
reg1 = reg1 & SPI_STAT_TXURERR;
|
||||
reg2 = reg2 & SPI_CTL1_ERRIE;
|
||||
break;
|
||||
/* SPI/I2S format error interrupt */
|
||||
case SPI_I2S_INT_FLAG_FERR:
|
||||
reg1 = reg1 & SPI_STAT_FERR;
|
||||
reg2 = reg2 & SPI_CTL1_ERRIE;
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
/*get SPI/I2S interrupt flag status */
|
||||
if((0U != reg1) && (0U != reg2)) {
|
||||
return SET;
|
||||
} else {
|
||||
return RESET;
|
||||
}
|
||||
}
|
205
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_syscfg.c
Normal file
205
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_syscfg.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/*!
|
||||
\file gd32e23x_syscfg.c
|
||||
\brief SYSCFG driver
|
||||
|
||||
\version 2024-02-22, V2.1.0, firmware for GD32E23x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2024, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "gd32e23x_syscfg.h"
|
||||
|
||||
/*!
|
||||
\brief reset the SYSCFG registers
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void syscfg_deinit(void)
|
||||
{
|
||||
rcu_periph_reset_enable(RCU_CFGCMPRST);
|
||||
rcu_periph_reset_disable(RCU_CFGCMPRST);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable the DMA channels remapping
|
||||
\param[in] syscfg_dma_remap: specify the DMA channels to remap
|
||||
\arg SYSCFG_DMA_REMAP_TIMER16: remap TIMER16 channel0 and UP DMA requests to channel1(defaut channel0)
|
||||
\arg SYSCFG_DMA_REMAP_TIMER15: remap TIMER15 channel2 and UP DMA requests to channel3(defaut channel2)
|
||||
\arg SYSCFG_DMA_REMAP_USART0RX: remap USART0 Rx DMA request to channel4(default channel2)
|
||||
\arg SYSCFG_DMA_REMAP_USART0TX: remap USART0 Tx DMA request to channel3(default channel1)
|
||||
\arg SYSCFG_DMA_REMAP_ADC: remap ADC DMA requests from channel0 to channel1
|
||||
\arg SYSCFG_PA11_REMAP_PA12: remap PA11 PA12
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void syscfg_dma_remap_enable(uint32_t syscfg_dma_remap)
|
||||
{
|
||||
SYSCFG_CFG0 |= syscfg_dma_remap;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable the DMA channels remapping
|
||||
\param[in] syscfg_dma_remap: specify the DMA channels to remap
|
||||
\arg SYSCFG_DMA_REMAP_TIMER16: remap TIMER16 channel0 and UP DMA requests to channel1(defaut channel0)
|
||||
\arg SYSCFG_DMA_REMAP_TIMER15: remap TIMER15 channel2 and UP DMA requests to channel3(defaut channel2)
|
||||
\arg SYSCFG_DMA_REMAP_USART0RX: remap USART0 Rx DMA request to channel4(default channel2)
|
||||
\arg SYSCFG_DMA_REMAP_USART0TX: remap USART0 Tx DMA request to channel3(default channel1)
|
||||
\arg SYSCFG_DMA_REMAP_ADC: remap ADC DMA requests from channel0 to channel1
|
||||
\arg SYSCFG_PA11_REMAP_PA12: remap PA11 PA12
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void syscfg_dma_remap_disable(uint32_t syscfg_dma_remap)
|
||||
{
|
||||
SYSCFG_CFG0 &= ~syscfg_dma_remap;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable PB9 high current capability
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void syscfg_high_current_enable(void)
|
||||
{
|
||||
SYSCFG_CFG0 |= SYSCFG_HIGH_CURRENT_ENABLE;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable PB9 high current capability
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void syscfg_high_current_disable(void)
|
||||
{
|
||||
SYSCFG_CFG0 &= SYSCFG_HIGH_CURRENT_DISABLE;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure the GPIO pin as EXTI Line
|
||||
\param[in] exti_port: specify the GPIO port used in EXTI
|
||||
\arg EXTI_SOURCE_GPIOx(x = A,B,C,F): EXTI GPIO port
|
||||
\param[in] exti_pin: specify the EXTI line
|
||||
\arg EXTI_SOURCE_PINx(GPIOA x = 0..15,GPIOB x = 0..15,GPIOC x = 13..15,GPIOF x = 0.1.6.7): EXTI GPIO pin
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void syscfg_exti_line_config(uint8_t exti_port, uint8_t exti_pin)
|
||||
{
|
||||
uint32_t clear_exti_mask = ~((uint32_t)EXTI_SS_MASK << (EXTI_SS_MSTEP(exti_pin)));
|
||||
uint32_t config_exti_mask = ((uint32_t)exti_port) << (EXTI_SS_MSTEP(exti_pin));
|
||||
|
||||
switch(exti_pin / EXTI_SS_JSTEP){
|
||||
case EXTISS0:
|
||||
/* clear EXTI source line(0..3) */
|
||||
SYSCFG_EXTISS0 &= clear_exti_mask;
|
||||
/* configure EXTI soure line(0..3) */
|
||||
SYSCFG_EXTISS0 |= config_exti_mask;
|
||||
break;
|
||||
case EXTISS1:
|
||||
/* clear EXTI soure line(4..7) */
|
||||
SYSCFG_EXTISS1 &= clear_exti_mask;
|
||||
/* configure EXTI soure line(4..7) */
|
||||
SYSCFG_EXTISS1 |= config_exti_mask;
|
||||
break;
|
||||
case EXTISS2:
|
||||
/* clear EXTI soure line(8..11) */
|
||||
SYSCFG_EXTISS2 &= clear_exti_mask;
|
||||
/* configure EXTI soure line(8..11) */
|
||||
SYSCFG_EXTISS2 |= config_exti_mask;
|
||||
break;
|
||||
case EXTISS3:
|
||||
/* clear EXTI soure line(12..15) */
|
||||
SYSCFG_EXTISS3 &= clear_exti_mask;
|
||||
/* configure EXTI soure line(12..15) */
|
||||
SYSCFG_EXTISS3 |= config_exti_mask;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief connect TIMER0/14/15/16 break input to the selected parameter
|
||||
\param[in] syscfg_lock: Specify the parameter to be connected
|
||||
\arg SYSCFG_LOCK_LOCKUP: Cortex-M23 lockup output connected to the break input
|
||||
\arg SYSCFG_LOCK_SRAM_PARITY_ERROR: SRAM_PARITY check error connected to the break input
|
||||
\arg SYSCFG_LOCK_LVD: LVD interrupt connected to the break input
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void syscfg_lock_config(uint32_t syscfg_lock)
|
||||
{
|
||||
SYSCFG_CFG2 |= syscfg_lock;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set the wait state counter value
|
||||
\param[in] irq_latency: IRQ_LATENCY value (0x00 - 0xFF)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void irq_latency_set(uint8_t irq_latency)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
reg = SYSCFG_CPU_IRQ_LAT &(~(uint32_t)SYSCFG_CPU_IRQ_LAT_IRQ_LATENCY);
|
||||
reg |= (uint32_t)(IRQ_LATENCY(irq_latency));
|
||||
|
||||
SYSCFG_CPU_IRQ_LAT = (uint32_t)reg;
|
||||
}
|
||||
/*!
|
||||
\brief check if the specified flag in SYSCFG_CFG2 is set or not.
|
||||
\param[in] syscfg_flag: specify the flag in SYSCFG_CFG2 to check.
|
||||
\arg SYSCFG_SRAM_PCEF: SRAM parity check error flag.
|
||||
\param[out] none
|
||||
\retval the syscfg_flag state returned (SET or RESET).
|
||||
*/
|
||||
FlagStatus syscfg_flag_get(uint32_t syscfg_flag)
|
||||
{
|
||||
if((SYSCFG_CFG2 & syscfg_flag) != (uint32_t)RESET){
|
||||
return SET;
|
||||
}else{
|
||||
return RESET;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief clear the flag in SYSCFG_CFG2 by writing 1.
|
||||
\param[in] syscfg_flag: Specify the flag in SYSCFG_CFG2 to clear.
|
||||
\arg SYSCFG_SRAM_PCEF: SRAM parity check error flag.
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void syscfg_flag_clear(uint32_t syscfg_flag)
|
||||
{
|
||||
SYSCFG_CFG2 |= (uint32_t) syscfg_flag;
|
||||
}
|
||||
|
2057
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_timer.c
Normal file
2057
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_timer.c
Normal file
File diff suppressed because it is too large
Load Diff
1274
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_usart.c
Normal file
1274
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_usart.c
Normal file
File diff suppressed because it is too large
Load Diff
126
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_wwdgt.c
Normal file
126
sdk/GD32E23x_standard_peripheral/Src/gd32e23x_wwdgt.c
Normal file
@@ -0,0 +1,126 @@
|
||||
/*!
|
||||
\file gd32e23x_wwdgt.c
|
||||
\brief WWDGT driver
|
||||
|
||||
\version 2024-02-22, V2.1.0, firmware for GD32E23x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2024, GigaDevice Semiconductor Inc.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "gd32e23x_wwdgt.h"
|
||||
|
||||
/*!
|
||||
\brief reset the window watchdog timer configuration
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void wwdgt_deinit(void)
|
||||
{
|
||||
rcu_periph_reset_enable(RCU_WWDGTRST);
|
||||
rcu_periph_reset_disable(RCU_WWDGTRST);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief start the window watchdog timer counter
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void wwdgt_enable(void)
|
||||
{
|
||||
WWDGT_CTL |= WWDGT_CTL_WDGTEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure the window watchdog timer counter value
|
||||
\param[in] counter_value: 0x00000000 - 0x0000007F
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void wwdgt_counter_update(uint16_t counter_value)
|
||||
{
|
||||
WWDGT_CTL = (uint32_t)(CTL_CNT(counter_value));
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure counter value, window value, and prescaler divider value
|
||||
\param[in] counter: 0x00000000 - 0x0000007F
|
||||
\param[in] window: 0x00000000 - 0x0000007F
|
||||
\param[in] prescaler: wwdgt prescaler value
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg WWDGT_CFG_PSC_DIV1: the time base of window watchdog counter = (PCLK1/4096)/1
|
||||
\arg WWDGT_CFG_PSC_DIV2: the time base of window watchdog counter = (PCLK1/4096)/2
|
||||
\arg WWDGT_CFG_PSC_DIV4: the time base of window watchdog counter = (PCLK1/4096)/4
|
||||
\arg WWDGT_CFG_PSC_DIV8: the time base of window watchdog counter = (PCLK1/4096)/8
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void wwdgt_config(uint16_t counter, uint16_t window, uint32_t prescaler)
|
||||
{
|
||||
WWDGT_CFG = (uint32_t)(CFG_WIN(window) | prescaler);
|
||||
WWDGT_CTL = (uint32_t)(CTL_CNT(counter));
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief check early wakeup interrupt state of WWDGT
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval FlagStatus: SET or RESET
|
||||
*/
|
||||
FlagStatus wwdgt_flag_get(void)
|
||||
{
|
||||
if(RESET != (WWDGT_STAT & WWDGT_STAT_EWIF)){
|
||||
return SET;
|
||||
}
|
||||
return RESET;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief clear early wakeup interrupt state of WWDGT
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void wwdgt_flag_clear(void)
|
||||
{
|
||||
WWDGT_STAT &= (~(uint32_t)WWDGT_STAT_EWIF);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable early wakeup interrupt of WWDGT
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void wwdgt_interrupt_enable(void)
|
||||
{
|
||||
WWDGT_CFG |= WWDGT_CFG_EWIE;
|
||||
}
|
Reference in New Issue
Block a user