First commit. Temp from Mo10

This commit is contained in:
2024-09-20 17:03:48 +08:00
parent 7b23ae3c40
commit 439d6579f0
59 changed files with 23704 additions and 0 deletions

View 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);
}

View 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;
}
}

View 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);
}

View 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));
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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));
}
}

View 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;
}
}

View 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;
}
}

File diff suppressed because it is too large Load Diff

View 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;
}

View 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;
}
}

View 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;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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;
}