Initial commit: CCU621_M firmware project with BLE debug link support.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-08 17:28:36 +08:00
commit 9ceb218f80
1597 changed files with 724159 additions and 0 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,732 @@
/*!
\file gd32h7xx_cau.c
\brief CAU driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_cau.h"
#include "gd32h7xx_rcu.h"
#define STAT0_AESDES_MASK ((uint32_t)0x00000015U)
#define STAT0_TDES_MASK ((uint32_t)0x00000014U)
/*!
\brief reset the CAU peripheral
\param[in] none
\param[out] none
\retval none
*/
void cau_deinit(void)
{
/* enable CAU reset state */
rcu_periph_reset_enable(RCU_CAURST);
/* release CAU from reset state */
rcu_periph_reset_disable(RCU_CAURST);
}
/*!
\brief initialize the CAU encrypt and decrypt parameter struct with the default values
\param[in] none
\param[out] cau_parameter:
alg_dir: algorithm directory
CAU_ENCRYPT, CAU_DECRYPT
key: key
key_size: key size in bytes
iv: initialization vector
iv_size: iv size in bytes
input: input data
in_length: input data length in bytes
aad: additional authentication data
aad_size: header size
\retval none
*/
void cau_struct_para_init(cau_parameter_struct *cau_parameter)
{
/* set the CAU encrypt and decrypt parameters struct with the default values */
cau_parameter->alg_dir = CAU_ENCRYPT;
cau_parameter->key = 0U;
cau_parameter->key_size = 0U;
cau_parameter->iv = 0U;
cau_parameter->iv_size = 0U;
cau_parameter->input = 0U;
cau_parameter->in_length = 0U;
cau_parameter->aad = 0U;
cau_parameter->aad_size = 0U;
}
/*!
\brief initialize the key parameter structure with the default values
\param[in] none
\param[out] key_initpara:
key_0_high: key 0 high
key_0_low: key 0 low
key_1_high: key 1 high
key_1_low: key 1 low
key_2_high: key 2 high
key_2_low: key 2 low
key_3_high: key 3 high
key_3_low: key 3 low
\retval none
*/
void cau_key_struct_para_init(cau_key_parameter_struct *key_initpara)
{
/* set the key parameters struct with the default values */
key_initpara->key_0_high = 0U;
key_initpara->key_0_low = 0U;
key_initpara->key_1_high = 0U;
key_initpara->key_1_low = 0U;
key_initpara->key_2_high = 0U;
key_initpara->key_2_low = 0U;
key_initpara->key_3_high = 0U;
key_initpara->key_3_low = 0U;
}
/*!
\brief initialize the vectors parameter struct with the default values
\param[in] none
\param[out] iv_initpara:
iv_0_high: init vector 0 high
iv_0_low: init vector 0 low
iv_1_high: init vector 1 high
iv_1_low: init vector 1 low
\retval none
*/
void cau_iv_struct_para_init(cau_iv_parameter_struct *iv_initpara)
{
/* set the vectors parameters struct with the default values */
iv_initpara->iv_0_high = 0U;
iv_initpara->iv_0_low = 0U;
iv_initpara->iv_1_high = 0U;
iv_initpara->iv_1_low = 0U;
}
/*!
\brief initialize the context parameter struct with the default values
\param[in] none
\param[out] cau_context:
ctl_config: current configuration
iv_0_high: init vector 0 high
iv_0_low: init vector 0 low
iv_1_high: init vector 1 high
iv_1_low: init vector 1 low
key_0_high: key 0 high
key_0_low: key 0 low
key_1_high: key 1 high
key_1_low: key 1 low
key_2_high: key 2 high
key_2_low: key 2 low
key_3_high: key 3 high
key_3_low: key 3 low
gcmccmctxs[8]: GCM or CCM mode context switch
gcmctxs[8]: GCM mode context switch
\retval none
*/
void cau_context_struct_para_init(cau_context_parameter_struct *cau_context)
{
cau_context->ctl_config = 0U;
/* set the vectors parameters with the default values */
cau_context->iv_0_high = 0U;
cau_context->iv_0_low = 0U;
cau_context->iv_1_high = 0U;
cau_context->iv_1_low = 0U;
/* set the key parameters with the default values */
cau_context->key_0_high = 0U;
cau_context->key_0_low = 0U;
cau_context->key_1_high = 0U;
cau_context->key_1_low = 0U;
cau_context->key_2_high = 0U;
cau_context->key_2_low = 0U;
cau_context->key_3_high = 0U;
cau_context->key_3_low = 0U;
/* set the context switch with the default values */
cau_context->gcmccmctxs[0] = 0U;
cau_context->gcmccmctxs[1] = 0U;
cau_context->gcmccmctxs[2] = 0U;
cau_context->gcmccmctxs[3] = 0U;
cau_context->gcmccmctxs[4] = 0U;
cau_context->gcmccmctxs[5] = 0U;
cau_context->gcmccmctxs[6] = 0U;
cau_context->gcmccmctxs[7] = 0U;
cau_context->gcmctxs[0] = 0U;
cau_context->gcmctxs[1] = 0U;
cau_context->gcmctxs[2] = 0U;
cau_context->gcmctxs[3] = 0U;
cau_context->gcmctxs[4] = 0U;
cau_context->gcmctxs[5] = 0U;
cau_context->gcmctxs[6] = 0U;
cau_context->gcmctxs[7] = 0U;
}
/*!
\brief enable the CAU peripheral
\param[in] none
\param[out] none
\retval none
*/
void cau_enable(void)
{
/* enable the CAU processor */
CAU_CTL |= CAU_CTL_CAUEN;
}
/*!
\brief disable the CAU peripheral
\param[in] none
\param[out] none
\retval none
*/
void cau_disable(void)
{
/* disable the CAU processor */
CAU_CTL &= ~CAU_CTL_CAUEN;
}
/*!
\brief enable the CAU DMA interface
\param[in] dma_req: specify the CAU DMA transfer request to be enabled
one or more parameters can be selected which are shown as below:
\arg CAU_DMA_INFIFO: DMA for incoming(Rx) data transfer
\arg CAU_DMA_OUTFIFO: DMA for outgoing(Tx) data transfer
\param[out] none
\retval none
*/
void cau_dma_enable(uint32_t dma_req)
{
/* enable the selected CAU DMA request */
CAU_DMAEN |= dma_req;
}
/*!
\brief disable the CAU DMA interface
\param[in] dma_req: specify the CAU DMA transfer request to be disabled
one or more parameters can be selected which are shown as below:
\arg CAU_DMA_INFIFO: DMA for incoming(Rx) data transfer
\arg CAU_DMA_OUTFIFO: DMA for outgoing(Tx) data transfer
\param[out] none
\retval none
*/
void cau_dma_disable(uint32_t dma_req)
{
/* disable the selected CAU DMA request */
CAU_DMAEN &= ~(dma_req);
}
/*!
\brief initialize the CAU peripheral
\param[in] alg_dir: algorithm direction
only one parameter can be selected which is shown as below:
\arg CAU_ENCRYPT: encrypt
\arg CAU_DECRYPT: decrypt
\param[in] algo_mode: algorithm mode selection
only one parameter can be selected which is shown as below:
\arg CAU_MODE_TDES_ECB: TDES-ECB (3DES Electronic codebook)
\arg CAU_MODE_TDES_CBC: TDES-CBC (3DES Cipher block chaining)
\arg CAU_MODE_DES_ECB: DES-ECB (simple DES Electronic codebook)
\arg CAU_MODE_DES_CBC: DES-CBC (simple DES Cipher block chaining)
\arg CAU_MODE_AES_ECB: AES-ECB (AES Electronic codebook)
\arg CAU_MODE_AES_CBC: AES-CBC (AES Cipher block chaining)
\arg CAU_MODE_AES_CTR: AES-CTR (AES counter mode)
\arg CAU_MODE_AES_KEY: AES decryption key preparation mode
\arg CAU_MODE_AES_GCM: AES-GCM (AES Galois/counter mode)
\arg CAU_MODE_AES_CCM: AES-CCM (AES combined cipher machine mode)
\arg CAU_MODE_AES_CFB: AES-CFB (cipher feedback mode)
\arg CAU_MODE_AES_OFB: AES-OFB (output feedback mode)
\param[in] swapping: data swapping selection
only one parameter can be selected which is shown as below:
\arg CAU_SWAPPING_32BIT: no swapping
\arg CAU_SWAPPING_16BIT: half-word swapping
\arg CAU_SWAPPING_8BIT: bytes swapping
\arg CAU_SWAPPING_1BIT: bit swapping
\param[out] none
\retval none
*/
void cau_init(uint32_t alg_dir, uint32_t algo_mode, uint32_t swapping)
{
/* select algorithm mode */
CAU_CTL &= ~CAU_CTL_ALGM;
CAU_CTL |= algo_mode;
/* select data swapping */
CAU_CTL &= ~CAU_CTL_DATAM;
CAU_CTL |= swapping;
/* select algorithm direction */
CAU_CTL &= ~CAU_CTL_CAUDIR;
CAU_CTL |= alg_dir;
}
/*!
\brief configure key selection
\param[in] key_selection: key source selection when aes mode
only one parameter can be selected which is shown as below:
\arg CAU_KEY: use the key from CAU register
\arg CAU_EFUSE_KEY: use the key from EFUSE
\param[out] none
\retval none
*/
void cau_aes_key_select(uint32_t key_selection)
{
CAU_CTL &= ~CAU_CTL_KEY_SEL;
CAU_CTL |= key_selection;
}
/*!
\brief configure key size if use AES algorithm
\param[in] key_size: key length selection when aes mode
only one parameter can be selected which is shown as below:
\arg CAU_KEYSIZE_128BIT: 128 bit key length
\arg CAU_KEYSIZE_192BIT: 192 bit key length
\arg CAU_KEYSIZE_256BIT: 256 bit key length
\param[out] none
\retval none
*/
void cau_aes_keysize_config(uint32_t key_size)
{
CAU_CTL &= ~CAU_CTL_KEYM;
CAU_CTL |= key_size;
}
/*!
\brief initialize the key parameters
\param[in] key_initpara: key init parameter struct
key_0_high: key 0 high
key_0_low: key 0 low
key_1_high: key 1 high
key_1_low: key 1 low
key_2_high: key 2 high
key_2_low: key 2 low
key_3_high: key 3 high
key_3_low: key 3 low
\param[out] none
\retval none
*/
void cau_key_init(cau_key_parameter_struct *key_initpara)
{
CAU_KEY0H = key_initpara->key_0_high;
CAU_KEY0L = key_initpara->key_0_low;
CAU_KEY1H = key_initpara->key_1_high;
CAU_KEY1L = key_initpara->key_1_low;
CAU_KEY2H = key_initpara->key_2_high;
CAU_KEY2L = key_initpara->key_2_low;
CAU_KEY3H = key_initpara->key_3_high;
CAU_KEY3L = key_initpara->key_3_low;
}
/*!
\brief initialize the vectors parameters
\param[in] iv_initpara: vectors init parameter struct
iv_0_high: init vector 0 high
iv_0_low: init vector 0 low
iv_1_high: init vector 1 high
iv_1_low: init vector 1 low
\param[out] none
\retval none
*/
void cau_iv_init(cau_iv_parameter_struct *iv_initpara)
{
CAU_IV0H = iv_initpara->iv_0_high;
CAU_IV0L = iv_initpara->iv_0_low;
CAU_IV1H = iv_initpara->iv_1_high;
CAU_IV1L = iv_initpara->iv_1_low;
}
/*!
\brief configure phase
\param[in] phase: gcm or ccm phase
only one parameter can be selected which is shown as below:
\arg CAU_PREPARE_PHASE: prepare phase
\arg CAU_AAD_PHASE: AAD phase
\arg CAU_ENCRYPT_DECRYPT_PHASE: encryption/decryption phase
\arg CAU_TAG_PHASE: tag phase
\param[out] none
\retval none
*/
void cau_phase_config(uint32_t phase)
{
uint32_t temp;
/* Get the CTL register */
temp = CAU_CTL;
/* Reset the phase configuration bits */
temp &= ~CAU_CTL_GCM_CCMPH;
/* Set the selected phase */
temp |= phase;
/* Set the CTL register */
CAU_CTL = temp;
}
/*!
\brief flush the IN and OUT FIFOs
\param[in] none
\param[out] none
\retval none
*/
void cau_fifo_flush(void)
{
/* reset the read and write pointers of the FIFOs */
CAU_CTL |= CAU_CTL_FFLUSH;
}
/*!
\brief return whether CAU peripheral is enabled or disabled
\param[in] none
\param[out] none
\retval ControlStatus: ENABLE or DISABLE
*/
ControlStatus cau_enable_state_get(void)
{
ControlStatus ret = DISABLE;
if(RESET != (CAU_CTL & CAU_CTL_CAUEN)) {
ret = ENABLE;
}
return ret;
}
/*!
\brief write data to the IN FIFO
\param[in] data: data to write (0 - 0xFFFFFFFF)
\param[out] none
\retval none
*/
void cau_data_write(uint32_t data)
{
CAU_DI = data;
}
/*!
\brief return the last data entered into the output FIFO
\param[in] none
\param[out] none
\retval last data entered into the output FIFO
*/
uint32_t cau_data_read(void)
{
return CAU_DO;
}
/*!
\brief save context before context switching
\param[in] key_initpara: key init parameter struct
key_0_high: key 0 high
key_0_low: key 0 low
key_1_high: key 1 high
key_1_low: key 1 low
key_2_high: key 2 high
key_2_low: key 2 low
key_3_high: key 3 high
key_3_low: key 3 low
\param[out] cau_context:
ctl_config: current configuration
iv_0_high: init vector 0 high
iv_0_low: init vector 0 low
iv_1_high: init vector 1 high
iv_1_low: init vector 1 low
key_0_high: key 0 high
key_0_low: key 0 low
key_1_high: key 1 high
key_1_low: key 1 low
key_2_high: key 2 high
key_2_low: key 2 low
key_3_high: key 3 high
key_3_low: key 3 low
gcmccmctxs[8]: GCM or CCM mode context switch
gcmctxs[8]: GCM mode context switch
\retval none
*/
void cau_context_save(cau_context_parameter_struct *cau_context, cau_key_parameter_struct *key_initpara)
{
uint32_t checkmask = 0U;
uint32_t checkbits = 0U;
uint32_t algm_reg = 0U;
/* stop DMA transfers on the IN FIFO by clearing the DMAIEN bit in the CAU_DMAEN */
CAU_DMAEN &= ~CAU_DMA_INFIFO;
algm_reg = CAU_CTL & CAU_CTL_ALGM;
/* AES or DES */
if((uint32_t)0 != (algm_reg & (~CAU_MODE_TDES_CBC))) {
/* wait until both the IN and OUT FIFOs are empty (IEM=1 and ONE=0 in the CAU_STAT0 register) and BUSY=0 */
checkbits = CAU_STAT0_IEM;
checkmask = STAT0_AESDES_MASK;
/* TDES */
} else {
/* wait until OUT FIFO is empty (ONE=0 in the CAU_STAT0 register) and BUSY=0 */
checkbits = 0U;
checkmask = STAT0_TDES_MASK;
}
while((CAU_STAT0 & checkmask) != checkbits) {
}
/* stop DMA transfers on the OUT FIFO by clear CAU_DMAEN_DMAOEN=0 */
CAU_DMAEN &= ~CAU_DMAEN_DMAOEN;
/* disable CAU */
CAU_CTL &= ~CAU_CTL_CAUEN;
/* save the current configuration (bit 19, bit[17:16] and bit[9:2] in the CAU_CTL register) */
cau_context->ctl_config = CAU_CTL & (CAU_CTL_GCM_CCMPH |
CAU_CTL_KEYM |
CAU_CTL_DATAM |
CAU_CTL_ALGM |
CAU_CTL_CAUDIR |
CAU_CTL_NBPILB);
/* save the key value */
cau_context->key_0_high = key_initpara->key_0_high;
cau_context->key_0_low = key_initpara->key_0_low;
cau_context->key_1_high = key_initpara->key_1_high;
cau_context->key_1_low = key_initpara->key_1_low;
cau_context->key_2_high = key_initpara->key_2_high;
cau_context->key_2_low = key_initpara->key_2_low;
cau_context->key_3_high = key_initpara->key_3_high;
cau_context->key_3_low = key_initpara->key_3_low;
if((CAU_MODE_TDES_ECB != algm_reg) && (CAU_MODE_DES_ECB != algm_reg) && (CAU_MODE_AES_ECB != algm_reg)) {
/* if not in ECB mode, save the initialization vectors */
cau_context->iv_0_high = CAU_IV0H;
cau_context->iv_0_low = CAU_IV0L;
cau_context->iv_1_high = CAU_IV1H;
cau_context->iv_1_low = CAU_IV1L;
}
/* if in GCM/CCM mode, save the context switch registers */
if((CAU_MODE_AES_GCM == algm_reg) || (CAU_MODE_AES_CCM == algm_reg)) {
cau_context->gcmccmctxs[0U] = CAU_GCMCCMCTXSx(0U);
cau_context->gcmccmctxs[1U] = CAU_GCMCCMCTXSx(1U);
cau_context->gcmccmctxs[2U] = CAU_GCMCCMCTXSx(2U);
cau_context->gcmccmctxs[3U] = CAU_GCMCCMCTXSx(3U);
cau_context->gcmccmctxs[4U] = CAU_GCMCCMCTXSx(4U);
cau_context->gcmccmctxs[5U] = CAU_GCMCCMCTXSx(5U);
cau_context->gcmccmctxs[6U] = CAU_GCMCCMCTXSx(6U);
cau_context->gcmccmctxs[7U] = CAU_GCMCCMCTXSx(7U);
}
/* if in GCM mode, save the context switch registers */
if(CAU_MODE_AES_GCM == algm_reg) {
cau_context->gcmctxs[0U] = CAU_GCMCTXSx(0U);
cau_context->gcmctxs[1U] = CAU_GCMCTXSx(1U);
cau_context->gcmctxs[2U] = CAU_GCMCTXSx(2U);
cau_context->gcmctxs[3U] = CAU_GCMCTXSx(3U);
cau_context->gcmctxs[4U] = CAU_GCMCTXSx(4U);
cau_context->gcmctxs[5U] = CAU_GCMCTXSx(5U);
cau_context->gcmctxs[6U] = CAU_GCMCTXSx(6U);
cau_context->gcmctxs[7U] = CAU_GCMCTXSx(7U);
}
}
/*!
\brief restore context after context switching
\param[in] cau_context:
ctl_config: current configuration
iv_0_high: init vector 0 high
iv_0_low: init vector 0 low
iv_1_high: init vector 1 high
iv_1_low: init vector 1 low
key_0_high: key 0 high
key_0_low: key 0 low
key_1_high: key 1 high
key_1_low: key 1 low
key_2_high: key 2 high
key_2_low: key 2 low
key_3_high: key 3 high
key_3_low: key 3 low
gcmccmctxs[8]: GCM or CCM mode context switch
gcmctxs[8]: GCM mode context switch
\param[out] none
\retval none
*/
void cau_context_restore(cau_context_parameter_struct *cau_context)
{
uint32_t algm_reg, aes_decrypt;
/* configure the processor with the saved configuration */
CAU_CTL = cau_context->ctl_config;
algm_reg = CAU_CTL & CAU_CTL_ALGM;
/* restore the key value */
CAU_KEY0H = cau_context->key_0_high;
CAU_KEY0L = cau_context->key_0_low;
CAU_KEY1H = cau_context->key_1_high;
CAU_KEY1L = cau_context->key_1_low;
CAU_KEY2H = cau_context->key_2_high;
CAU_KEY2L = cau_context->key_2_low;
CAU_KEY3H = cau_context->key_3_high;
CAU_KEY3L = cau_context->key_3_low;
if((CAU_MODE_TDES_ECB != algm_reg) && (CAU_MODE_DES_ECB != algm_reg) && (CAU_MODE_AES_ECB != algm_reg)) {
/* restore the initialization vectors */
CAU_IV0H = cau_context->iv_0_high;
CAU_IV0L = cau_context->iv_0_low;
CAU_IV1H = cau_context->iv_1_high;
CAU_IV1L = cau_context->iv_1_low;
}
/* if in GCM/CCM mode, restore the context switch registers */
if((CAU_MODE_AES_GCM == algm_reg) || (CAU_MODE_AES_CCM == algm_reg)) {
CAU_GCMCCMCTXSx(0U) = cau_context->gcmccmctxs[0U];
CAU_GCMCCMCTXSx(1U) = cau_context->gcmccmctxs[1U];
CAU_GCMCCMCTXSx(2U) = cau_context->gcmccmctxs[2U];
CAU_GCMCCMCTXSx(3U) = cau_context->gcmccmctxs[3U];
CAU_GCMCCMCTXSx(4U) = cau_context->gcmccmctxs[4U];
CAU_GCMCCMCTXSx(5U) = cau_context->gcmccmctxs[5U];
CAU_GCMCCMCTXSx(6U) = cau_context->gcmccmctxs[6U];
CAU_GCMCCMCTXSx(7U) = cau_context->gcmccmctxs[7U];
}
/* if in GCM mode, restore the context switch registers */
if(CAU_MODE_AES_GCM == algm_reg) {
CAU_GCMCTXSx(0U) = cau_context->gcmctxs[0U];
CAU_GCMCTXSx(1U) = cau_context->gcmctxs[1U];
CAU_GCMCTXSx(2U) = cau_context->gcmctxs[2U];
CAU_GCMCTXSx(3U) = cau_context->gcmctxs[3U];
CAU_GCMCTXSx(4U) = cau_context->gcmctxs[4U];
CAU_GCMCTXSx(5U) = cau_context->gcmctxs[5U];
CAU_GCMCTXSx(6U) = cau_context->gcmctxs[6U];
CAU_GCMCTXSx(7U) = cau_context->gcmctxs[7U];
}
/* if it is AES ECB/CBC decryption, then first prepare key */
aes_decrypt = CAU_CTL & (CAU_CTL_ALGM | CAU_CTL_CAUDIR);
if(((CAU_MODE_AES_ECB | CAU_DECRYPT) == aes_decrypt) || ((CAU_MODE_AES_CBC | CAU_DECRYPT) == aes_decrypt)) {
uint32_t alg_dir, algo_mode, swapping;
/* flush IN/OUT FIFOs */
cau_fifo_flush();
/* parameters for key preparation for AES decryption */
alg_dir = CAU_DECRYPT;
algo_mode = CAU_MODE_AES_KEY;
swapping = CAU_SWAPPING_32BIT;
cau_init(alg_dir, algo_mode, swapping);
/* enable CAU */
cau_enable();
/* wait until BUSY=0 */
while((uint32_t)0U != cau_flag_get(CAU_FLAG_BUSY)) {
}
/* parameters for decryption */
CAU_CTL = cau_context->ctl_config;
}
/* enable CAU */
cau_enable();
}
/*!
\brief get the CAU flag status
\param[in] flag: CAU flag status
only one parameter can be selected which is shown as below:
\arg CAU_FLAG_INFIFO_EMPTY: input FIFO empty
\arg CAU_FLAG_INFIFO_NO_FULL: input FIFO is not full
\arg CAU_FLAG_OUTFIFO_NO_EMPTY: output FIFO not empty
\arg CAU_FLAG_OUTFIFO_FULL: output FIFO is full
\arg CAU_FLAG_BUSY: the CAU core is busy
\arg CAU_FLAG_INFIFO: input FIFO flag status
\arg CAU_FLAG_OUTFIFO: output FIFO flag status
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus cau_flag_get(uint32_t flag)
{
uint32_t reg = 0U;
FlagStatus ret_flag = RESET;
/* check if the flag is in CAU_STAT1 register */
if(1U == (flag >> 31U)) {
reg = CAU_STAT1;
} else {
/* the flag is in CAU_STAT0 register */
reg = CAU_STAT0;
}
/* check the status of the specified CAU flag */
if(0U != (reg & flag)) {
ret_flag = SET;
}
return ret_flag;
}
/*!
\brief enable the CAU interrupts
\param[in] interrupt: specify the CAU interrupt source to be enabled
one or more parameters can be selected which are shown as below:
\arg CAU_INT_INFIFO: input FIFO interrupt
\arg CAU_INT_OUTFIFO: output FIFO interrupt
\param[out] none
\retval none
*/
void cau_interrupt_enable(uint32_t interrupt)
{
/* enable the selected CAU interrupt */
CAU_INTEN |= interrupt;
}
/*!
\brief disable the CAU interrupts
\param[in] interrupt: specify the CAU interrupt source to be disabled
one or more parameters can be selected which are shown as below:
\arg CAU_INT_INFIFO: input FIFO interrupt
\arg CAU_INT_OUTFIFO: output FIFO interrupt
\param[out] none
\retval none
*/
void cau_interrupt_disable(uint32_t interrupt)
{
/* disable the selected CAU interrupt */
CAU_INTEN &= ~(interrupt);
}
/*!
\brief get the interrupt flag
\param[in] int_flag: CAU interrupt flag
only one parameter can be selected which is shown as below:
\arg CAU_INT_FLAG_INFIFO: input FIFO interrupt
\arg CAU_INT_FLAG_OUTFIFO: output FIFO interrupt
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus cau_interrupt_flag_get(uint32_t int_flag)
{
FlagStatus flag = RESET;
/* check the status of the specified CAU interrupt */
if(RESET != (CAU_INTF & int_flag)) {
flag = SET;
}
return flag;
}
@@ -0,0 +1,917 @@
/*!
\file gd32h7xx_cau_aes.c
\brief CAU AES driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_cau.h"
#include <string.h>
#define AESBSY_TIMEOUT ((uint32_t)0x00010000U)
#define BLOCK_B0_MASK ((uint8_t)0x07U)
#define BLOCK_DATA_SIZE ((uint32_t)0x00000010U)
#define MIN_CCM_IV_SIZE ((uint32_t)0x00000007U)
#define MAX_CCM_IV_SIZE ((uint32_t)0x0000000DU)
/* configure AES key structure parameter */
static void cau_aes_key_config(uint8_t *key, uint32_t keysize, cau_key_parameter_struct *cau_key_initpara);
/* fill data into data input register */
static ErrStatus cau_fill_data(uint8_t *input, uint32_t in_length);
/* AES calculate process */
static ErrStatus cau_aes_calculate(uint8_t *input, uint32_t in_length, uint8_t *output);
/*!
\brief encrypt and decrypt using AES in ECB mode
\param[in] cau_parameter: pointer to the input structure
alg_dir: algorithm directory
CAU_ENCRYPT, CAU_DECRYPT
key: key
key_size: key size in bits, must be either 128, 192 or 256
input: input data
in_length: input data length in bytes, must be a multiple of 16 bytes
\param[out] output: pointer to the returned buffer
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus cau_aes_ecb(cau_parameter_struct *cau_parameter, uint8_t *output)
{
ErrStatus ret = ERROR;
cau_key_parameter_struct key_initpara;
__IO uint32_t counter = 0U;
uint32_t busystatus = 0U;
/* key structure initialization */
cau_key_struct_para_init(&key_initpara);
/* AES key structure parameter config */
cau_aes_key_config(cau_parameter->key, cau_parameter->key_size, &key_initpara);
/* key initialization */
cau_key_init(&key_initpara);
/* AES decryption */
if(CAU_DECRYPT == cau_parameter->alg_dir) {
/* flush the IN and OUT FIFOs */
cau_fifo_flush();
/* initialize the CAU peripheral */
cau_init(CAU_DECRYPT, CAU_MODE_AES_KEY, CAU_SWAPPING_32BIT);
/* enable the CAU peripheral */
cau_enable();
/* wait until the busy flag is RESET */
do {
busystatus = cau_flag_get(CAU_FLAG_BUSY);
counter++;
} while((AESBSY_TIMEOUT != counter) && (RESET != busystatus));
if(RESET != busystatus) {
return ERROR;
}
}
/* initialize the CAU peripheral */
cau_init(cau_parameter->alg_dir, CAU_MODE_AES_ECB, CAU_SWAPPING_8BIT);
/* flush the IN and OUT FIFOs */
cau_fifo_flush();
/* enable the CAU peripheral */
cau_enable();
/* AES calculate process */
ret = cau_aes_calculate(cau_parameter->input, cau_parameter->in_length, output);
/* disable the CAU peripheral */
cau_disable();
return ret;
}
/*!
\brief encrypt and decrypt using AES in CBC mode
\param[in] cau_parameter: pointer to the input structure
alg_dir: algorithm directory
CAU_ENCRYPT, CAU_DECRYPT
key: key
key_size: key size in bits, must be either 128, 192 or 256
iv: initialization vector, 16 bytes
input: input data
in_length: input data length in bytes, must be a multiple of 16 bytes
\param[out] output: pointer to the returned buffer
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus cau_aes_cbc(cau_parameter_struct *cau_parameter, uint8_t *output)
{
ErrStatus ret = ERROR;
cau_key_parameter_struct key_initpara;
cau_iv_parameter_struct iv_initpara;
__IO uint32_t counter = 0U;
uint32_t busystatus = 0U;
uint32_t ivaddr = (uint32_t)cau_parameter->iv;
/* key structure initialization */
cau_key_struct_para_init(&key_initpara);
/* AES key structure parameter config */
cau_aes_key_config(cau_parameter->key, cau_parameter->key_size, &key_initpara);
/* key initialization */
cau_key_init(&key_initpara);
/* AES decryption */
if(CAU_DECRYPT == cau_parameter->alg_dir) {
/* flush the IN and OUT FIFOs */
cau_fifo_flush();
/* initialize the CAU peripheral */
cau_init(CAU_DECRYPT, CAU_MODE_AES_KEY, CAU_SWAPPING_32BIT);
/* enable the CAU peripheral */
cau_enable();
/* wait until the busy flag is RESET */
do {
busystatus = cau_flag_get(CAU_FLAG_BUSY);
counter++;
} while((AESBSY_TIMEOUT != counter) && (RESET != busystatus));
if(RESET != busystatus) {
return ERROR;
}
}
/* initialize the CAU peripheral */
cau_init(cau_parameter->alg_dir, CAU_MODE_AES_CBC, CAU_SWAPPING_8BIT);
/* vectors initialization */
iv_initpara.iv_0_high = __REV(*(uint32_t *)(ivaddr));
ivaddr += 4U;
iv_initpara.iv_0_low = __REV(*(uint32_t *)(ivaddr));
ivaddr += 4U;
iv_initpara.iv_1_high = __REV(*(uint32_t *)(ivaddr));
ivaddr += 4U;
iv_initpara.iv_1_low = __REV(*(uint32_t *)(ivaddr));
cau_iv_init(&iv_initpara);
/* flush the IN and OUT FIFOs */
cau_fifo_flush();
/* enable the CAU peripheral */
cau_enable();
/* AES calculate process */
ret = cau_aes_calculate(cau_parameter->input, cau_parameter->in_length, output);
/* disable the CAU peripheral */
cau_disable();
return ret;
}
/*!
\brief encrypt and decrypt using AES in CTR mode
\param[in] cau_parameter: pointer to the input structure
alg_dir: algorithm directory
CAU_ENCRYPT, CAU_DECRYPT
key: key
key_size: key size in bits, must be either 128, 192 or 256
iv: initialization vector, 16 bytes
input: input data
in_length: input data length in bytes, must be a multiple of 16 bytes
\param[out] output: pointer to the returned buffer
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus cau_aes_ctr(cau_parameter_struct *cau_parameter, uint8_t *output)
{
ErrStatus ret = ERROR;
cau_key_parameter_struct key_initpara;
cau_iv_parameter_struct iv_initpara;
uint32_t ivaddr = (uint32_t)cau_parameter->iv;
/* key structure initialization */
cau_key_struct_para_init(&key_initpara);
/* initialize the CAU peripheral */
cau_init(cau_parameter->alg_dir, CAU_MODE_AES_CTR, CAU_SWAPPING_8BIT);
/* AES key structure parameter config */
cau_aes_key_config(cau_parameter->key, cau_parameter->key_size, &key_initpara);
/* key initialization */
cau_key_init(&key_initpara);
/* vectors initialization */
iv_initpara.iv_0_high = __REV(*(uint32_t *)(ivaddr));
ivaddr += 4U;
iv_initpara.iv_0_low = __REV(*(uint32_t *)(ivaddr));
ivaddr += 4U;
iv_initpara.iv_1_high = __REV(*(uint32_t *)(ivaddr));
ivaddr += 4U;
iv_initpara.iv_1_low = __REV(*(uint32_t *)(ivaddr));
cau_iv_init(&iv_initpara);
/* flush the IN and OUT FIFOs */
cau_fifo_flush();
/* enable the CAU peripheral */
cau_enable();
/* AES calculate process */
ret = cau_aes_calculate(cau_parameter->input, cau_parameter->in_length, output);
/* disable the CAU peripheral */
cau_disable();
return ret;
}
/*!
\brief encrypt and decrypt using AES in CFB mode
\param[in] cau_parameter: pointer to the input structure
alg_dir: algorithm directory
CAU_ENCRYPT, CAU_DECRYPT
key: key
key_size: key size in bits, must be either 128, 192 or 256
iv: initialization vector, 16 bytes
input: input data
in_length: input data length in bytes, must be a multiple of 16 bytes
\param[out] output: pointer to the returned buffer
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus cau_aes_cfb(cau_parameter_struct *cau_parameter, uint8_t *output)
{
ErrStatus ret = ERROR;
cau_key_parameter_struct key_initpara;
cau_iv_parameter_struct iv_initpara;
uint32_t ivaddr = (uint32_t)cau_parameter->iv;
/* key structure initialization */
cau_key_struct_para_init(&key_initpara);
/* initialize the CAU peripheral */
cau_init(cau_parameter->alg_dir, CAU_MODE_AES_CFB, CAU_SWAPPING_8BIT);
/* AES key structure parameter config */
cau_aes_key_config(cau_parameter->key, cau_parameter->key_size, &key_initpara);
/* key initialization */
cau_key_init(&key_initpara);
/* vectors initialization */
iv_initpara.iv_0_high = __REV(*(uint32_t *)(ivaddr));
ivaddr += 4U;
iv_initpara.iv_0_low = __REV(*(uint32_t *)(ivaddr));
ivaddr += 4U;
iv_initpara.iv_1_high = __REV(*(uint32_t *)(ivaddr));
ivaddr += 4U;
iv_initpara.iv_1_low = __REV(*(uint32_t *)(ivaddr));
cau_iv_init(&iv_initpara);
/* flush the IN and OUT FIFOs */
cau_fifo_flush();
/* enable the CAU peripheral */
cau_enable();
/* AES calculate process */
ret = cau_aes_calculate(cau_parameter->input, cau_parameter->in_length, output);
/* disable the CAU peripheral */
cau_disable();
return ret;
}
/*!
\brief encrypt and decrypt using AES in OFB mode
\param[in] cau_parameter: pointer to the input structure
alg_dir: algorithm directory
CAU_ENCRYPT, CAU_DECRYPT
key: key
key_size: key size in bits, must be either 128, 192 or 256
iv: initialization vector, 16 bytes
input: input data
in_length: input data length in bytes, must be a multiple of 16 bytes
\param[out] output: pointer to the returned buffer
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus cau_aes_ofb(cau_parameter_struct *cau_parameter, uint8_t *output)
{
ErrStatus ret = ERROR;
cau_key_parameter_struct key_initpara;
cau_iv_parameter_struct iv_initpara;
uint32_t ivaddr = (uint32_t)cau_parameter->iv;
/* key structure initialization */
cau_key_struct_para_init(&key_initpara);
/* initialize the CAU peripheral */
cau_init(cau_parameter->alg_dir, CAU_MODE_AES_OFB, CAU_SWAPPING_8BIT);
/* AES key structure parameter config */
cau_aes_key_config(cau_parameter->key, cau_parameter->key_size, &key_initpara);
/* key initialization */
cau_key_init(&key_initpara);
/* vectors initialization */
iv_initpara.iv_0_high = __REV(*(uint32_t *)(ivaddr));
ivaddr += 4U;
iv_initpara.iv_0_low = __REV(*(uint32_t *)(ivaddr));
ivaddr += 4U;
iv_initpara.iv_1_high = __REV(*(uint32_t *)(ivaddr));
ivaddr += 4U;
iv_initpara.iv_1_low = __REV(*(uint32_t *)(ivaddr));
cau_iv_init(&iv_initpara);
/* flush the IN and OUT FIFOs */
cau_fifo_flush();
/* enable the CAU peripheral */
cau_enable();
/* AES calculate process */
ret = cau_aes_calculate(cau_parameter->input, cau_parameter->in_length, output);
/* disable the CAU peripheral */
cau_disable();
return ret;
}
/*!
\brief encrypt and decrypt using AES in GCM mode
\param[in] cau_parameter: pointer to the input structure
alg_dir: algorithm directory
CAU_ENCRYPT, CAU_DECRYPT
key: key
key_size: key size in bits, must be either 128, 192 or 256
iv: initialization vector, 16 bytes
input: input data
in_length: input data length in bytes, must be a multiple of 16 bytes
aad: additional authentication data
aad_size: aad size in bytes, must be a multiple of 16 bytes
\param[out] output: pointer to the returned output data buffer
\param[out] tag: pointer to the returned tag buffer
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus cau_aes_gcm(cau_parameter_struct *cau_parameter, uint8_t *output, uint8_t *tag)
{
ErrStatus ret = SUCCESS;
cau_key_parameter_struct key_initpara;
cau_iv_parameter_struct iv_initpara;
uint64_t aadlength = (uint64_t)cau_parameter->aad_size * 8U;
uint64_t inputlength = (uint64_t)cau_parameter->in_length * 8U;
uint32_t ivaddr = (uint32_t)cau_parameter->iv;
uint32_t tagaddr = (uint32_t)tag;
/* key structure initialization */
cau_key_struct_para_init(&key_initpara);
/* initialize the CAU peripheral */
cau_init(cau_parameter->alg_dir, CAU_MODE_AES_GCM, CAU_SWAPPING_8BIT);
/* AES key structure parameter config */
cau_aes_key_config(cau_parameter->key, cau_parameter->key_size, &key_initpara);
/* key initialization */
cau_key_init(&key_initpara);
/* vectors initialization */
iv_initpara.iv_0_high = __REV(*(uint32_t *)(ivaddr));
ivaddr += 4U;
iv_initpara.iv_0_low = __REV(*(uint32_t *)(ivaddr));
ivaddr += 4U;
iv_initpara.iv_1_high = __REV(*(uint32_t *)(ivaddr));
ivaddr += 4U;
iv_initpara.iv_1_low = __REV(*(uint32_t *)(ivaddr));
cau_iv_init(&iv_initpara);
/* prepare phase */
/* select prepare phase */
cau_phase_config(CAU_PREPARE_PHASE);
/* enable the CAU peripheral */
cau_enable();
/* wait for CAUEN bit to be 0 */
while(ENABLE == cau_enable_state_get()) {
}
/* aad phase */
if((uint32_t)0U != cau_parameter->aad_size) {
/* select aad phase */
cau_phase_config(CAU_AAD_PHASE);
/* flush the IN and OUT FIFOs */
cau_fifo_flush();
/* enable the CAU peripheral */
cau_enable();
ret = cau_fill_data(cau_parameter->aad, cau_parameter->aad_size);
if(ERROR == ret) {
return ret;
}
}
/* encrypt or decrypt phase */
if((uint32_t)0U != cau_parameter->in_length) {
/* select encrypt or decrypt phase */
cau_phase_config(CAU_ENCRYPT_DECRYPT_PHASE);
/* flush the IN and OUT FIFOs */
cau_fifo_flush();
/* enable the CAU peripheral */
cau_enable();
/* AES calculate process */
ret = cau_aes_calculate(cau_parameter->input, cau_parameter->in_length, output);
if(ERROR == ret) {
return ret;
}
}
/* tag phase */
/* select tag phase */
cau_phase_config(CAU_TAG_PHASE);
/* flush the IN and OUT FIFOs */
cau_fifo_flush();
/* enable the CAU peripheral */
cau_enable();
if(DISABLE == cau_enable_state_get()) {
return ERROR;
}
cau_data_write(__REV((uint32_t)(aadlength >> 32U)));
cau_data_write(__REV((uint32_t)aadlength));
cau_data_write(__REV((uint32_t)(inputlength >> 32U)));
cau_data_write(__REV((uint32_t)inputlength));
/* wait until the ONE flag is set */
while(RESET == cau_flag_get(CAU_FLAG_OUTFIFO_NO_EMPTY)) {
}
/* read the tag in the OUT FIFO */
*(uint32_t *)(tagaddr) = cau_data_read();
tagaddr += 4U;
*(uint32_t *)(tagaddr) = cau_data_read();
tagaddr += 4U;
*(uint32_t *)(tagaddr) = cau_data_read();
tagaddr += 4U;
*(uint32_t *)(tagaddr) = cau_data_read();
/* disable the CAU peripheral */
cau_disable();
return ret;
}
/*!
\brief encrypt and decrypt using AES in CCM mode
\param[in] cau_parameter: pointer to the input structure
alg_dir: algorithm directory
CAU_ENCRYPT, CAU_DECRYPT
key: key
key_size: key size in bytes
iv: initialization vector
iv_size: iv size in bytes
input: input data
in_length: input data length in bytes
aad: additional authentication data
aad_size: aad size
\param[in] mac_size: mac size (in bytes)
\param[out] output: pointer to the returned output data buffer
\param[out] tag: pointer to the returned tag buffer
\param[out] aad_buf: pointer to the user buffer used when formatting aad block
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus cau_aes_ccm(cau_parameter_struct *cau_parameter, uint8_t *output, uint8_t tag[], uint32_t tag_size, uint8_t aad_buf[])
{
cau_key_parameter_struct key_initpara;
cau_iv_parameter_struct iv_initpara;
ErrStatus ret = ERROR;
uint32_t inputaddr = (uint32_t)cau_parameter->input;
uint32_t inputsize = cau_parameter->in_length;
uint32_t aadaddr = (uint32_t)cau_parameter->aad;
uint32_t aadsize = cau_parameter->aad_size;
uint32_t aad_block_size = 0U;
uint32_t ivaddr = (uint32_t)cau_parameter->iv;
uint32_t ivsize = cau_parameter->iv_size;
uint32_t outputaddr = (uint32_t)output;
uint32_t i = 0U, plen = 0U;
uint32_t head_index = 0U;
uint8_t blockb0[16U] = {0U};
uint8_t counter[16U] = {0U};
uint32_t ctraddr = (uint32_t)counter;
uint32_t b0addr = (uint32_t)blockb0;
uint32_t temp_tag[4U];
/* formatting the aad block */
if((uint32_t)0U != aadsize) {
/* check that the aad length is lower than 2^16 - 2^8 = 65536 - 256 = 65280 */
if(aadsize < 65280U) {
aad_buf[head_index++] = (uint8_t)((aadsize >> 8U) & 0xFFU);
aad_buf[head_index++] = (uint8_t)((aadsize) & 0xFFU);
aad_block_size = aadsize + 2U;
} else {
/* aad is encoded as 0xFF || 0xFE || [aadsize]32, i.e., six octets */
aad_buf[head_index++] = 0xFFU;
aad_buf[head_index++] = 0xFEU;
aad_buf[head_index++] = (uint8_t)((aadsize & 0xFF000000U) >> 24U);
aad_buf[head_index++] = (uint8_t)((aadsize & 0x00FF0000U) >> 16U);
aad_buf[head_index++] = (uint8_t)((aadsize & 0x0000FF00U) >> 8U);
aad_buf[head_index++] = (uint8_t)(aadsize & 0x000000FFU);
aad_block_size = aadsize + 6U;
}
/* copy the aad buffer in internal buffer "HBuffer" */
for(i = 0U; i < aadsize; i++) {
aad_buf[head_index++] = *(uint8_t *)((uint32_t)(aadaddr + i));
}
/* check if the aad block size is modulo 16 */
if(0U != (aad_block_size % 16U)) {
/* Pad the aad buffer with 0s till the HBuffer length is modulo 16 */
for(i = aad_block_size; i <= ((aad_block_size / 16U) + 1U) * 16U; i++) {
aad_buf[i] = 0U;
}
/* set the aad size to modulo 16 */
aad_block_size = ((aad_block_size / 16U) + 1U) * 16U;
}
/* set the pointer aadaddr to HBuffer */
aadaddr = (uint32_t)aad_buf;
}
/* formatting the block B0 */
if(0U != aadsize) {
blockb0[0] = 0x40U;
}
/* flags byte */
blockb0[0] |= (0U | (((((uint8_t) tag_size - 2U) / 2U) & 0x07U) << 3U) | (((uint8_t)(15U - ivsize) - 1U) & 0x07U));
if((MIN_CCM_IV_SIZE > ivsize) || (MAX_CCM_IV_SIZE < ivsize)) {
return ERROR;
}
for(i = 0U; i < ivsize; i++) {
blockb0[i + 1U] = *(uint8_t *)((uint32_t)(ivaddr + i));
}
/* the byte length for payload length expressing, which plus the ivsize must equal to 15 bytes */
plen = 15U - ivsize;
/* if the byte length for payload length expressing is more than 4 bytes */
if(plen > 4U) {
/* pad the blockb0 after vectors, and before the last 4 bytes */
for(; i < 11U; i++) {
blockb0[i + 1U] = 0U;
}
blockb0[12U] = (uint8_t)((inputsize >> 24U) & 0xFFU);
blockb0[13U] = (uint8_t)((inputsize >> 16U) & 0xFFU);
blockb0[14U] = (uint8_t)((inputsize >> 8U) & 0xFFU);
blockb0[15U] = (uint8_t)(inputsize & 0xFFU);
} else {
/* the payload length is expressed in plen bytes */
for(; i < 15U; i++) {
blockb0[i + 1U] = (uint8_t)((inputsize >> ((uint8_t)((plen - 1U) * 8U))) & 0xFFU);
plen--;
}
}
/* formatting the initial counter */
/* byte 0: bits 0-2 contain the same encoding of q as in B0 */
counter[0] = blockb0[0] & BLOCK_B0_MASK;
for(i = 1U; i < ivsize + 1U; i++) {
counter[i] = blockb0[i];
}
/* set the LSB to 1 */
counter[15] |= 0x01U;
/* prepare phase */
/* flush the IN and OUT FIFOs */
cau_fifo_flush();
/* clear CAUEN bit to ensure CAU is disable */
cau_disable();
/* key structure initialization */
cau_key_struct_para_init(&key_initpara);
/* initialize the CAU peripheral */
cau_init(cau_parameter->alg_dir, CAU_MODE_AES_CCM, CAU_SWAPPING_8BIT);
/* select init phase */
cau_phase_config(CAU_PREPARE_PHASE);
/* AES key structure parameter config */
cau_aes_key_config(cau_parameter->key, cau_parameter->key_size, &key_initpara);
/* key initialization */
cau_key_init(&key_initpara);
/* vectors initialization */
iv_initpara.iv_0_high = __REV(*(uint32_t *)(ctraddr));
ctraddr += 4U;
iv_initpara.iv_0_low = __REV(*(uint32_t *)(ctraddr));
ctraddr += 4U;
iv_initpara.iv_1_high = __REV(*(uint32_t *)(ctraddr));
ctraddr += 4U;
iv_initpara.iv_1_low = __REV(*(uint32_t *)(ctraddr));
cau_iv_init(&iv_initpara);
/* enable the CAU peripheral */
cau_enable();
/* write block B0 in the In FIFO */
cau_data_write(*(uint32_t *)(b0addr));
b0addr += 4U;
cau_data_write(*(uint32_t *)(b0addr));
b0addr += 4U;
cau_data_write(*(uint32_t *)(b0addr));
b0addr += 4U;
cau_data_write(*(uint32_t *)(b0addr));
/* wait for CAUEN bit to be 0 */
while(ENABLE == cau_enable_state_get()) {
}
/* aad phase */
if((uint32_t)0U != aadsize) {
/* select aad phase */
cau_phase_config(CAU_AAD_PHASE);
/* enable the CAU peripheral */
cau_enable();
ret = cau_fill_data((uint8_t *)aadaddr, aad_block_size);
if(ERROR == ret) {
return ret;
}
}
/* encrypt or decrypt phase */
inputsize = cau_parameter->in_length;
if((uint32_t)0U != inputsize) {
/* select encrypt or decrypt phase */
cau_phase_config(CAU_ENCRYPT_DECRYPT_PHASE);
/* enable the CAU peripheral */
cau_enable();
/* AES calculate process */
ret = cau_aes_calculate((uint8_t *)inputaddr, inputsize, (uint8_t *)outputaddr);
if(ERROR == ret) {
return ret;
}
}
/* tag phase */
/* select final phase */
cau_phase_config(CAU_TAG_PHASE);
/* enable the CAU peripheral */
cau_enable();
if(DISABLE == cau_enable_state_get()) {
return ERROR;
}
ctraddr = (uint32_t)counter;
cau_data_write(*(uint32_t *)(ctraddr));
ctraddr += 4U;
cau_data_write(*(uint32_t *)(ctraddr));
ctraddr += 4U;
cau_data_write(*(uint32_t *)(ctraddr));
ctraddr += 4U;
/* reset bit 0 (after 8-bit swap) is equivalent to reset bit 24 (before 8-bit swap) */
cau_data_write(*(uint32_t *)(ctraddr) & 0xFEFFFFFFU);
/* wait until the ONE flag is set */
while(RESET == cau_flag_get(CAU_FLAG_OUTFIFO_NO_EMPTY)) {
}
/* read the tag in the OUT FIFO */
temp_tag[0] = cau_data_read();
temp_tag[1] = cau_data_read();
temp_tag[2] = cau_data_read();
temp_tag[3] = cau_data_read();
/* disable the CAU peripheral */
cau_disable();
/* Copy temporary authentication TAG in user TAG buffer */
for(i = 0U; i < tag_size; i++) {
tag[i] = (uint8_t)(temp_tag[i / 4U] >> (8U * (i % 4U)));
}
return ret;
}
/*!
\brief AES key structure parameter config
\param[in] key: key used for AES algorithm
\param[in] keysize: length of the key in bits, must be either 128, 192 or 256
\param[out] cau_key_initpara: key init parameter struct
key_0_high: key 0 high
key_0_low: key 0 low
key_1_high: key 1 high
key_1_low: key 1 low
key_2_high: key 2 high
key_2_low: key 2 low
key_3_high: key 3 high
key_3_low: key 3 low
\retval none
*/
static void cau_aes_key_config(uint8_t *key, uint32_t keysize, cau_key_parameter_struct *cau_key_initpara)
{
uint32_t keyaddr = (uint32_t)key;
switch(keysize) {
/* 128-bit key initialization */
case 128:
cau_aes_keysize_config(CAU_KEYSIZE_128BIT);
cau_key_initpara->key_2_high = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
cau_key_initpara->key_2_low = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
cau_key_initpara->key_3_high = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
cau_key_initpara->key_3_low = __REV(*(uint32_t *)(keyaddr));
break;
/* 192-bit key initialization */
case 192:
cau_aes_keysize_config(CAU_KEYSIZE_192BIT);
cau_key_initpara->key_1_high = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
cau_key_initpara->key_1_low = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
cau_key_initpara->key_2_high = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
cau_key_initpara->key_2_low = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
cau_key_initpara->key_3_high = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
cau_key_initpara->key_3_low = __REV(*(uint32_t *)(keyaddr));
break;
/* 256-bit key initialization */
case 256:
cau_aes_keysize_config(CAU_KEYSIZE_256BIT);
cau_key_initpara->key_0_high = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
cau_key_initpara->key_0_low = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
cau_key_initpara->key_1_high = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
cau_key_initpara->key_1_low = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
cau_key_initpara->key_2_high = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
cau_key_initpara->key_2_low = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
cau_key_initpara->key_3_high = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
cau_key_initpara->key_3_low = __REV(*(uint32_t *)(keyaddr));
break;
default:
break;
}
}
/*!
\brief fill data into data input register
\param[in] input: pointer to the input buffer
\param[in] in_length: length of the input buffer in bytes, must be a multiple of 16 bytes
\retval ErrStatus: SUCCESS or ERROR
*/
static ErrStatus cau_fill_data(uint8_t *input, uint32_t in_length)
{
uint32_t inputaddr = (uint32_t)input;
uint32_t i = 0U;
__IO uint32_t counter = 0U;
uint32_t busystatus = 0U;
if(DISABLE == cau_enable_state_get()) {
return ERROR;
}
for(i = 0U; i < in_length; i += BLOCK_DATA_SIZE) {
/* wait until the IEM flag is set */
while(RESET == cau_flag_get(CAU_FLAG_INFIFO_EMPTY)) {
}
if(i + BLOCK_DATA_SIZE > in_length) {
/* the last block data number is less than 128bit */
uint32_t block_data_temp[4] = {0U};
/* fill the remaining bits with zero */
memcpy(block_data_temp, (uint32_t *)inputaddr, in_length - i);
inputaddr = (uint32_t)block_data_temp;
/* if GCM encryption or CCM decryption, then configurate NBPILB bits in CTL register */
if((CAU_CTL & CAU_CTL_GCM_CCMPH) == CAU_ENCRYPT_DECRYPT_PHASE) {
if((CAU_CTL & (CAU_CTL_ALGM | CAU_CTL_CAUDIR)) == (CAU_MODE_AES_GCM | CAU_ENCRYPT)) {
CAU_CTL |= CAU_PADDING_BYTES(i + BLOCK_DATA_SIZE - in_length);
} else if((CAU_CTL & (CAU_CTL_ALGM | CAU_CTL_CAUDIR)) == (CAU_MODE_AES_CCM | CAU_DECRYPT)) {
CAU_CTL |= CAU_PADDING_BYTES(i + BLOCK_DATA_SIZE - in_length);
} else {
}
}
}
/* write data to the IN FIFO */
cau_data_write(*(uint32_t *)(inputaddr));
inputaddr += 4U;
cau_data_write(*(uint32_t *)(inputaddr));
inputaddr += 4U;
cau_data_write(*(uint32_t *)(inputaddr));
inputaddr += 4U;
cau_data_write(*(uint32_t *)(inputaddr));
inputaddr += 4U;
}
/* wait until the complete message has been processed */
counter = 0U;
do {
busystatus = cau_flag_get(CAU_FLAG_BUSY);
counter++;
} while((AESBSY_TIMEOUT != counter) && (RESET != busystatus));
if(RESET != busystatus) {
return ERROR;
}
return SUCCESS;
}
/*!
\brief AES calculate process
\param[in] input: pointer to the input buffer
\param[in] in_length: length of the input buffer in bytes, must be a multiple of 16 bytes
\param[out] output: pointer to the returned buffer
\retval ErrStatus: SUCCESS or ERROR
*/
static ErrStatus cau_aes_calculate(uint8_t *input, uint32_t in_length, uint8_t *output)
{
uint32_t inputaddr = (uint32_t)input;
uint32_t outputaddr = (uint32_t)output;
uint32_t i = 0U;
__IO uint32_t counter = 0U;
uint32_t busystatus = 0U;
/* the clock is not enabled or there is no embedded CAU peripheral */
if(DISABLE == cau_enable_state_get()) {
return ERROR;
}
for(i = 0U; i < in_length; i += BLOCK_DATA_SIZE) {
/* wait until the IEM flag is set */
while(RESET == cau_flag_get(CAU_FLAG_INFIFO_EMPTY)) {
}
/* check if the last input data block */
if(i + BLOCK_DATA_SIZE > in_length) {
/* the last block data number is less than 128bit */
uint32_t block_data_temp[4] = {0};
/* fill the remaining bits with zero */
memcpy(block_data_temp, (uint32_t *)inputaddr, in_length - i);
inputaddr = (uint32_t)block_data_temp;
/* if GCM encryption or CCM decryption, then configurate NBPILB bits in CTL register */
if((CAU_CTL & (CAU_CTL_ALGM | CAU_CTL_CAUDIR)) == (CAU_MODE_AES_GCM | CAU_ENCRYPT)) {
CAU_CTL |= CAU_PADDING_BYTES(i + BLOCK_DATA_SIZE - in_length);
} else if((CAU_CTL & (CAU_CTL_ALGM | CAU_CTL_CAUDIR)) == (CAU_MODE_AES_CCM | CAU_DECRYPT)) {
CAU_CTL |= CAU_PADDING_BYTES(i + BLOCK_DATA_SIZE - in_length);
} else {
}
}
/* write data to the IN FIFO */
cau_data_write(*(uint32_t *)(inputaddr));
inputaddr += 4U;
cau_data_write(*(uint32_t *)(inputaddr));
inputaddr += 4U;
cau_data_write(*(uint32_t *)(inputaddr));
inputaddr += 4U;
cau_data_write(*(uint32_t *)(inputaddr));
inputaddr += 4U;
/* wait until the complete message has been processed */
counter = 0U;
do {
busystatus = cau_flag_get(CAU_FLAG_BUSY);
counter++;
} while((AESBSY_TIMEOUT != counter) && (RESET != busystatus));
if(RESET != busystatus) {
return ERROR;
} else {
/* read the output block from the output FIFO */
*(uint32_t *)(outputaddr) = cau_data_read();
outputaddr += 4U;
*(uint32_t *)(outputaddr) = cau_data_read();
outputaddr += 4U;
*(uint32_t *)(outputaddr) = cau_data_read();
outputaddr += 4U;
*(uint32_t *)(outputaddr) = cau_data_read();
outputaddr += 4U;
}
}
return SUCCESS;
}
@@ -0,0 +1,183 @@
/*!
\file gd32h7xx_cau_des.c
\brief CAU DES driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_cau.h"
#define DESBUSY_TIMEOUT ((uint32_t)0x00010000U)
/* DES calculate process */
static ErrStatus cau_des_calculate(uint8_t *input, uint32_t in_length, uint8_t *output);
/*!
\brief encrypt and decrypt using DES in ECB mode
\param[in] cau_parameter: pointer to the input structure
alg_dir: algorithm directory
CAU_ENCRYPT, CAU_DECRYPT
key: key, 8 bytes
input: input data
in_length: input data length in bytes, must be a multiple of 8 bytes
\param[out] output: pointer to the output buffer
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus cau_des_ecb(cau_parameter_struct *cau_parameter, uint8_t *output)
{
ErrStatus ret = ERROR;
cau_key_parameter_struct key_initpara;
uint32_t keyaddr = (uint32_t)(cau_parameter->key);
uint32_t inputaddr = (uint32_t)(cau_parameter->input);
uint32_t outputaddr = (uint32_t)output;
/* key structure initialization */
cau_key_struct_para_init(&key_initpara);
/* initialize the CAU peripheral */
cau_init(cau_parameter->alg_dir, CAU_MODE_DES_ECB, CAU_SWAPPING_8BIT);
/* key initialisation */
key_initpara.key_1_high = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
key_initpara.key_1_low = __REV(*(uint32_t *)(keyaddr));
cau_key_init(&key_initpara);
/* flush the IN and OUT FIFOs */
cau_fifo_flush();
/* enable the CAU peripheral */
cau_enable();
/* DES calculate process */
ret = cau_des_calculate((uint8_t *)inputaddr, cau_parameter->in_length, (uint8_t *)outputaddr);
/* disable the CAU peripheral */
cau_disable();
return ret;
}
/*!
\brief encrypt and decrypt using DES in CBC mode
\param[in] cau_parameter: pointer to the input structure
alg_dir: algorithm directory
CAU_ENCRYPT, CAU_DECRYPT
key: key, 8 bytes
iv: initialization vector, 8 bytes
input: input data
in_length: input data length in bytes, must be a multiple of 8 bytes
\param[out] output: pointer to the output structure
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus cau_des_cbc(cau_parameter_struct *cau_parameter, uint8_t *output)
{
ErrStatus ret = ERROR;
cau_key_parameter_struct key_initpara;
cau_iv_parameter_struct iv_initpara;
uint32_t keyaddr = (uint32_t)(cau_parameter->key);
uint32_t inputaddr = (uint32_t)(cau_parameter->input);
uint32_t outputaddr = (uint32_t)output;
uint32_t ivaddr = (uint32_t)(cau_parameter->iv);
/* key structure initialization */
cau_key_struct_para_init(&key_initpara);
/* initialize the CAU peripheral */
cau_init(cau_parameter->alg_dir, CAU_MODE_DES_CBC, CAU_SWAPPING_8BIT);
/* key initialisation */
key_initpara.key_1_high = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
key_initpara.key_1_low = __REV(*(uint32_t *)(keyaddr));
cau_key_init(&key_initpara);
/* vectors initialization */
iv_initpara.iv_0_high = __REV(*(uint32_t *)(ivaddr));
ivaddr += 4U;
iv_initpara.iv_0_low = __REV(*(uint32_t *)(ivaddr));
cau_iv_init(&iv_initpara);
/* flush the IN and OUT FIFOs */
cau_fifo_flush();
/* enable the CAU peripheral */
cau_enable();
/* DES calculate process */
ret = cau_des_calculate((uint8_t *)inputaddr, cau_parameter->in_length, (uint8_t *)outputaddr);
/* disable the CAU peripheral */
cau_disable();
return ret;
}
/*!
\brief DES calculate process
\param[in] input: pointer to the input buffer
\param[in] in_length: length of the input buffer in bytes, must be a multiple of 8 bytes
\param[in] output: pointer to the returned buffer
\param[out] none
\retval ErrStatus: SUCCESS or ERROR
*/
static ErrStatus cau_des_calculate(uint8_t *input, uint32_t in_length, uint8_t *output)
{
uint32_t inputaddr = (uint32_t)input;
uint32_t outputaddr = (uint32_t)output;
uint32_t i = 0U;
__IO uint32_t counter = 0U;
uint32_t busystatus = 0U;
/* the clock is not enabled or there is no embedded CAU peripheral */
if(DISABLE == cau_enable_state_get()) {
return ERROR;
}
for(i = 0U; i < in_length; i += 8U) {
/* write data to the IN FIFO */
cau_data_write(*(uint32_t *)(inputaddr));
inputaddr += 4U;
cau_data_write(*(uint32_t *)(inputaddr));
inputaddr += 4U;
/* wait until the complete message has been processed */
counter = 0U;
do {
busystatus = cau_flag_get(CAU_FLAG_BUSY);
counter++;
} while((DESBUSY_TIMEOUT != counter) && (RESET != busystatus));
if(RESET != busystatus) {
return ERROR;
} else {
/* read the output block from the output FIFO */
*(uint32_t *)(outputaddr) = cau_data_read();
outputaddr += 4U;
*(uint32_t *)(outputaddr) = cau_data_read();
outputaddr += 4U;
}
}
return SUCCESS;
}
@@ -0,0 +1,198 @@
/*!
\file gd32h7xx_cau_tdes.c
\brief CAU TDES driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_cau.h"
#define TDESBSY_TIMEOUT ((uint32_t)0x00010000U)
/* TDES calculate process */
static ErrStatus cau_tdes_calculate(uint8_t *input, uint32_t in_length, uint8_t *output);
/*!
\brief encrypt and decrypt using TDES in ECB mode
\param[in] cau_parameter: pointer to the input structure
alg_dir: algorithm directory
CAU_ENCRYPT, CAU_DECRYPT
key: key, 24 bytes
input: input data
in_length: input data length in bytes, must be a multiple of 8 bytes
\param[out] output: pointer to the output structure
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus cau_tdes_ecb(cau_parameter_struct *cau_parameter, uint8_t *output)
{
ErrStatus ret = ERROR;
cau_key_parameter_struct key_initpara;
uint32_t keyaddr = (uint32_t)(cau_parameter->key);
uint32_t inputaddr = (uint32_t)(cau_parameter->input);
uint32_t outputaddr = (uint32_t)output;
/* key structure initialization */
cau_key_struct_para_init(&key_initpara);
/* initialize the CAU peripheral */
cau_init(cau_parameter->alg_dir, CAU_MODE_TDES_ECB, CAU_SWAPPING_8BIT);
/* key initialization */
key_initpara.key_1_high = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
key_initpara.key_1_low = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
key_initpara.key_2_high = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
key_initpara.key_2_low = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
key_initpara.key_3_high = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
key_initpara.key_3_low = __REV(*(uint32_t *)(keyaddr));
cau_key_init(&key_initpara);
/* flush the IN and OUT FIFOs */
cau_fifo_flush();
/* enable the CAU peripheral */
cau_enable();
/* TDES calculate process */
ret = cau_tdes_calculate((uint8_t *)inputaddr, cau_parameter->in_length, (uint8_t *)outputaddr);
/* disable the CAU peripheral */
cau_disable();
return ret;
}
/*!
\brief encrypt and decrypt using TDES in CBC mode
\param[in] cau_parameter: pointer to the input structure
alg_dir: algorithm directory
CAU_ENCRYPT, CAU_DECRYPT
key: key, 24 bytes
iv: initialization vector, 8 bytes
input: input data
in_length: input data length in bytes, must be a multiple of 8 bytes
\param[out] output: pointer to the output structure
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus cau_tdes_cbc(cau_parameter_struct *cau_parameter, uint8_t *output)
{
ErrStatus ret = ERROR;
cau_key_parameter_struct key_initpara;
cau_iv_parameter_struct iv_initpara;
uint32_t keyaddr = (uint32_t)(cau_parameter->key);
uint32_t inputaddr = (uint32_t)(cau_parameter->input);
uint32_t outputaddr = (uint32_t)output;
uint32_t ivaddr = (uint32_t)(cau_parameter->iv);
/* key structure initialization */
cau_key_struct_para_init(&key_initpara);
/* initialize the CAU peripheral */
cau_init(cau_parameter->alg_dir, CAU_MODE_TDES_CBC, CAU_SWAPPING_8BIT);
/* key initialization */
key_initpara.key_1_high = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
key_initpara.key_1_low = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
key_initpara.key_2_high = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
key_initpara.key_2_low = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
key_initpara.key_3_high = __REV(*(uint32_t *)(keyaddr));
keyaddr += 4U;
key_initpara.key_3_low = __REV(*(uint32_t *)(keyaddr));
cau_key_init(&key_initpara);
/* vectors initialization */
iv_initpara.iv_0_high = __REV(*(uint32_t *)(ivaddr));
ivaddr += 4U;
iv_initpara.iv_0_low = __REV(*(uint32_t *)(ivaddr));
cau_iv_init(&iv_initpara);
/* flush the IN and OUT FIFOs */
cau_fifo_flush();
/* enable the CAU peripheral */
cau_enable();
/* TDES calculate process */
ret = cau_tdes_calculate((uint8_t *)inputaddr, cau_parameter->in_length, (uint8_t *)outputaddr);
/* disable the CAU peripheral */
cau_disable();
return ret;
}
/*!
\brief TDES calculate process
\param[in] input: pointer to the input buffer
\param[in] in_length: length of the input buffer in bytes, must be a multiple of 8 bytes
\param[out] output: pointer to the returned buffer
\retval ErrStatus: SUCCESS or ERROR
*/
static ErrStatus cau_tdes_calculate(uint8_t *input, uint32_t in_length, uint8_t *output)
{
uint32_t inputaddr = (uint32_t)input;
uint32_t outputaddr = (uint32_t)output;
uint32_t i = 0U;
__IO uint32_t counter = 0U;
uint32_t busystatus = 0U;
/* the clock is not enabled or there is no embedded CAU peripheral */
if(DISABLE == cau_enable_state_get()) {
return ERROR;
}
for(i = 0U; i < in_length; i += 8U) {
/* write data to the IN FIFO */
cau_data_write(*(uint32_t *)(inputaddr));
inputaddr += 4U;
cau_data_write(*(uint32_t *)(inputaddr));
inputaddr += 4U;
/* wait until the complete message has been processed */
counter = 0U;
do {
busystatus = cau_flag_get(CAU_FLAG_BUSY);
counter++;
} while((TDESBSY_TIMEOUT != counter) && (RESET != busystatus));
if(RESET != busystatus) {
return ERROR;
} else {
/* read the output block from the output FIFO */
*(uint32_t *)(outputaddr) = cau_data_read();
outputaddr += 4U;
*(uint32_t *)(outputaddr) = cau_data_read();
outputaddr += 4U;
}
}
return SUCCESS;
}
@@ -0,0 +1,577 @@
/*!
\file gd32h7xx_cmp.c
\brief CMP driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_cmp.h"
/*!
\brief CMP deinit
\param[in] cmp_periph
\arg CMP0: comparator 0
\arg CMP1: comparator 1
\param[out] none
\retval none
*/
void cmp_deinit(cmp_enum cmp_periph)
{
if(CMP0 == cmp_periph){
CMP0_CS &= ((uint32_t)0x00000000U);
CMP_IFC &= ((uint32_t)0xFFFEFFFFU);
CMP_STAT &= ((uint32_t)0xFFFEFFFEU);
CMP_SR &= ((uint32_t)0x00000000U);
}else if(CMP1 == cmp_periph){
CMP1_CS &= ((uint32_t)0x00000000U);
CMP_IFC &= ((uint32_t)0xFFFDFFFFU);
CMP_STAT &= ((uint32_t)0xFFFDFFFDU);
CMP_SR &= ((uint32_t)0x00000000U);
}else{
}
}
/*!
\brief CMP mode init
\param[in] cmp_periph
\arg CMP0: comparator 0
\arg CMP1: comparator 1
\param[in] operating_mode
\arg CMP_MODE_HIGHSPEED: high speed mode
\arg CMP_MODE_MIDDLESPEED: medium 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_DAC0_OUT0: CMP inverting input DAC0_OUT0
\arg CMP_INVERTING_INPUT_DAC0_OUT1: CMP inverting input DAC0_OUT1
\arg CMP_INVERTING_INPUT_PB1_PE10: PB1 for CMP0 or PE10 for CMP1 as inverting input
\arg CMP_INVERTING_INPUT_PC4_PE7: PC4 for CMP0 or PE7 for CMP1 as inverting input
\param[in] 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 = CMP0_CS;
temp &= ~(uint32_t)(CMP_CS_CMPXM | CMP_CS_CMPXMISEL | CMP_CS_CMPXHST);
temp |= (uint32_t)(operating_mode | inverting_input | output_hysteresis);
CMP0_CS = temp;
}else if(CMP1 == cmp_periph){
/* initialize comparator 1 mode */
temp = CMP1_CS;
temp &= ~(uint32_t)(CMP_CS_CMPXM | CMP_CS_CMPXMISEL | CMP_CS_CMPXHST);
temp |= (uint32_t)(operating_mode | inverting_input | output_hysteresis);
CMP1_CS = temp;
}else{
}
}
/*!
\brief CMP noninverting input select
\param[in] cmp_periph
\arg CMP0: comparator 0
\arg CMP1: comparator 1
\param[in] noninverting_input
\arg CMP_NONINVERTING_INPUT_PB0_PE9: CMP noninverting input PB0 for CMP0 or PE9 for CMP1
\arg CMP_NONINVERTING_INPUT_PB2_PE12: CMP noninverting input PB2 for CMP0 or PE12 for CMP1
\param[out] none
\retval none
*/
void cmp_noninverting_input_select(cmp_enum cmp_periph, uint32_t noninverting_input)
{
uint32_t temp = 0U;
if(CMP0 == cmp_periph){
temp = CMP0_CS;
temp &= ~(uint32_t)CMP_CS_CMPXPSEL;
temp |= (uint32_t)noninverting_input;
CMP0_CS = temp;
}else if(CMP1 == cmp_periph){
temp = CMP1_CS;
temp &= ~(uint32_t)CMP_CS_CMPXPSEL;
temp |= (uint32_t)noninverting_input;
CMP1_CS = temp;
}else{
}
}
/*!
\brief CMP output init
\param[in] cmp_periph
\arg CMP0: comparator 0
\arg CMP1: comparator 1
\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_polarity)
{
uint32_t temp = 0U;
if(CMP0 == cmp_periph){
/* initialize comparator 0 output */
temp = CMP0_CS;
/* output polarity */
if(CMP_OUTPUT_POLARITY_INVERTED == output_polarity){
temp |= (uint32_t)CMP_CS_CMPXPL;
}else{
temp &= ~(uint32_t)CMP_CS_CMPXPL;
}
CMP0_CS = temp;
}else if(CMP1 == cmp_periph){
/* initialize comparator 1 output */
temp = CMP1_CS;
/* output polarity */
if(CMP_OUTPUT_POLARITY_INVERTED == output_polarity){
temp |= (uint32_t)CMP_CS_CMPXPL;
}else{
temp &= ~(uint32_t)CMP_CS_CMPXPL;
}
CMP1_CS = temp;
}else{
}
}
/*!
\brief config comparator output port
\param[in] cmp_periph
\arg CMP0: comparator 0
\arg CMP1: comparator 1
\param[in] cmp_output_sel
\arg CMP_AFSE_GPIO_PA6: CMP alternate GPIO PA6
\arg CMP_AFSE_GPIO_PA8: CMP alternate GPIO PA8
\arg CMP_AFSE_GPIO_PB12: CMP alternate GPIO PB12
\arg CMP_AFSE_GPIO_PE6: CMP alternate GPIO PE6
\arg CMP_AFSE_GPIO_PE15: CMP alternate GPIO PE15
\arg CMP_AFSE_GPIO_PG2: CMP alternate GPIO PG2
\arg CMP_AFSE_GPIO_PG3: CMP alternate GPIO PG3
\arg CMP_AFSE_GPIO_PG4: CMP alternate GPIO PG4
\arg CMP_AFSE_GPIO_PK0: CMP alternate GPIO PK0
\arg CMP_AFSE_GPIO_PK1: CMP alternate GPIO PK1
\arg CMP_AFSE_GPIO_PK2: CMP alternate GPIO PK2
\param[out] none
\retval none
*/
void cmp_output_mux_config(cmp_enum cmp_periph, uint32_t cmp_output_sel)
{
if(CMP0 == cmp_periph){
CMP_SR &= ~(uint32_t)cmp_output_sel;
}else if(CMP1 == cmp_periph){
CMP_SR |= cmp_output_sel;
}else{
}
}
/*!
\brief CMP output blanking function init
\param[in] cmp_periph
\arg CMP0: comparator 0
\arg CMP1: comparator 1
\param[in] blanking_source_selection
\arg CMP_BLANKING_NONE: CMP no blanking source
\arg CMP_BLANKING_TIMER0_OC0: CMP TIMER0_CH0 output compare signal selected as blanking source
\arg CMP_BLANKING_TIMER1_OC2: CMP TIMER1_CH2 output compare signal selected as blanking source
\arg CMP_BLANKING_TIMER2_OC2: CMP TIMER2_CH2 output compare signal selected as blanking source
\arg CMP_BLANKING_TIMER2_OC3: CMP TIMER2_CH3 output compare signal selected as blanking source
\arg CMP_BLANKING_TIMER7_OC0: CMP TIMER7_CH0 output compare signal selected as blanking source
\arg CMP_BLANKING_TIMER14_OC0: CMP TIMER14_CH0 output compare signal selected as blanking source
\param[out] none
\retval none
*/
void cmp_blanking_init(cmp_enum cmp_periph, uint32_t blanking_source_selection)
{
uint32_t temp = 0U;
if(CMP0 == cmp_periph){
temp = CMP0_CS;
temp &= ~(uint32_t)CMP_CS_CMPXBLK;
temp |= (uint32_t)blanking_source_selection;
CMP0_CS = temp;
}else if(CMP1 == cmp_periph){
temp = CMP1_CS;
temp &= ~(uint32_t)CMP_CS_CMPXBLK;
temp |= (uint32_t)blanking_source_selection;
CMP1_CS = temp;
}else{
}
}
/*!
\brief enable CMP
\param[in] cmp_periph
\arg CMP0: comparator 0
\arg CMP1: comparator 1
\param[out] none
\retval none
*/
void cmp_enable(cmp_enum cmp_periph)
{
if(CMP0 == cmp_periph){
CMP0_CS |= (uint32_t)CMP_CS_CMPXEN;
}else if(CMP1 == cmp_periph){
CMP1_CS |= (uint32_t)CMP_CS_CMPXEN;
}else{
}
}
/*!
\brief disable CMP
\param[in] cmp_periph
\arg CMP0: comparator 0
\arg CMP1: comparator 1
\param[out] none
\retval none
*/
void cmp_disable(cmp_enum cmp_periph)
{
if(CMP0 == cmp_periph){
CMP0_CS &= ~(uint32_t)CMP_CS_CMPXEN;
}else if(CMP1 == cmp_periph){
CMP1_CS &= ~(uint32_t)CMP_CS_CMPXEN;
}else{
}
}
/*!
\brief enable the window mode
\param[in] none
\param[out] none
\retval none
*/
void cmp_window_enable(void)
{
CMP1_CS |= (uint32_t)CMP_CS_WNDEN;
}
/*!
\brief disable the window mode
\param[in] none
\param[out] none
\retval none
*/
void cmp_window_disable(void)
{
CMP1_CS &= ~(uint32_t)CMP_CS_WNDEN;
}
/*!
\brief lock the comparator
\param[in] cmp_periph
\arg CMP0: comparator 0
\arg CMP1: comparator 1
\param[out] none
\retval none
*/
void cmp_lock_enable(cmp_enum cmp_periph)
{
if(CMP0 == cmp_periph){
/* lock CMP0 */
CMP0_CS |= (uint32_t)CMP_CS_CMPXLK;
}else if(CMP1 == cmp_periph){
/* lock CMP1 */
CMP1_CS |= (uint32_t)CMP_CS_CMPXLK;
}else{
}
}
/*!
\brief enable the voltage scaler
\param[in] cmp_periph
\arg CMP0: comparator 0
\arg CMP1: comparator 1
\param[out] none
\retval none
*/
void cmp_voltage_scaler_enable(cmp_enum cmp_periph)
{
if(CMP0 == cmp_periph){
CMP0_CS |= (uint32_t)CMP_CS_CMPXSEN;
}else if(CMP1 == cmp_periph){
CMP1_CS |= (uint32_t)CMP_CS_CMPXSEN;
}else{
}
}
/*!
\brief disable the voltage scaler
\param[in] cmp_periph
\arg CMP0: comparator 0
\arg CMP1: comparator 1
\param[out] none
\retval none
*/
void cmp_voltage_scaler_disable(cmp_enum cmp_periph)
{
if(CMP0 == cmp_periph){
CMP0_CS &= ~(uint32_t)CMP_CS_CMPXSEN;
}else if(CMP1 == cmp_periph){
CMP1_CS &= ~(uint32_t)CMP_CS_CMPXSEN;
}else{
}
}
/*!
\brief enable the scaler bridge
\param[in] cmp_periph
\arg CMP0: comparator 0
\arg CMP1: comparator 1
\param[out] none
\retval none
*/
void cmp_scaler_bridge_enable(cmp_enum cmp_periph)
{
if(CMP0 == cmp_periph){
CMP0_CS |= (uint32_t)CMP_CS_CMPXBEN;
}else if(CMP1 == cmp_periph){
CMP1_CS |= (uint32_t)CMP_CS_CMPXBEN;
}else{
}
}
/*!
\brief disable the scaler bridge
\param[in] cmp_periph
\arg CMP0: comparator 0
\arg CMP1: comparator 1
\param[out] none
\retval none
*/
void cmp_scaler_bridge_disable(cmp_enum cmp_periph)
{
if(CMP0 == cmp_periph){
CMP0_CS &= ~(uint32_t)CMP_CS_CMPXBEN;
}else if(CMP1 == cmp_periph){
CMP1_CS &= ~(uint32_t)CMP_CS_CMPXBEN;
}else{
}
}
/*!
\brief get output level
\param[in] cmp_periph
\arg CMP0: comparator 0
\arg CMP1: comparator 1
\param[out] none
\retval the output level
*/
uint32_t cmp_output_level_get(cmp_enum cmp_periph)
{
if(CMP0 == cmp_periph){
/* get output level of CMP0 */
if((uint32_t)RESET != (CMP_STAT & CMP_STAT_CMP0O)) {
return CMP_OUTPUTLEVEL_HIGH;
}else{
return CMP_OUTPUTLEVEL_LOW;
}
}else{
/* get output level of CMP1 */
if((uint32_t)RESET != (CMP_STAT & CMP_STAT_CMP1O)) {
return CMP_OUTPUTLEVEL_HIGH;
}else{
return CMP_OUTPUTLEVEL_LOW;
}
}
}
/*!
\brief get CMP flag
\param[in] cmp_periph
\arg CMP0: comparator 0
\arg CMP1: comparator 1
\param[in] flag: CMP flags
\arg CMP_FLAG_COMPARE: CMP compare flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus cmp_flag_get(cmp_enum cmp_periph, uint32_t flag)
{
FlagStatus reval = RESET;
if(CMP0 == cmp_periph){
if(CMP_FLAG_COMPARE == flag){
if(0U != (CMP_STAT & CMP_STAT_CMP0IF)){
reval = SET;
}
}
}else if(CMP1 == cmp_periph){
if(CMP_FLAG_COMPARE == flag){
if(0U != (CMP_STAT & CMP_STAT_CMP1IF)){
reval = SET;
}
}
}
return reval;
}
/*!
\brief clear CMP flag
\param[in] cmp_periph
\arg CMP0: comparator 0
\arg CMP1: comparator 1
\param[in] flag: CMP flags
\arg CMP_FLAG_COMPARE: CMP compare flag
\param[out] none
\retval none
*/
void cmp_flag_clear(cmp_enum cmp_periph, uint32_t flag)
{
if(CMP0 == cmp_periph){
if(CMP_FLAG_COMPARE == flag){
CMP_IFC |= (uint32_t)CMP_IFC_CMP0IC;
}
}else if(CMP1 == cmp_periph){
if(CMP_FLAG_COMPARE == flag){
CMP_IFC |= (uint32_t)CMP_IFC_CMP1IC;
}
}else{
}
}
/*!
\brief enable CMP interrupt
\param[in] cmp_periph
\arg CMP0: comparator 0
\arg CMP1: comparator 1
\param[in] interrupt: CMP interrupt enable source
only one parameter can be selected which is shown as below:
\arg CMP_INT_COMPARE: CMP compare interrupt
\param[out] none
\retval none
*/
void cmp_interrupt_enable(cmp_enum cmp_periph, uint32_t interrupt)
{
if(CMP0 == cmp_periph){
/* enable CMP0 interrupt */
CMP0_CS |= (uint32_t)interrupt;
}else if(CMP1 == cmp_periph){
/* enable CMP1 interrupt */
CMP1_CS |= (uint32_t)interrupt;
}else{
}
}
/*!
\brief disable CMP interrupt
\param[in] cmp_periph
\arg CMP0: comparator 0
\arg CMP1: comparator 1
\param[in] interrupt: CMP interrupt enable source
only one parameter can be selected which is shown as below:
\arg CMP_INT_COMPARE: CMP compare interrupt
\param[out] none
\retval none
*/
void cmp_interrupt_disable(cmp_enum cmp_periph, uint32_t interrupt)
{
if(CMP0 == cmp_periph){
/* disable CMP0 interrupt */
CMP0_CS &= ~(uint32_t)interrupt;
}else if(CMP1 == cmp_periph){
/* disable CMP1 interrupt */
CMP1_CS &= ~(uint32_t)interrupt;
}else{
}
}
/*!
\brief get CMP interrupt flag
\param[in] cmp_periph
\arg CMP0: comparator 0
\arg CMP1: comparator 1
\param[in] flag: CMP interrupt flags
\arg CMP_INT_FLAG_COMPARE: CMP compare interrupt flag
\param[out] none
\retval none
*/
FlagStatus cmp_interrupt_flag_get(cmp_enum cmp_periph, uint32_t flag)
{
uint32_t intstatus = 0U, flagstatus = 0U;
if(CMP0 == cmp_periph){
if(CMP_INT_FLAG_COMPARE == flag){
/* get the corresponding flag bit status */
flagstatus = CMP_STAT & CMP_STAT_CMP0IF;
/* get the interrupt enable bit status */
intstatus = CMP0_CS & CMP_CS_CMPXINTEN;
}
}else if(CMP1 == cmp_periph){
if(CMP_INT_FLAG_COMPARE == flag){
/* get the corresponding flag bit status */
flagstatus = CMP_STAT & CMP_STAT_CMP1IF;
/* get the interrupt enable bit status */
intstatus = CMP1_CS & CMP_CS_CMPXINTEN;
}
}else{
}
if((0U != flagstatus) && (0U != intstatus)){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear CMP interrupt flag
\param[in] cmp_periph
\arg CMP0: comparator 0
\arg CMP1: comparator 1
\param[in] flag: CMP interrupt flags
\arg CMP_INT_FLAG_COMPARE: CMP compare interrupt flag
\param[out] none
\retval none
*/
void cmp_interrupt_flag_clear(cmp_enum cmp_periph, uint32_t flag)
{
/* clear CMP interrupt flag */
if(CMP0 == cmp_periph){
if(CMP_INT_FLAG_COMPARE == flag){
CMP_IFC |= (uint32_t)CMP_IFC_CMP0IC;
}
}else if(CMP1 == cmp_periph){
if(CMP_INT_FLAG_COMPARE == flag){
CMP_IFC |= (uint32_t)CMP_IFC_CMP1IC;
}
}else{
}
}
@@ -0,0 +1,276 @@
/*!
\file gd32h7xx_cpdm.c
\brief CPDM driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_cpdm.h"
#define CPDM_CPSEL_MASK ((uint32_t)0xFFFFFFF0U) /*!< CPDM output clock phase seclection mask */
#define CPDM_DLSTCNT_MASK ((uint32_t)0xFFFF80FFU) /*!< CPDM delay step count for a uint delay UINT mask */
#define CPDM_DLLENF_MASK ((uint32_t)0x80000000U) /*!< CPDM delay line length valid flag mask */
#define CPDM_DLLEN_MASK ((uint32_t)0x0FFF0000U) /*!< CPDM delay line length mask */
#define CPDM_DLLEN_OFFSET ((uint32_t)16U) /*!< CPDM delay line length offset */
#define CPDM_DLSTCNT_OFFSET ((uint32_t)8U) /*!< CPDM delay step count for a uint delay UINT offset */
#define CPDM_DLLEN_11 ((uint32_t)0x04000000U) /*!< CPDM delay line length bit 11 */
#define CPDM_DLLEN_10 ((uint32_t)0x08000000U) /*!< CPDM delay line length bit 10 */
#define CPDM_DLLEN_10_0_MASK ((uint32_t)0x7FFU) /*!< CPDM delay line length bit 10 to bit 0 mask */
#define CPDM_MAX_TIMEOUT ((uint32_t)0x0000FFFFU) /*!< count to judge of CPDM timeout */
/*!
\brief enable CPDM
\param[in] cpdm_periph: the clock phase delay module of SDIO
only one parameter can be selected which is shown as below:
\arg CPDM_SDIO0: clock phase delay module of SDIO0
\arg CPDM_SDIO1: clock phase delay module of SDIO1
\param[out] none
\retval none
*/
void cpdm_enable(uint32_t cpdm_periph)
{
/* enable CPDM */
CPDM_CTL(cpdm_periph) |= (uint32_t)CPDM_CTL_CPDMEN;
}
/*!
\brief disable CPDM
\param[in] cpdm_periph: the clock phase delay module of SDIO
only one parameter can be selected which is shown as below:
\arg CPDM_SDIO0: clock phase delay module of SDIO0
\arg CPDM_SDIO1: clock phase delay module of SDIO1
\param[out] none
\retval none
*/
void cpdm_disable(uint32_t cpdm_periph)
{
/* disable CPDM */
CPDM_CTL(cpdm_periph) &= ~(uint32_t)CPDM_CTL_CPDMEN;
}
/*!
\brief enable CPDM delay line sample module
\param[in] cpdm_periph: the clock phase delay module of SDIO
only one parameter can be selected which is shown as below:
\arg CPDM_SDIO0: clock phase delay module of SDIO0
\arg CPDM_SDIO1: clock phase delay module of SDIO1
\param[out] none
\retval none
*/
void cpdm_delayline_sample_enable(uint32_t cpdm_periph)
{
/* enable CPDM delay line sample module */
CPDM_CTL(cpdm_periph) |= (uint32_t)CPDM_CTL_DLSEN;
}
/*!
\brief disable CPDM delay line sample module
\param[in] cpdm_periph: the clock phase delay module of SDIO
only one parameter can be selected which is shown as below:
\arg CPDM_SDIO0: clock phase delay module of SDIO0
\arg CPDM_SDIO1: clock phase delay module of SDIO1
\param[out] none
\retval none
*/
void cpdm_delayline_sample_disable(uint32_t cpdm_periph)
{
/* disable CPDM delay line sample module */
CPDM_CTL(cpdm_periph) &= ~(uint32_t)CPDM_CTL_DLSEN;
}
/*!
\brief select CPDM output clock phase
\param[in] cpdm_periph: the clock phase delay module of SDIO
only one parameter can be selected which is shown as below:
\arg CPDM_SDIO0: clock phase delay module of SDIO0
\arg CPDM_SDIO1: clock phase delay module of SDIO1
\param[in] output_clock_phase: the output clock phase, refer to cpdm_output_phase_enum
only one parameter can be selected which is shown as below:
\arg CPDM_OUTPUT_PHASE_SELECTION_0: output clock phase = input clock
\arg CPDM_OUTPUT_PHASE_SELECTION_1: output clock phase = input clock + 1 * UNIT delay
\arg CPDM_OUTPUT_PHASE_SELECTION_2: output clock phase = input clock + 2 * UNIT delay
\arg CPDM_OUTPUT_PHASE_SELECTION_3: output clock phase = input clock + 3 * UNIT delay
\arg CPDM_OUTPUT_PHASE_SELECTION_4: output clock phase = input clock + 4 * UNIT delay
\arg CPDM_OUTPUT_PHASE_SELECTION_5: output clock phase = input clock + 5 * UNIT delay
\arg CPDM_OUTPUT_PHASE_SELECTION_6: output clock phase = input clock + 6 * UNIT delay
\arg CPDM_OUTPUT_PHASE_SELECTION_7: output clock phase = input clock + 7 * UNIT delay
\arg CPDM_OUTPUT_PHASE_SELECTION_8: output clock phase = input clock + 8 * UNIT delay
\arg CPDM_OUTPUT_PHASE_SELECTION_9: output clock phase = input clock + 9 * UNIT delay
\arg CPDM_OUTPUT_PHASE_SELECTION_10: output clock phase = input clock + 10 * UNIT delay
\arg CPDM_OUTPUT_PHASE_SELECTION_11: output clock phase = input clock + 11 * UNIT delay
\arg CPDM_OUTPUT_PHASE_SELECTION_12: output clock phase = input clock + 12 * UNIT delay
\param[out] none
\retval none
*/
void cpdm_output_clock_phase_select(uint32_t cpdm_periph, cpdm_output_phase_enum output_clock_phase)
{
uint32_t reg = 0U;
reg = CPDM_CFG(cpdm_periph);
reg &= CPDM_CPSEL_MASK;
/* select CPDM output clock phase */
reg |= output_clock_phase;
CPDM_CFG(cpdm_periph) = (uint32_t)reg;
}
/*!
\brief configure CPDM delay step
\param[in] cpdm_periph: the clock phase delay module of SDIO
only one parameter can be selected which is shown as below:
\arg CPDM_SDIO0: clock phase delay module of SDIO0
\arg CPDM_SDIO1: clock phase delay module of SDIO1
\param[in] delay_step: 0 ~ 127
\param[out] none
\retval none
*/
void cpdm_delay_step_config(uint32_t cpdm_periph, uint8_t delay_step)
{
uint32_t reg = 0U;
reg = CPDM_CFG(cpdm_periph);
reg &= CPDM_DLSTCNT_MASK;
/* configure delay step */
reg |= ((uint32_t)delay_step << CPDM_DLSTCNT_OFFSET);
CPDM_CFG(cpdm_periph) = (uint32_t)reg;
}
/*!
\brief get delay line length valid flag
\param[in] cpdm_periph: the clock phase delay module of SDIO
only one parameter can be selected which is shown as below:
\arg CPDM_SDIO0: clock phase delay module of SDIO0
\arg CPDM_SDIO1: clock phase delay module of SDIO1
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus cpdm_delayline_length_valid_flag_get(uint32_t cpdm_periph)
{
uint32_t reg = 0U;
reg = CPDM_CFG(cpdm_periph);
if(reg & CPDM_DLLENF_MASK) {
return SET;
} else {
return RESET;
}
}
/*!
\brief get delay line length
\param[in] cpdm_periph: the clock phase delay module of SDIO
only one parameter can be selected which is shown as below:
\arg CPDM_SDIO0: clock phase delay module of SDIO0
\arg CPDM_SDIO1: clock phase delay module of SDIO1
\param[out] none
\retval the value of delay line length, 0x00~0xFFF
*/
uint16_t cpdm_delayline_length_get(uint32_t cpdm_periph)
{
return (uint16_t)((CPDM_CFG(cpdm_periph) & CPDM_DLLEN_MASK) >> CPDM_DLLEN_OFFSET);
}
/*!
\brief configure CPDM clock output
\param[in] cpdm_periph: the clock phase delay module of SDIO
only one parameter can be selected which is shown as below:
\arg CPDM_SDIO0: clock phase delay module of SDIO0
\arg CPDM_SDIO1: clock phase delay module of SDIO1
\param[in] output_clock_phase: the output clock phase, refer to cpdm_output_phase_enum
only one parameter can be selected which is shown as below:
\arg CPDM_OUTPUT_PHASE_SELECTION_0: output clock phase = input clock
\arg CPDM_OUTPUT_PHASE_SELECTION_1: output clock phase = input clock + 1 * UNIT delay
\arg CPDM_OUTPUT_PHASE_SELECTION_2: output clock phase = input clock + 2 * UNIT delay
\arg CPDM_OUTPUT_PHASE_SELECTION_3: output clock phase = input clock + 3 * UNIT delay
\arg CPDM_OUTPUT_PHASE_SELECTION_4: output clock phase = input clock + 4 * UNIT delay
\arg CPDM_OUTPUT_PHASE_SELECTION_5: output clock phase = input clock + 5 * UNIT delay
\arg CPDM_OUTPUT_PHASE_SELECTION_6: output clock phase = input clock + 6 * UNIT delay
\arg CPDM_OUTPUT_PHASE_SELECTION_7: output clock phase = input clock + 7 * UNIT delay
\arg CPDM_OUTPUT_PHASE_SELECTION_8: output clock phase = input clock + 8 * UNIT delay
\arg CPDM_OUTPUT_PHASE_SELECTION_9: output clock phase = input clock + 9 * UNIT delay
\arg CPDM_OUTPUT_PHASE_SELECTION_10: output clock phase = input clock + 10 * UNIT delay
\arg CPDM_OUTPUT_PHASE_SELECTION_11: output clock phase = input clock + 11 * UNIT delay
\arg CPDM_OUTPUT_PHASE_SELECTION_12: output clock phase = input clock + 12 * UNIT delay
\param[out] none
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus cpdm_clock_output(uint32_t cpdm_periph, cpdm_output_phase_enum output_clock_phase)
{
uint32_t reg = 0U;
uint32_t reg_cfg = 0U;
uint32_t delay_count = 0U;
uint32_t timeout = 0U;
/* enable CPDM and delay line sample module */
CPDM_CTL(cpdm_periph) = 0U;
CPDM_CTL(cpdm_periph) = CPDM_CTL_CPDMEN | CPDM_CTL_DLSEN;
/* configure CPDM output clock phase to the max value (12) */
reg = CPDM_CFG(cpdm_periph);
reg &= CPDM_CPSEL_MASK;
reg |= CPDM_MAX_PHASE;
CPDM_CFG(cpdm_periph) = (uint32_t)reg;
for(delay_count = 0U; delay_count <= CPDM_MAX_DELAY_STEP_COUNT; delay_count++) {
reg = CPDM_CFG(cpdm_periph);
reg &= CPDM_DLSTCNT_MASK;
/* configure delay line step count */
reg |= delay_count << CPDM_DLSTCNT_OFFSET;
CPDM_CFG(cpdm_periph) = (uint32_t)reg;
while(RESET == (CPDM_CFG(cpdm_periph) & CPDM_CFG_DLLENF)) {
timeout++;
if(timeout > CPDM_MAX_TIMEOUT)
{
return ERROR;
}
}
reg_cfg = CPDM_CFG(cpdm_periph);
if((((reg_cfg >> CPDM_DLLEN_OFFSET) & CPDM_DLLEN_10_0_MASK) > 0U) &&
((RESET == (reg_cfg & CPDM_DLLEN_11)) || (RESET == (reg_cfg & CPDM_DLLEN_10)))) {
break;
}
}
/* enable CPDM and delay line sample module */
CPDM_CTL(cpdm_periph) = 0U;
CPDM_CTL(cpdm_periph) = CPDM_CTL_CPDMEN | CPDM_CTL_DLSEN;
/* select the output clock phase */
reg = CPDM_CFG(cpdm_periph);
reg &= CPDM_CPSEL_MASK;
reg |= output_clock_phase;
CPDM_CFG(cpdm_periph) = (uint32_t)reg;
/* disable delay line sample module */
CPDM_CTL(cpdm_periph) = CPDM_CTL_CPDMEN;
return SUCCESS;
}
@@ -0,0 +1,247 @@
/*!
\file gd32h7xx_crc.c
\brief CRC driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_crc.h"
#define CRC_IDATA_RESET_VALUE ((uint32_t)0xFFFFFFFFU)
#define CRC_DATA_RESET_VALUE ((uint32_t)0xFFFFFFFFU)
#define CRC_FDATA_RESET_VALUE ((uint32_t)0x00000000U)
#define CRC_POLY_RESET_VALUE ((uint32_t)0x04C11DB7U)
/*!
\brief deinit CRC calculation unit
\param[in] none
\param[out] none
\retval none
*/
void crc_deinit(void)
{
CRC_IDATA = CRC_IDATA_RESET_VALUE;
CRC_DATA = CRC_DATA_RESET_VALUE;
CRC_FDATA = CRC_FDATA_RESET_VALUE;
CRC_POLY = CRC_POLY_RESET_VALUE;
CRC_CTL = (uint32_t)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 initialization 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 initialization 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 = 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 if(INPUT_FORMAT_BYTE == data_format) {
REG8(CRC) = (uint8_t)sdata;
} else {
}
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);
}
@@ -0,0 +1,390 @@
/*!
\file gd32h7xx_ctc.c
\brief CTC driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_ctc.h"
#define CTC_FLAG_MASK ((uint32_t)0x00000700U)
/* CTC register bit offset */
#define CTC_TRIMVALUE_OFFSET ((uint32_t)8U)
#define CTC_TRIM_VALUE_OFFSET ((uint32_t)8U)
#define CTC_REFCAP_OFFSET ((uint32_t)16U)
#define CTC_LIMIT_VALUE_OFFSET ((uint32_t)16U)
/*!
\brief reset CTC clock trim controller
\param[in] none
\param[out] none
\retval none
*/
void ctc_deinit(void)
{
/* reset CTC */
rcu_periph_reset_enable(RCU_CTCRST);
rcu_periph_reset_disable(RCU_CTCRST);
}
/*!
\brief enable CTC trim counter
\param[in] none
\param[out] none
\retval none
*/
void ctc_counter_enable(void)
{
CTC_CTL0 |= (uint32_t)CTC_CTL0_CNTEN;
}
/*!
\brief disable CTC trim counter
\param[in] none
\param[out] none
\retval none
*/
void ctc_counter_disable(void)
{
CTC_CTL0 &= (uint32_t)(~CTC_CTL0_CNTEN);
}
/*!
\brief configure the IRC48M trim value
\param[in] trim_value: 8-bit IRC48M trim value
\arg 0x00 - 0x3F
\param[out] none
\retval none
*/
void ctc_irc48m_trim_value_config(uint8_t trim_value)
{
/* clear TRIMVALUE bits */
CTC_CTL0 &= (~(uint32_t)CTC_CTL0_TRIMVALUE);
/* set TRIMVALUE bits */
CTC_CTL0 |= ((uint32_t)trim_value << CTC_TRIM_VALUE_OFFSET);
}
/*!
\brief generate software reference source sync pulse
\param[in] none
\param[out] none
\retval none
*/
void ctc_software_refsource_pulse_generate(void)
{
CTC_CTL0 |= (uint32_t)CTC_CTL0_SWREFPUL;
}
/*!
\brief configure hardware automatically trim mode
\param[in] hardmode:
only one parameter can be selected which is shown as below:
\arg CTC_HARDWARE_TRIM_MODE_ENABLE: hardware automatically trim mode enable
\arg CTC_HARDWARE_TRIM_MODE_DISABLE: hardware automatically trim mode disable
\param[out] none
\retval none
*/
void ctc_hardware_trim_mode_config(uint32_t hardmode)
{
CTC_CTL0 &= (uint32_t)(~CTC_CTL0_AUTOTRIM);
CTC_CTL0 |= (uint32_t)hardmode;
}
/*!
\brief configure reference signal source polarity
\param[in] polarity: reference signal source edge
only one parameter can be selected which is shown as below:
\arg CTC_REFSOURCE_POLARITY_FALLING: reference signal source polarity is falling edge
\arg CTC_REFSOURCE_POLARITY_RISING: reference signal source polarity is rising edge
\param[out] none
\retval none
*/
void ctc_refsource_polarity_config(uint32_t polarity)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_REFPOL);
CTC_CTL1 |= (uint32_t)polarity;
}
/*!
\brief select reference signal source
\param[in] refs: reference signal source
only one parameter can be selected which is shown as below:
\arg CTC_REFSOURCE_GPIO: GPIO is selected
\arg CTC_REFSOURCE_LXTAL: LXTAL is selected
\param[out] none
\retval none
*/
void ctc_refsource_signal_select(uint32_t refs)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_REFSEL);
CTC_CTL1 |= (uint32_t)refs;
}
/*!
\brief configure reference signal source prescaler
\param[in] prescaler: reference signal source prescaler
only one parameter can be selected which is shown as below:
\arg CTC_REFSOURCE_PSC_OFF: reference signal not divided
\arg CTC_REFSOURCE_PSC_DIV2: reference signal divided by 2
\arg CTC_REFSOURCE_PSC_DIV4: reference signal divided by 4
\arg CTC_REFSOURCE_PSC_DIV8: reference signal divided by 8
\arg CTC_REFSOURCE_PSC_DIV16: reference signal divided by 16
\arg CTC_REFSOURCE_PSC_DIV32: reference signal divided by 32
\arg CTC_REFSOURCE_PSC_DIV64: reference signal divided by 64
\arg CTC_REFSOURCE_PSC_DIV128: reference signal divided by 128
\param[out] none
\retval none
*/
void ctc_refsource_prescaler_config(uint32_t prescaler)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_REFPSC);
CTC_CTL1 |= (uint32_t)prescaler;
}
/*!
\brief configure clock trim base limit value
\param[in] limit_value: 8-bit clock trim base limit value
\arg 0x00 - 0xFF
\param[out] none
\retval none
*/
void ctc_clock_limit_value_config(uint8_t limit_value)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_CKLIM);
CTC_CTL1 |= (uint32_t)((uint32_t)limit_value << CTC_LIMIT_VALUE_OFFSET);
}
/*!
\brief configure CTC counter reload value
\param[in] reload_value: 16-bit CTC counter reload value
\arg 0x0000 - 0xFFFF
\param[out] none
\retval none
*/
void ctc_counter_reload_value_config(uint16_t reload_value)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_RLVALUE);
CTC_CTL1 |= (uint32_t)reload_value;
}
/*!
\brief read CTC counter capture value when reference sync pulse occurred
\param[in] none
\param[out] none
\retval the 16-bit CTC counter capture value
*/
uint16_t ctc_counter_capture_value_read(void)
{
uint16_t capture_value = 0U;
capture_value = (uint16_t)((CTC_STAT & CTC_STAT_REFCAP)>> CTC_REFCAP_OFFSET);
return (capture_value);
}
/*!
\brief read CTC trim counter direction when reference sync pulse occurred
\param[in] none
\param[out] none
\retval FlagStatus: SET or RESET
\arg SET: CTC trim counter direction is down-counting
\arg RESET: CTC trim counter direction is up-counting
*/
FlagStatus ctc_counter_direction_read(void)
{
if(RESET != (CTC_STAT & CTC_STAT_REFDIR)){
return SET;
}else{
return RESET;
}
}
/*!
\brief read CTC counter reload value
\param[in] none
\param[out] none
\retval the 16-bit CTC counter reload value
*/
uint16_t ctc_counter_reload_value_read(void)
{
uint16_t reload_value = 0U;
reload_value = (uint16_t)(CTC_CTL1 & CTC_CTL1_RLVALUE);
return (reload_value);
}
/*!
\brief read the IRC48M trim value
\param[in] none
\param[out] none
\retval the 8-bit IRC48M trim value
*/
uint8_t ctc_irc48m_trim_value_read(void)
{
uint8_t trim_value = 0U;
trim_value = (uint8_t)((CTC_CTL0 & CTC_CTL0_TRIMVALUE) >> CTC_TRIMVALUE_OFFSET);
return (trim_value);
}
/*!
\brief get CTC flag
\param[in] flag: the CTC flag
only one parameter can be selected which is shown as below:
\arg CTC_FLAG_CKOK: clock trim OK flag
\arg CTC_FLAG_CKWARN: clock trim warning flag
\arg CTC_FLAG_ERR: error flag
\arg CTC_FLAG_EREF: expect reference flag
\arg CTC_FLAG_CKERR: clock trim error flag
\arg CTC_FLAG_REFMISS: reference sync pulse miss flag
\arg CTC_FLAG_TRIMERR: trim value error flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus ctc_flag_get(uint32_t flag)
{
if(RESET != (CTC_STAT & flag)){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear CTC flag
\param[in] flag: the CTC flag
only one parameter can be selected which is shown as below:
\arg CTC_FLAG_CKOK: clock trim OK flag
\arg CTC_FLAG_CKWARN: clock trim warning flag
\arg CTC_FLAG_ERR: error flag
\arg CTC_FLAG_EREF: expect reference flag
\arg CTC_FLAG_CKERR: clock trim error flag
\arg CTC_FLAG_REFMISS: reference sync pulse miss flag
\arg CTC_FLAG_TRIMERR: trim value error flag
\param[out] none
\retval none
*/
void ctc_flag_clear(uint32_t flag)
{
if(RESET != (flag & CTC_FLAG_MASK)){
CTC_INTC |= CTC_INTC_ERRIC;
}else{
CTC_INTC |= flag;
}
}
/*!
\brief enable the CTC interrupt
\param[in] interrupt: CTC interrupt enable source
one or more parameters can be selected which are shown as below:
\arg CTC_INT_CKOK: clock trim OK interrupt
\arg CTC_INT_CKWARN: clock trim warning interrupt
\arg CTC_INT_ERR: error interrupt
\arg CTC_INT_EREF: expect reference interrupt
\param[out] none
\retval none
*/
void ctc_interrupt_enable(uint32_t interrupt)
{
CTC_CTL0 |= (uint32_t)interrupt;
}
/*!
\brief disable the CTC interrupt
\param[in] interrupt: CTC interrupt disable source
one or more parameters can be selected which are shown as below:
\arg CTC_INT_CKOK: clock trim OK interrupt
\arg CTC_INT_CKWARN: clock trim warning interrupt
\arg CTC_INT_ERR: error interrupt
\arg CTC_INT_EREF: expect reference interrupt
\param[out] none
\retval none
*/
void ctc_interrupt_disable(uint32_t interrupt)
{
CTC_CTL0 &= (uint32_t)(~interrupt);
}
/*!
\brief get CTC interrupt flag
\param[in] int_flag: the CTC interrupt flag
only one parameter can be selected which is shown as below:
\arg CTC_INT_FLAG_CKOK: clock trim OK interrupt flag
\arg CTC_INT_FLAG_CKWARN: clock trim warning interrupt flag
\arg CTC_INT_FLAG_ERR: error interrupt flag
\arg CTC_INT_FLAG_EREF: expect reference interrupt flag
\arg CTC_INT_FLAG_CKERR: clock trim error bit interrupt flag
\arg CTC_INT_FLAG_REFMISS: reference sync pulse miss interrupt flag
\arg CTC_INT_FLAG_TRIMERR: trim value error interrupt flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus ctc_interrupt_flag_get(uint32_t int_flag)
{
uint32_t interrupt_flag = 0U, intenable = 0U;
/* check whether the interrupt is enabled */
if(RESET != (int_flag & CTC_FLAG_MASK)){
intenable = CTC_CTL0 & CTC_CTL0_ERRIE;
}else{
intenable = CTC_CTL0 & int_flag;
}
/* get interrupt flag status */
interrupt_flag = CTC_STAT & int_flag;
if(interrupt_flag && intenable){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear CTC interrupt flag
\param[in] int_flag: the CTC interrupt flag
only one parameter can be selected which is shown as below:
\arg CTC_INT_FLAG_CKOK: clock trim OK interrupt flag
\arg CTC_INT_FLAG_CKWARN: clock trim warning interrupt flag
\arg CTC_INT_FLAG_ERR: error interrupt flag
\arg CTC_INT_FLAG_EREF: expect reference interrupt flag
\arg CTC_INT_FLAG_CKERR: clock trim error bit interrupt flag
\arg CTC_INT_FLAG_REFMISS: reference sync pulse miss interrupt flag
\arg CTC_INT_FLAG_TRIMERR: trim value error interrupt flag
\param[out] none
\retval none
*/
void ctc_interrupt_flag_clear(uint32_t int_flag)
{
if(RESET != (int_flag & CTC_FLAG_MASK)){
CTC_INTC |= CTC_INTC_ERRIC;
}else{
CTC_INTC |= int_flag;
}
}
@@ -0,0 +1,754 @@
/*!
\file gd32h7xx_dac.c
\brief DAC driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_dac.h"
/* DAC register bit offset */
#define OUT1_REG_OFFSET ((uint32_t)0x00000010U)
#define DH_12BIT_OFFSET ((uint32_t)0x00000010U)
#define DH_8BIT_OFFSET ((uint32_t)0x00000008U)
#define DAC_STAT_FLAG_MASK0 (DAC_FLAG_DDUDR0 | DAC_FLAG_DDUDR1 | DAC_FLAG_CALF0 | DAC_FLAG_CALF1 | DAC_FLAG_BWT0 | DAC_FLAG_BWT1)
#define DAC_INT_EN_MASK0 (DAC_INT_DDUDR0 | DAC_INT_DDUDR1)
#define DAC_INT_FLAG_MASK0 (DAC_INT_FLAG_DDUDR0 | DAC_INT_FLAG_DDUDR1)
/*!
\brief deinitialize DAC
\param[in] dac_periph: DACx(x=0)
\param[out] none
\retval none
*/
void dac_deinit(uint32_t dac_periph)
{
switch(dac_periph){
case DAC0:
/* reset DAC0 */
rcu_periph_reset_enable(RCU_DACRST);
rcu_periph_reset_disable(RCU_DACRST);
break;
default:
break;
}
}
/*!
\brief enable DAC
\param[in] dac_periph: DACx(x=0)
\param[in] dac_out: DAC_OUTx(x=0,1)
\param[out] none
\retval none
*/
void dac_enable(uint32_t dac_periph, uint8_t dac_out)
{
if(DAC_OUT0 == dac_out){
DAC_CTL0(dac_periph) |= (uint32_t)DAC_CTL0_DEN0;
}else if(DAC_OUT1 == dac_out){
DAC_CTL0(dac_periph) |= (uint32_t)DAC_CTL0_DEN1;
}else{
/* illegal parameters */
}
}
/*!
\brief disable DAC
\param[in] dac_periph: DACx(x=0)
\param[in] dac_out: DAC_OUTx(x=0,1)
\param[out] none
\retval none
*/
void dac_disable(uint32_t dac_periph, uint8_t dac_out)
{
if(DAC_OUT0 == dac_out){
DAC_CTL0(dac_periph) &= (uint32_t)(~DAC_CTL0_DEN0);
}else if(DAC_OUT1 == dac_out){
DAC_CTL0(dac_periph) &= (uint32_t)(~DAC_CTL0_DEN1);
}else{
/* illegal parameters */
}
}
/*!
\brief enable DAC DMA function
\param[in] dac_periph: DACx(x=0)
\param[in] dac_out: DAC_OUTx(x=0,1)
\param[out] none
\retval none
*/
void dac_dma_enable(uint32_t dac_periph, uint8_t dac_out)
{
if(DAC_OUT0 == dac_out){
DAC_CTL0(dac_periph) |= (uint32_t)DAC_CTL0_DDMAEN0;
}else if(DAC_OUT1 == dac_out){
DAC_CTL0(dac_periph) |= (uint32_t)DAC_CTL0_DDMAEN1;
}else{
/* illegal parameters */
}
}
/*!
\brief disable DAC DMA function
\param[in] dac_periph: DACx(x=0)
\param[in] dac_out: DAC_OUTx(x=0,1)
\param[out] none
\retval none
*/
void dac_dma_disable(uint32_t dac_periph, uint8_t dac_out)
{
if(DAC_OUT0 == dac_out){
DAC_CTL0(dac_periph) &= (uint32_t)(~DAC_CTL0_DDMAEN0);
}else if(DAC_OUT1 == dac_out){
DAC_CTL0(dac_periph) &= (uint32_t)(~DAC_CTL0_DDMAEN1);
}else{
/* illegal parameters */
}
}
/*!
\brief configure DAC mode
\param[in] dac_periph: DACx(x=0)
\param[in] dac_out: DAC_OUTx(x=0,1)
\param[in] mode: DAC working mode
only one parameter can be selected which is shown as below:
\arg NORMAL_PIN_BUFFON: DAC_OUT_x work in normal mode and connect to external pin with buffer enable
\arg NORMAL_PIN_PERIPHERAL_BUFFON: DAC_OUT_x work in normal mode and connect to external pin and on chip peripherals with buffer enable
\arg NORMAL_PIN_BUFFOFF: DAC_OUT_x work in normal mode and connect to external pin with buffer disable
\arg NORMAL_PIN_PERIPHERAL_BUFFOFF: DAC_OUT_x work in normal mode and connect to on chip peripherals with buffer disable
\arg SAMPLEKEEP_PIN_BUFFON: DAC_OUT_x work in sample and keep mode and connect to external pin with buffer enable
\arg SAMPLEKEEP_PIN_PERIPHERAL_BUFFON: DAC_OUT_x work in sample and keep mode and connect to external pin and on chip peripherals with buffer enable
\arg SAMPLEKEEP_PIN_BUFFOFF: DAC_OUT_x work in sample and keep mode and connect to external pin and on chip peripherals with buffer enable
\arg SAMPLEKEEP_PIN_PERIPHERAL_BUFFOFF: DAC_OUT_x work in sample and keep mode and connect to on chip peripherals with buffer disable
\param[out] none
\retval none
*/
void dac_mode_config(uint32_t dac_periph, uint32_t dac_out, uint32_t mode)
{
if(DAC_OUT0 == dac_out){
/* configure DAC0 mode */
DAC_MDCR(dac_periph) &= ~(uint32_t)DAC_MDCR_MODE0;
DAC_MDCR(dac_periph) |= mode;
}else if(DAC_OUT1 == dac_out){
/* configure DAC1 mode */
DAC_MDCR(dac_periph) &= ~(uint32_t)DAC_MDCR_MODE1;
DAC_MDCR(dac_periph) |= (mode << OUT1_REG_OFFSET);
}else{
/* illegal parameters */
}
}
/*!
\brief get the DACx trimming value
\param[in] dac_periph: DACx(x=0)
\param[in] dac_out: DAC_OUTx(x=0,1)
\param[out] none
\retval DACx trimming value
*/
uint32_t dac_trimming_value_get(uint32_t dac_periph, uint32_t dac_out)
{
uint32_t tmp = 0U;
if(DAC_OUT0 == dac_out) {
/* get the DAC_OUT_0 trimming value */
tmp = DAC_CALR(dac_periph) & DAC_CALR_OTV0;
} else if(DAC_OUT1 == dac_out) {
/* get the DAC_OUT_1 trimming value */
tmp = (DAC_CALR(dac_periph) & DAC_CALR_OTV1) >> OUT1_REG_OFFSET;
} else {
}
return tmp;
}
/*!
\brief set the DACx trimming value
\param[in] dac_periph: DACx(x=0)
\param[in] dac_out: DAC_OUTx(x=0,1)
\param[in] trim_value: set new DAC trimming value
\param[out] none
*/
void dac_trimming_value_set(uint32_t dac_periph, uint32_t dac_out, uint32_t trim_value)
{
uint32_t tmp = 0U;
/* get the trimming value */
tmp = DAC_CALR(dac_periph);
if(DAC_OUT0 == dac_out) {
/* set the DACx_OUT0 trimming value */
tmp &= ~(uint32_t)DAC_CALR_OTV0;
tmp |= (trim_value & DAC_CALR_OTV0);
DAC_CALR(dac_periph) = tmp;
}else if(DAC_OUT1 == dac_out){
/* set the DACx_OUT1 trimming value */
tmp &= ~(uint32_t)DAC_CALR_OTV1;
tmp |= ((trim_value << OUT1_REG_OFFSET) & DAC_CALR_OTV1);
DAC_CALR(dac_periph) = tmp;
}else{
/* illegal parameters */
}
}
/*!
\brief enable the DACx trimming
\param[in] dac_periph: DACx(x=0)
\param[in] dac_out: DAC_OUTx(x=0,1)
\param[out] none
*/
void dac_trimming_enable(uint32_t dac_periph, uint32_t dac_out)
{
if(DAC_OUT0 == dac_out){
/* enable the DACx_OUT0 trimming */
DAC_CTL0(dac_periph) |= DAC_CTL0_CALEN0;
}else if(DAC_OUT1 == dac_out){
/* enable the DACx_OUT1 trimming */
DAC_CTL0(dac_periph) |= DAC_CTL0_CALEN1;
}else{
/* illegal parameters */
}
}
/*!
\brief get DAC output value
\param[in] dac_periph: DACx(x=0)
\param[in] dac_out: DAC_OUTx(x=0,1)
\param[out] none
\retval DAC output data: 0~4095
*/
uint16_t dac_output_value_get(uint32_t dac_periph, uint8_t dac_out)
{
uint16_t data = 0U;
if(DAC_OUT0 == dac_out){
/* store the DACx_OUT0 output value */
data = (uint16_t)DAC_OUT0_DO(dac_periph);
}else if(DAC_OUT1 == dac_out){
/* store the DACx_OUT1 output value */
data = (uint16_t)DAC_OUT1_DO(dac_periph);
}else{
/* illegal parameters */
}
return data;
}
/*!
\brief set DAC data holding register value
\param[in] dac_periph: DACx(x=0)
\param[in] dac_out: DAC_OUTx(x=0,1)
\param[in] dac_align: DAC data alignment mode
only one parameter can be selected which is shown as below:
\arg DAC_ALIGN_12B_R: 12-bit right-aligned data
\arg DAC_ALIGN_12B_L: 12-bit left-aligned data
\arg DAC_ALIGN_8B_R: 8-bit right-aligned data
\param[in] data: data to be loaded(0~4095)
\param[out] none
\retval none
*/
void dac_data_set(uint32_t dac_periph, uint8_t dac_out, uint32_t dac_align, uint16_t data)
{
/* DAC_OUT0 data alignment */
if(DAC_OUT0 == dac_out){
switch(dac_align){
/* 12-bit right-aligned data */
case DAC_ALIGN_12B_R:
DAC_OUT0_R12DH(dac_periph) = data;
break;
/* 12-bit left-aligned data */
case DAC_ALIGN_12B_L:
DAC_OUT0_L12DH(dac_periph) = data;
break;
/* 8-bit right-aligned data */
case DAC_ALIGN_8B_R:
DAC_OUT0_R8DH(dac_periph) = data;
break;
default:
break;
}
}else if(DAC_OUT1 == dac_out){
/* DAC_OUT1 data alignment */
switch(dac_align){
/* 12-bit right-aligned data */
case DAC_ALIGN_12B_R:
DAC_OUT1_R12DH(dac_periph) = data;
break;
/* 12-bit left-aligned data */
case DAC_ALIGN_12B_L:
DAC_OUT1_L12DH(dac_periph) = data;
break;
/* 8-bit right-aligned data */
case DAC_ALIGN_8B_R:
DAC_OUT1_R8DH(dac_periph) = data;
break;
default:
break;
}
}else{
/* illegal parameters */
}
}
/*!
\brief enable DAC trigger
\param[in] dac_periph: DACx(x=0)
\param[in] dac_out: DAC_OUTx(x=0,1)
\param[out] none
\retval none
*/
void dac_trigger_enable(uint32_t dac_periph, uint8_t dac_out)
{
if(DAC_OUT0 == dac_out){
DAC_CTL0(dac_periph) |= (uint32_t)DAC_CTL0_DTEN0;
}else if(DAC_OUT1 == dac_out){
DAC_CTL0(dac_periph) |= (uint32_t)DAC_CTL0_DTEN1;
}else{
/* illegal parameters */
}
}
/*!
\brief disable DAC trigger
\param[in] dac_periph: DACx(x=0)
\param[in] dac_out: DAC_OUTx(x=0,1)
\param[out] none
\retval none
*/
void dac_trigger_disable(uint32_t dac_periph, uint8_t dac_out)
{
if(DAC_OUT0 == dac_out){
DAC_CTL0(dac_periph) &= (uint32_t)(~DAC_CTL0_DTEN0);
}else if(DAC_OUT1 == dac_out){
DAC_CTL0(dac_periph) &= (uint32_t)(~DAC_CTL0_DTEN1);
}else{
/* illegal parameters */
}
}
/*!
\brief configure DAC trigger source
\param[in] dac_periph: DACx(x=0)
\param[in] dac_out: DAC_OUTx(x=0,1)
\param[in] triggersource: external trigger of DAC
only one parameter can be selected which is shown as below:
\arg DAC_TRIGGER_EXTERNAL: external trigger selected by TRIGSEL
\arg DAC_TRIGGER_SOFTWARE: software trigger
\param[out] none
\retval none
*/
void dac_trigger_source_config(uint32_t dac_periph, uint8_t dac_out, uint32_t triggersource)
{
if(DAC_OUT0 == dac_out){
/* configure DACx_OUT0 trigger source */
DAC_CTL0(dac_periph) &= (uint32_t)(~DAC_CTL0_DTSEL0);
DAC_CTL0(dac_periph) |= triggersource;
}else if(DAC_OUT1 == dac_out){
/* configure DACx_OUT1 trigger source */
DAC_CTL0(dac_periph) &= (uint32_t)(~DAC_CTL0_DTSEL1);
DAC_CTL0(dac_periph) |= (triggersource << OUT1_REG_OFFSET);
}else{
/* illegal parameters */
}
}
/*!
\brief enable DAC software trigger
\param[in] dac_periph: DACx(x=0)
\param[in] dac_out: DAC_OUTx(x=0,1)
\retval none
*/
void dac_software_trigger_enable(uint32_t dac_periph, uint8_t dac_out)
{
if(DAC_OUT0 == dac_out){
DAC_SWT(dac_periph) |= (uint32_t)DAC_SWT_SWTR0;
}else if(DAC_OUT1 == dac_out){
DAC_SWT(dac_periph) |= (uint32_t)DAC_SWT_SWTR1;
}else{
/* illegal parameters */
}
}
/*!
\brief configure DAC wave mode
\param[in] dac_periph: DACx(x=0)
\param[in] dac_out: DAC_OUTx(x=0,1)
\param[in] wave_mode: DAC wave mode
only one parameter can be selected which is shown as below:
\arg DAC_WAVE_DISABLE: wave mode disable
\arg DAC_WAVE_MODE_LFSR: LFSR noise mode
\arg DAC_WAVE_MODE_TRIANGLE: triangle noise mode
\param[out] none
\retval none
*/
void dac_wave_mode_config(uint32_t dac_periph, uint8_t dac_out, uint32_t wave_mode)
{
if(DAC_OUT0 == dac_out){
/* configure DACx_OUT0 wave mode */
DAC_CTL0(dac_periph) &= (uint32_t)(~DAC_CTL0_DWM0);
DAC_CTL0(dac_periph) |= wave_mode;
}else if(DAC_OUT1 == dac_out){
/* configure DACx_OUT1 wave mode */
DAC_CTL0(dac_periph) &= (uint32_t)(~DAC_CTL0_DWM1);
DAC_CTL0(dac_periph) |= (wave_mode << OUT1_REG_OFFSET);
}else{
/* illegal parameters */
}
}
/*!
\brief configure DAC LFSR noise mode
\param[in] dac_periph: DACx(x=0)
\param[in] dac_out: DAC_OUTx(x=0,1)
\param[in] unmask_bits: LFSR noise unmask bits
only one parameter can be selected which is shown as below:
\arg DAC_LFSR_BIT0: unmask the LFSR bit0
\arg DAC_LFSR_BITS1_0: unmask the LFSR bits[1:0]
\arg DAC_LFSR_BITS2_0: unmask the LFSR bits[2:0]
\arg DAC_LFSR_BITS3_0: unmask the LFSR bits[3:0]
\arg DAC_LFSR_BITS4_0: unmask the LFSR bits[4:0]
\arg DAC_LFSR_BITS5_0: unmask the LFSR bits[5:0]
\arg DAC_LFSR_BITS6_0: unmask the LFSR bits[6:0]
\arg DAC_LFSR_BITS7_0: unmask the LFSR bits[7:0]
\arg DAC_LFSR_BITS8_0: unmask the LFSR bits[8:0]
\arg DAC_LFSR_BITS9_0: unmask the LFSR bits[9:0]
\arg DAC_LFSR_BITS10_0: unmask the LFSR bits[10:0]
\arg DAC_LFSR_BITS11_0: unmask the LFSR bits[11:0]
\param[out] none
\retval none
*/
void dac_lfsr_noise_config(uint32_t dac_periph, uint8_t dac_out, uint32_t unmask_bits)
{
if(DAC_OUT0 == dac_out){
/* configure DACx_OUT0 LFSR noise mode */
DAC_CTL0(dac_periph) &= (uint32_t)(~DAC_CTL0_DWBW0);
DAC_CTL0(dac_periph) |= unmask_bits;
}else if(DAC_OUT1 == dac_out){
/* configure DACx_OUT1 LFSR noise mode */
DAC_CTL0(dac_periph) &= (uint32_t)(~DAC_CTL0_DWBW1);
DAC_CTL0(dac_periph) |= (unmask_bits << OUT1_REG_OFFSET);
}else{
/* illegal parameters */
}
}
/*!
\brief configure DAC triangle noise mode
\param[in] dac_periph: DACx(x=0)
\param[in] dac_out: DAC_OUTx(x=0,1)
\param[in] amplitude: the amplitude of the triangle
only one parameter can be selected which is shown as below:
\arg DAC_TRIANGLE_AMPLITUDE_1: triangle amplitude is 1
\arg DAC_TRIANGLE_AMPLITUDE_3: triangle amplitude is 3
\arg DAC_TRIANGLE_AMPLITUDE_7: triangle amplitude is 7
\arg DAC_TRIANGLE_AMPLITUDE_15: triangle amplitude is 15
\arg DAC_TRIANGLE_AMPLITUDE_31: triangle amplitude is 31
\arg DAC_TRIANGLE_AMPLITUDE_63: triangle amplitude is 63
\arg DAC_TRIANGLE_AMPLITUDE_127: triangle amplitude is 127
\arg DAC_TRIANGLE_AMPLITUDE_255: triangle amplitude is 255
\arg DAC_TRIANGLE_AMPLITUDE_511: triangle amplitude is 511
\arg DAC_TRIANGLE_AMPLITUDE_1023: triangle amplitude is 1023
\arg DAC_TRIANGLE_AMPLITUDE_2047: triangle amplitude is 2047
\arg DAC_TRIANGLE_AMPLITUDE_4095: triangle amplitude is 4095
\param[out] none
\retval none
*/
void dac_triangle_noise_config(uint32_t dac_periph, uint8_t dac_out, uint32_t amplitude)
{
if(DAC_OUT0 == dac_out){
/* configure DACx_OUT0 triangle noise mode */
DAC_CTL0(dac_periph) &= (uint32_t)(~DAC_CTL0_DWBW0);
DAC_CTL0(dac_periph) |= amplitude;
}else if(DAC_OUT1 == dac_out){
/* configure DACx_OUT1 triangle noise mode */
DAC_CTL0(dac_periph) &= (uint32_t)(~DAC_CTL0_DWBW1);
DAC_CTL0(dac_periph) |= (amplitude << OUT1_REG_OFFSET);
}else{
/* illegal parameters */
}
}
/*!
\brief enable DAC concurrent mode
\param[in] dac_periph: DACx(x=0)
\param[out] none
\retval none
*/
void dac_concurrent_enable(uint32_t dac_periph)
{
uint32_t ctl = 0U;
ctl = (uint32_t)(DAC_CTL0_DEN0 | DAC_CTL0_DEN1);
DAC_CTL0(dac_periph) |= (uint32_t)ctl;
}
/*!
\brief disable DAC concurrent mode
\param[in] dac_periph: DACx(x=0)
\param[out] none
\retval none
*/
void dac_concurrent_disable(uint32_t dac_periph)
{
uint32_t ctl = 0U;
ctl = (uint32_t)(DAC_CTL0_DEN0 | DAC_CTL0_DEN1);
DAC_CTL0(dac_periph) &= (uint32_t)(~ctl);
}
/*!
\brief enable DAC concurrent software trigger
\param[in] dac_periph: DACx(x=0)
\param[out] none
\retval none
*/
void dac_concurrent_software_trigger_enable(uint32_t dac_periph)
{
uint32_t swt = 0U;
swt = (uint32_t)(DAC_SWT_SWTR0 | DAC_SWT_SWTR1);
DAC_SWT(dac_periph) |= (uint32_t)swt;
}
/*!
\brief set DAC concurrent mode data holding register value
\param[in] dac_periph: DACx(x=0)
\param[in] dac_align: DAC data alignment mode
only one parameter can be selected which is shown as below:
\arg DAC_ALIGN_12B_R: 12-bit right-aligned data
\arg DAC_ALIGN_12B_L: 12-bit left-aligned data
\arg DAC_ALIGN_8B_R: 8-bit right-aligned data
\param[in] data0: data to be loaded(0~4095)
\param[in] data1: data to be loaded(0~4095)
\param[out] none
\retval none
*/
void dac_concurrent_data_set(uint32_t dac_periph, uint32_t dac_align, uint16_t data0, uint16_t data1)
{
uint32_t data = 0U;
switch(dac_align){
/* 12-bit right-aligned data */
case DAC_ALIGN_12B_R:
data = (uint32_t)(((uint32_t)data1 << DH_12BIT_OFFSET) | data0);
DACC_R12DH(dac_periph) = (uint32_t)data;
break;
/* 12-bit left-aligned data */
case DAC_ALIGN_12B_L:
data = (uint32_t)(((uint32_t)data1 << DH_12BIT_OFFSET) | data0);
DACC_L12DH(dac_periph) = (uint32_t)data;
break;
/* 8-bit right-aligned data */
case DAC_ALIGN_8B_R:
data = (uint32_t)(((uint32_t)data1 << DH_8BIT_OFFSET) | data0);
DACC_R8DH(dac_periph) = (uint32_t)data;
break;
default:
break;
}
}
/*!
\brief set DAC sample and keep time value
\param[in] dac_periph: DACx(x=0)
\param[in] dac_out: DAC_OUTx(x=0,1)
\param[in] sample_time: DAC sample time
\param[in] keep_time: DAC keep time
\param[in] refresh_time: DAC refresh time
\param[out] none
\retval none
*/
void dac_sample_keep_mode_config(uint32_t dac_periph, uint32_t dac_out, uint32_t sample_time, uint32_t keep_time, uint32_t refresh_time)
{
uint32_t tmp = 0U;
if(DAC_OUT0 == dac_out){
/* configure DACx_OUT0 Sample & Keep mode */
DAC_SKSTR0(dac_periph) |= (sample_time & DAC_SKSTR0_TSAMP0);
tmp = (DAC_SKKTR(dac_periph) & ~(uint32_t)DAC_SKKTR_TKEEP0);
DAC_SKKTR(dac_periph) = tmp | (keep_time & DAC_SKKTR_TKEEP0);
tmp = (DAC_SKRTR(dac_periph) & ~(uint32_t)DAC_SKRTR_TREF0);
DAC_SKRTR(dac_periph) = tmp | (refresh_time & DAC_SKRTR_TREF0);
}else if(DAC_OUT1 == dac_out){
/* configure DACx_OUT1 Sample & Keep mode */
DAC_SKSTR1(dac_periph) |= (sample_time & DAC_SKSTR1_TSAMP1);
tmp = (DAC_SKKTR(dac_periph) & ~(uint32_t)DAC_SKKTR_TKEEP1);
DAC_SKKTR(dac_periph) = tmp | ((keep_time << 16) & DAC_SKKTR_TKEEP1);
tmp = (DAC_SKRTR(dac_periph) & ~(uint32_t)DAC_SKRTR_TREF1);
DAC_SKRTR(dac_periph) = tmp | ((refresh_time << 16) & DAC_SKRTR_TREF1);
}else{
/* illegal parameters */
}
}
/*!
\brief get DAC flag
\param[in] dac_periph: DACx(x=0)
\param[in] flag: the DAC status flags, only one parameter can be selected which is shown
as below:
\arg DAC_FLAG_DDUDR0: DACx_OUT0 DMA underrun flag
\arg DAC_FLAG_CALF0: DACx_OUT0 calibration offset flag
\arg DAC_FLAG_BWT0: DACx_OUT0 sample and keep wtire enable flag
\arg DAC_FLAG_DDUDR1: DACx_OUT1 DMA underrun flag
\arg DAC_FLAG_CALF1: DACx_OUT1 calibration offset flag
\arg DAC_FLAG_BWT1: DACx_OUT1 sample and keep wtire enable flag
\param[out] none
\retval the state of DAC bit(SET or RESET)
*/
FlagStatus dac_flag_get(uint32_t dac_periph, uint32_t flag)
{
if(flag & DAC_STAT_FLAG_MASK0){
/* check DAC_STAT0 flag */
if(RESET != (DAC_STAT0(dac_periph) & flag)){
return SET;
}else{
return RESET;
}
}else{
/* illegal parameters */
return RESET;
}
}
/*!
\brief clear DAC flag
\param[in] dac_periph: DACx(x=0)
\param[in] flag: DAC flag
only one parameter can be selected which is shown as below:
\arg DAC_FLAG_DDUDR0: DACx_OUT0 DMA underrun flag
\arg DAC_FLAG_CALF0: DACx_OUT0 calibration offset flag
\arg DAC_FLAG_BWT0: DACx_OUT0 sample and keep wtire enable flag
\arg DAC_FLAG_DDUDR1: DACx_OUT1 DMA underrun flag
\arg DAC_FLAG_CALF1: DACx_OUT1 calibration offset flag
\arg DAC_FLAG_BWT1: DACx_OUT1 sample and keep wtire enable flag
\param[out] none
\retval none
*/
void dac_flag_clear(uint32_t dac_periph, uint32_t flag)
{
if(flag & DAC_STAT_FLAG_MASK0){
/* check DAC_STAT0 flag */
DAC_STAT0(dac_periph) = (uint32_t)(flag & DAC_STAT_FLAG_MASK0);
}else{
/* illegal parameters */
}
}
/*!
\brief enable DAC interrupt
\param[in] dac_periph: DACx(x=0)
\param[in] interrupt: the DAC interrupt
only one parameter can be selected which is shown as below:
\arg DAC_INT_DDUDR0: DACx_OUT0 DMA underrun interrupt
\arg DAC_INT_DDUDR1: DACx_OUT1 DMA underrun interrupt
\param[out] none
\retval none
*/
void dac_interrupt_enable(uint32_t dac_periph, uint32_t interrupt)
{
if(interrupt & DAC_INT_EN_MASK0){
/* enable underrun interrupt */
DAC_CTL0(dac_periph) |= (uint32_t)(interrupt & DAC_INT_EN_MASK0);
}else{
/* illegal parameters */
}
}
/*!
\brief disable DAC interrupt
\param[in] dac_periph: DACx(x=0)
\param[in] interrupt: the DAC interrupt
only one parameter can be selected which is shown as below:
\arg DAC_INT_DDUDR0: DACx_OUT0 DMA underrun interrupt
\arg DAC_INT_DDUDR1: DACx_OUT1 DMA underrun interrupt
\param[out] none
\retval none
*/
void dac_interrupt_disable(uint32_t dac_periph, uint32_t interrupt)
{
if(interrupt & DAC_INT_EN_MASK0){
/* disable underrun interrupt */
DAC_CTL0(dac_periph) &= (uint32_t)(~(interrupt & DAC_INT_EN_MASK0));
}else{
/* illegal parameters */
}
}
/*!
\brief get DAC interrupt flag
\param[in] dac_periph: DACx(x=0)
\param[in] int_flag: DAC interrupt flag
only one parameter can be selected which is shown as below:
\arg DAC_INT_FLAG_DDUDR0: DACx_OUT0 DMA underrun interrupt flag
\arg DAC_INT_FLAG_DDUDR1: DACx_OUT1 DMA underrun interrupt flag
\param[out] none
\retval the state of DAC interrupt flag(SET or RESET)
*/
FlagStatus dac_interrupt_flag_get(uint32_t dac_periph, uint32_t int_flag)
{
uint32_t reg1 = 0U, reg2 = 0U;
if(int_flag & DAC_INT_FLAG_MASK0){
/* check underrun interrupt int_flag */
reg1 = DAC_STAT0(dac_periph) & int_flag;
reg2 = DAC_CTL0(dac_periph) & int_flag;
}else{
/* illegal parameters */
}
/*get DAC interrupt flag status */
if((RESET != reg1) && (RESET != reg2)){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear DAC interrupt flag
\param[in] dac_periph: DACx(x=0)
\param[in] int_flag: DAC interrupt flag
only one parameter can be selected which is shown as below:
\arg DAC_INT_FLAG_DDUDR0: DACx_OUT0 DMA underrun interrupt flag
\arg DAC_INT_FLAG_DDUDR1: DACx_OUT1 DMA underrun interrupt flag
\param[out] none
\retval none
*/
void dac_interrupt_flag_clear(uint32_t dac_periph, uint32_t int_flag)
{
/* clear underrun interrupt int_flag */
if(int_flag & DAC_INT_FLAG_MASK0)
{
DAC_STAT0(dac_periph) = (uint32_t)int_flag;
}
}
@@ -0,0 +1,168 @@
/*!
\file gd32h7xx_dbg.c
\brief DBG driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_dbg.h"
#define DBG_RESET_VAL ((uint32_t)0x00000000U) /*!< DBG reset value */
/*!
\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;
DBG_CTL2 = DBG_RESET_VAL;
DBG_CTL3 = DBG_RESET_VAL;
DBG_CTL4 = 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:
only one parameter can be selected which is shown as below:
\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:
only one parameter can be selected which is shown as below:
\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 trace pin assignment
\param[in] none
\param[out] none
\retval none
*/
void dbg_trace_pin_enable(void)
{
DBG_CTL0 |= DBG_CTL0_TRACECLKEN;
}
/*!
\brief disable trace pin assignment
\param[in] none
\param[out] none
\retval none
*/
void dbg_trace_pin_disable(void)
{
DBG_CTL0 &= ~DBG_CTL0_TRACECLKEN;
}
/*!
\brief trace pin mode selection
\param[in] trace_mode:
\arg TRACE_MODE_ASYNC: trace pin used for async mode
\arg TRACE_MODE_SYNC_DATASIZE_1: trace pin used for sync mode and data size is 1
\arg TRACE_MODE_SYNC_DATASIZE_2: trace pin used for sync mode and data size is 2
\arg TRACE_MODE_SYNC_DATASIZE_4: trace pin used for sync mode and data size is 4
\param[out] none
\retval none
*/
void dbg_trace_pin_mode_set(uint32_t trace_mode)
{
DBG_CTL0 &= ~DBG_CTL0_TRACE_MODE;
DBG_CTL0 |= trace_mode;
}
/*!
\brief enable peripheral behavior when the mcu is in debug mode
\param[in] dbg_periph: refer to dbg_periph_enum
only one parameter can be selected which are 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_TIMERx_HOLD (x=0,1,2,3,4,5,6,7,14,15,16,22,23,30,31,40,41,42,43,44,50,51): hold TIMERx counter when core is halted
\arg DBG_I2Cx_HOLD (x=0,1,2,3): hold I2Cx smbus when core is halted
\arg DBG_CANx_HOLD (x=0,1,2): hold CANx 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: refer to dbg_periph_enum
only one parameter can be selected which are 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_TIMERx_HOLD (x=0,1,2,3,4,5,6,7,14,15,16,22,23,30,31,40,41,42,43,44,50,51): hold TIMERx counter when core is halted
\arg DBG_I2Cx_HOLD (x=0,1,2,3): hold I2Cx smbus when core is halted
\arg DBG_CANx_HOLD (x=0,1,2): hold CANx 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));
}
@@ -0,0 +1,448 @@
/*!
\file gd32h7xx_dci.c
\brief DCI driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_dci.h"
/*!
\brief DCI deinit
\param[in] none
\param[out] none
\retval none
*/
void dci_deinit(void)
{
rcu_periph_reset_enable(RCU_DCIRST);
rcu_periph_reset_disable(RCU_DCIRST);
}
/*!
\brief initialize DCI registers
\param[in] dci_struct: DCI parameter initialization structure
members of the structure and the member values are shown as below:
capture_mode : DCI_CAPTURE_MODE_CONTINUOUS, DCI_CAPTURE_MODE_SNAPSHOT
colck_polarity : DCI_CK_POLARITY_FALLING, DCI_CK_POLARITY_RISING
hsync_polarity : DCI_HSYNC_POLARITY_LOW, DCI_HSYNC_POLARITY_HIGH
vsync_polarity : DCI_VSYNC_POLARITY_LOW, DCI_VSYNC_POLARITY_HIGH
frame_rate : DCI_FRAME_RATE_ALL, DCI_FRAME_RATE_1_2, DCI_FRAME_RATE_1_4
interface_format: DCI_INTERFACE_FORMAT_8BITS, DCI_INTERFACE_FORMAT_10BITS,
DCI_INTERFACE_FORMAT_12BITS, DCI_INTERFACE_FORMAT_14BITS
\param[out] none
\retval none
*/
void dci_init(dci_parameter_struct *dci_struct)
{
uint32_t reg = 0U;
/* disable capture function and DCI */
DCI_CTL &= ~(DCI_CTL_CAP | DCI_CTL_DCIEN);
/* configure DCI parameter */
reg |= dci_struct->capture_mode;
reg |= dci_struct->clock_polarity;
reg |= dci_struct->hsync_polarity;
reg |= dci_struct->vsync_polarity;
reg |= dci_struct->frame_rate;
reg |= dci_struct->interface_format;
DCI_CTL = reg;
}
/*!
\brief enable DCI function
\param[in] none
\param[out] none
\retval none
*/
void dci_enable(void)
{
DCI_CTL |= DCI_CTL_DCIEN;
}
/*!
\brief disable DCI function
\param[in] none
\param[out] none
\retval none
*/
void dci_disable(void)
{
DCI_CTL &= ~DCI_CTL_DCIEN;
}
/*!
\brief enable DCI capture
\param[in] none
\param[out] none
\retval none
*/
void dci_capture_enable(void)
{
DCI_CTL |= DCI_CTL_CAP;
}
/*!
\brief disable DCI capture
\param[in] none
\param[out] none
\retval none
*/
void dci_capture_disable(void)
{
DCI_CTL &= ~DCI_CTL_CAP;
}
/*!
\brief enable DCI external vsync function in CCIR progressive mode
\param[in] none
\param[out] none
\retval none
*/
void dci_external_vsync_enable(void)
{
DCI_CTL |= DCI_CTL_EVSEN;
}
/*!
\brief disable DCI external vsync function in CCIR progressive mode
\param[in] none
\param[out] none
\retval none
*/
void dci_external_vsync_disable(void)
{
DCI_CTL &= ~DCI_CTL_EVSEN;
}
/*!
\brief enable DCI automatic error correction function in CCIR interlaced mode
\param[in] none
\param[out] none
\retval none
*/
void dci_automatic_error_correction_enable(void)
{
DCI_CTL |= DCI_CTL_AECEN;
}
/*!
\brief disable DCI automatic error correction function in CCIR interlaced mode
\param[in] none
\param[out] none
\retval none
*/
void dci_automatic_error_correction_disable(void)
{
DCI_CTL &= ~DCI_CTL_AECEN;
}
/*!
\brief enable DCI jpeg mode
\param[in] none
\param[out] none
\retval none
*/
void dci_jpeg_enable(void)
{
DCI_CTL |= DCI_CTL_JM;
}
/*!
\brief disable DCI jpeg mode
\param[in] none
\param[out] none
\retval none
*/
void dci_jpeg_disable(void)
{
DCI_CTL &= ~DCI_CTL_JM;
}
/*!
\brief enable cropping window function
\param[in] none
\param[out] none
\retval none
*/
void dci_crop_window_enable(void)
{
DCI_CTL |= DCI_CTL_WDEN;
}
/*!
\brief disable cropping window function
\param[in] none
\param[out] none
\retval none
*/
void dci_crop_window_disable(void)
{
DCI_CTL &= ~DCI_CTL_WDEN;
}
/*!
\brief configure DCI cropping window
\param[in] start_x: window horizontal start position
\param[in] start_y: window vertical start position
\param[in] size_width: window horizontal size
\param[in] size_height: window vertical size
\param[out] none
\retval none
*/
void dci_crop_window_config(uint16_t start_x, uint16_t start_y, uint16_t size_width, uint16_t size_height)
{
DCI_CWSPOS = ((uint32_t)start_x | ((uint32_t)start_y << 16U));
DCI_CWSZ = ((uint32_t)size_width | ((uint32_t)size_height << 16U));
}
/*!
\brief enable embedded synchronous mode
\param[in] none
\param[out] none
\retval none
*/
void dci_embedded_sync_enable(void)
{
DCI_CTL |= DCI_CTL_ESM;
}
/*!
\brief disble embedded synchronous mode
\param[in] none
\param[out] none
\retval none
*/
void dci_embedded_sync_disable(void)
{
DCI_CTL &= ~DCI_CTL_ESM;
}
/*!
\brief CCIR mode enable
\param[in] none
\param[out] none
\retval none
*/
void dci_ccir_enable(void)
{
DCI_CTL |= DCI_CTL_CCEN;
}
/*!
\brief CCIR mode disable
\param[in] none
\param[out] none
\retval none
*/
void dci_ccir_disable(void)
{
DCI_CTL &= ~DCI_CTL_CCEN;
}
/*!
\brief CCIR mode select
\param[in] ccir_mode: specify which mode to select
only one parameter can be selected which is shown as below:
\arg CCIR_PROGRESSIVE_MODE: CCIR progressive mode
\arg CCIR_INTERLACE_MODE: CCIR interlace mode
\param[out] none
\retval none
*/
void dci_ccir_mode_select(uint32_t ccir_mode)
{
if(CCIR_INTERLACE_MODE == ccir_mode) {
DCI_CTL |= DCI_CTL_CCMOD;
} else {
DCI_CTL &= ~DCI_CTL_CCMOD;
}
}
/*!
\brief config synchronous codes in embedded synchronous mode
\param[in] frame_start: frame start code in embedded synchronous mode
\param[in] line_start: line start code in embedded synchronous mode
\param[in] line_end: line end code in embedded synchronous mode
\param[in] frame_end: frame end code in embedded synchronous mode
\param[out] none
\retval none
*/
void dci_sync_codes_config(uint8_t frame_start, uint8_t line_start, uint8_t line_end, uint8_t frame_end)
{
DCI_SC = ((uint32_t)frame_start | ((uint32_t)line_start << 8U) | \
((uint32_t)line_end << 16U) | ((uint32_t)frame_end << 24U));
}
/*!
\brief config synchronous codes unmask in embedded synchronous mode
\param[in] frame_start: frame start code unmask bits in embedded synchronous mode
\param[in] line_start: line start code unmask bits in embedded synchronous mode
\param[in] line_end: line end code unmask bits in embedded synchronous mode
\param[in] frame_end: frame end code unmask bits in embedded synchronous mode
\param[out] none
\retval none
*/
void dci_sync_codes_unmask_config(uint8_t frame_start, uint8_t line_start, uint8_t line_end, uint8_t frame_end)
{
DCI_SCUMSK = ((uint32_t)frame_start | ((uint32_t)line_start << 8U) | \
((uint32_t)line_end << 16U) | ((uint32_t)frame_end << 24U));
}
/*!
\brief read DCI data register
\param[in] none
\param[out] none
\retval data
*/
uint32_t dci_data_read(void)
{
return DCI_DATA;
}
/*!
\brief get specified flag
\param[in] flag: specify which flag to get
only one parameter can be selected which is shown as below:
\arg DCI_FLAG_HS: HS line status
\arg DCI_FLAG_VS: VS line status
\arg DCI_FLAG_FV: FIFO valid
\arg DCI_FLAG_EF: end of frame flag
\arg DCI_FLAG_OVR: FIFO overrun flag
\arg DCI_FLAG_ESE: embedded synchronous error flag
\arg DCI_FLAG_VSYNC: vsync flag
\arg DCI_FLAG_EL: end of line flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus dci_flag_get(uint32_t flag)
{
uint32_t stat = 0U;
if(flag >> 31U) {
/* get flag status from DCI_STAT1 register */
stat = DCI_STAT1;
} else {
/* get flag status from DCI_STAT0 register */
stat = DCI_STAT0;
}
if(flag & stat) {
return SET;
} else {
return RESET;
}
}
/*!
\brief enable specified DCI interrupt
\param[in] interrupt: specify which interrupt to enable
one or more parameter can be selected which is shown as below:
\arg DCI_INT_EF: end of frame interrupt
\arg DCI_INT_OVR: FIFO overrun interrupt
\arg DCI_INT_ESE: embedded synchronous error interrupt
\arg DCI_INT_VSYNC: vsync interrupt
\arg DCI_INT_EL: end of line interrupt
\arg DCI_INT_F0: CCIR field 0 interrupt
\arg DCI_INT_F1: CCIR field 1 interrupt
\arg DCI_INT_COF: CCIR change of field interrupt
\arg DCI_INT_CCE: CCIR error interrupt
\param[out] none
\retval none
*/
void dci_interrupt_enable(uint32_t interrupt)
{
DCI_INTEN |= interrupt;
}
/*!
\brief disable specified DCI interrupt
\param[in] interrupt: specify which interrupt to disable
one or more parameter can be selected which is shown as below:
\arg DCI_INT_EF: end of frame interrupt
\arg DCI_INT_OVR: FIFO overrun interrupt
\arg DCI_INT_ESE: embedded synchronous error interrupt
\arg DCI_INT_VSYNC: vsync interrupt
\arg DCI_INT_EL: end of line interrupt
\arg DCI_INT_F0: CCIR field 0 interrupt
\arg DCI_INT_F1: CCIR field 1 interrupt
\arg DCI_INT_COF: CCIR change of field interrupt
\arg DCI_INT_CCE: CCIR error interrupt
\param[out] none
\retval none
*/
void dci_interrupt_disable(uint32_t interrupt)
{
DCI_INTEN &= ~interrupt;
}
/*!
\brief get specified interrupt flag
\param[in] int_flag: specify which flag to get
one or more parameter can be selected which is shown as below:
\arg DCI_INT_FLAG_EF: end of frame interrupt flag
\arg DCI_INT_FLAG_OVR: FIFO overrun interrupt flag
\arg DCI_INT_FLAG_ESE: embedded synchronous error interrupt flag
\arg DCI_INT_FLAG_VSYNC: vsync interrupt flag
\arg DCI_INT_FLAG_EL: end of line interrupt flag
\arg DCI_INT_FLAG_F0: CCIR field 0 interrupt flag
\arg DCI_INT_FLAG_F1: CCIR field 1 interrupt flag
\arg DCI_INT_FLAG_COF: CCIR change of field interrupt flag
\arg DCI_INT_FLAG_CCE: CCIR error interrupt flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus dci_interrupt_flag_get(uint32_t int_flag)
{
if(RESET == (DCI_INTF & int_flag)) {
return RESET;
} else {
return SET;
}
}
/*!
\brief clear specified interrupt flag
\param[in] int_flag: specify which flag to clear
one or more parameter can be selected which is shown as below:
\arg DCI_INT_FLAG_EF: end of frame interrupt flag
\arg DCI_INT_FLAG_OVR: FIFO overrun interrupt flag
\arg DCI_INT_FLAG_ESE: embedded synchronous error interrupt flag
\arg DCI_INT_FLAG_VSYNC: vsync interrupt flag
\arg DCI_INT_FLAG_EL: end of line interrupt flag
\arg DCI_INT_FLAG_COF: CCIR change of field interrupt flag
\arg DCI_INT_FLAG_CCE: CCIR error interrupt flag
\param[out] none
\retval none
*/
void dci_interrupt_flag_clear(uint32_t int_flag)
{
DCI_INTC |= int_flag;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,207 @@
/*!
\file gd32h7xx_edout.c
\brief EDOUT driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_edout.h"
/* EDOUT register bit offset */
#define LOC_LOCMAX_MIN ((uint32_t)0x0000000FU) /*!< LOCMAX fields minimum value */
#define LOC_LOCMAX_STEP ((uint32_t)0x00000004U) /*!< LOCMAX fields step value */
#define OCNT_PDC_OFFSET ((uint32_t)0x00000010U) /*!< bit offset of PDC in EDOUT_OCNT */
#define ZCR_ZOWH_OFFSET ((uint32_t)0x00000010U) /*!< bit offset of ZOWH in EDOUT_ZCR */
/*!
\brief deinitialize EDOUT
\param[in] none
\param[out] none
\retval none
*/
void edout_deinit(void)
{
/* reset EDOUT */
rcu_periph_reset_enable(RCU_EDOUTRST);
rcu_periph_reset_disable(RCU_EDOUTRST);
}
/*!
\brief initialize EDOUT
\param[in] pol: the active polarity of the B-phase output signal selection
only one parameter can be selected which is shown as below:
\arg EDOUT_POL_POSITIVE: active polarity is positive
\arg EDOUT_POL_NEGATIVE: active polarity is negative
\param[in] max_loc: (max_loc+1) must be a multiple of four between 16~65536 (e.g. 0x000F: The maximum location value is 16 (16=4*4))
\param[in] cur_loc: current location value, 0~locmax (locmax is the LOCMAX bit fields value of EDOUT_LOC register)
\param[out] none
\retval none
*/
void edout_init(uint32_t pol, uint32_t max_loc, uint32_t cur_loc)
{
/* reset polarity of the B-phase */
EDOUT_CTL &= ~EDOUT_CTL_POL;
/* set polarity of the B-phase */
EDOUT_CTL = pol;
/* reset the maximum location value */
EDOUT_LOC &= ~EDOUT_LOC_LOCMAX;
/* check the maximum location value */
if(LOC_LOCMAX_MIN > max_loc) {
max_loc = LOC_LOCMAX_MIN;
}
while(0U != ((max_loc + 1U) % LOC_LOCMAX_STEP)) {
max_loc++;
}
/* set the maximum location value */
EDOUT_LOC = max_loc & EDOUT_LOC_LOCMAX;
/* reset the current location value */
EDOUT_LCNT &= ~EDOUT_LCNT_LOCCNT;
/* set the current location value */
EDOUT_LCNT = cur_loc & EDOUT_LCNT_LOCCNT;
}
/*!
\brief enable EDOUT
\param[in] none
\param[out] none
\retval none
*/
void edout_enable(void)
{
EDOUT_ENABLE |= EDOUT_ENABLE_EDOUTEN;
}
/*!
\brief disable EDOUT
\param[in] none
\param[out] none
\retval none
*/
void edout_disable(void)
{
EDOUT_ENABLE &= ~EDOUT_ENABLE_EDOUTEN;
}
/*!
\brief set B-phase active polarity
\param[in] pol: the active polarity of the B-phase output signal selection
only one parameter can be selected which is shown as below:
\arg EDOUT_POL_POSITIVE: active polarity is positive
\arg EDOUT_POL_NEGATIVE: active polarity is negative
\param[out] none
\retval none
*/
void edout_polarity_config(uint32_t pol)
{
EDOUT_CTL = pol;
}
/*!
\brief set the maximum location value for one rotation
\param[in] max_loc: (max_loc+1) must be a multiple of four between 16~65536, e.g. 0x000F: The maximum location value is 16
\param[out] none
\retval none
*/
void edout_max_location_value_config(uint32_t max_loc)
{
EDOUT_LOC = max_loc & EDOUT_LOC_LOCMAX;
}
/*!
\brief update the output counter, used to set the phase difference and the number of edges for the next update period
\param[in] num_edges: edge count, value range is -32768~32767, positive means clockwise rotation, negative means counter-clockwise rotation
\param[in] phase_diff: phase difference, value range is 2~65535, in units of PCLK
\param[out] none
\retval none
*/
void edout_output_counter_update(int16_t num_edges, uint16_t phase_diff)
{
EDOUT_OCNT = ((uint32_t)num_edges & EDOUT_OCNT_EDGC) | ((uint32_t)phase_diff << OCNT_PDC_OFFSET);
}
/*!
\brief set the current location value
\param[in] cur_loc: current location value, 0~locmax (locmax is the LOCMAX bit fields value of EDOUT_LOC register)
\param[out] none
\retval none
*/
void edout_current_location_config(uint32_t cur_loc)
{
EDOUT_LCNT = cur_loc & EDOUT_LCNT_LOCCNT;
}
/*!
\brief get the current location value
\param[in] none
\param[out] none
\retval current location value, 0~locmax (locmax is the LOCMAX bit fields value of EDOUT_LOC register)
*/
uint16_t edout_current_location_get(void)
{
return (uint16_t)EDOUT_LCNT;
}
/*!
\brief configure Z-phase output mode
\param[in] mode: Z-phase output mode
only one parameter can be selected which is shown as below:
\arg EDOUT_Z_OUTPUT_MODE0: output according to the current location
\arg EDOUT_Z_OUTPUT_MODE1: output according to the number of edges
\param[out] none
\retval none
*/
void edout_z_output_mode_config(uint32_t mode)
{
/* reset the Z-phase output mode */
EDOUT_ZCR &= ~EDOUT_ZCR_ZOMD;
/* set the Z-phase output mode */
EDOUT_ZCR |= mode;
}
/*!
\brief configure Z-phase output start location and width
\param[in] start_loc: Z-phase output start location,
when Z-phase output mode select EDOUT_Z_OUTPUT_MODE0: 0~locmax (locmax is the LOCMAX bit fields value of EDOUT_LOC register)
when Z-phase output mode select EDOUT_Z_OUTPUT_MODE1: 0~edges (edges is the EDGC bit fields value of EDOUT_OCNT register)
\param[in] width: Z-phase output width
when Z-phase output mode select EDOUT_Z_OUTPUT_MODE0: 0~(locmax - start_loc) (locmax is the LOCMAX bit fields value of EDOUT_LOC register)
when Z-phase output mode select EDOUT_Z_OUTPUT_MODE1: 0~(edges - start_loc) (edges is the EDGC bit fields value of EDOUT_OCNT register)
\param[out] none
\retval none
*/
void edout_z_output_start_loc_and_width_config(uint32_t start_loc, uint32_t width)
{
/* reset the Z-phase output start location and output width */
EDOUT_ZCR &= ~(EDOUT_ZCR_ZOSP | EDOUT_ZCR_ZOWH);
/* set the Z-phase output start location and output width */
EDOUT_ZCR |= (start_loc & EDOUT_ZCR_ZOSP) | ((width << ZCR_ZOWH_OFFSET) & EDOUT_ZCR_ZOWH);
}
@@ -0,0 +1,512 @@
/*!
\file gd32h7xx_efuse.c
\brief EFUSE driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_efuse.h"
/* FMC register bit offset */
#define EFUSE_CTL_AES_KEY_CRC_OFFSET ((uint32_t)0x00000018U) /*!< bit offset of AES_KEY_CRC in EFUSE_CTL register*/
#define EFUSE_CTL_MPVEN_OFFSET ((uint32_t)0x0000000FU) /*!< bit offset of MPVEN in EFUSE_CTL register*/
#define EFUSE_STAT_LDO_RDY_OFFSET ((uint32_t)0x00000004U) /*!< bit offset of LDO_RDY in EFUSE_STAT register*/
#define EFUSE_ADDR_EFSIZE_OFFSET ((uint32_t)0x0000000AU) /*!< EFSIZE OFFSET in register EFUSE_ADDR */
#define EFUSE_TIMEOUT ((uint32_t)0x0000FFFFU) /*!< EFUSE operation timeout value */
#define USER_CTL_NDBG0 BIT(8) /*!< debug mode setting bit0 in register EFUSE_USER_CTL */
static uint32_t para_start_efaddr[EFUSE_PARA_CNT] = {USER_CTL_EFADDR, MCU_RESERVED_EFADDR, DP_EFADDR, AES_KEY_EFADDR, USER_DATA_EFADDR};
static uint32_t para_reg_start_addr[EFUSE_PARA_CNT] = {EFUSE_USER_CTL_REG_ADDR, EFUSE_MCU_RSV_REG_ADDR, EFUSE_DP_REG_ADDR, EFUSE_AES_KEY_REG_ADDR, EFUSE_USER_DATA_REG_ADDR};
static efuse_state_enum efuse_ready_wait(uint32_t efuse_flag, uint32_t timeout);
/*!
\brief read system parameters from EFUSE macro to registers
\param[in] ef_addr: start address of the system parameters to be read
only one parameter can be selected which is shown as below:
\arg USER_CTL_EFADDR: user control parameter start address
\arg MCU_RESERVED_EFADDR: MCU reserved parameter start address
\arg DP_EFADDR: debug password parameter start address
\arg USER_DATA_EFADDR: user data parameter start address
\param[in] size: size of the system parameters to be read
only one parameter can be selected which is shown as below:
\arg USER_CTL_SIZE: user control parameter size
\arg MCU_RESERVED_SIZE: MCU reserved parameter size
\arg DP_SIZE: debug password parameter size
\arg USER_DATA_SIZE: user data parameter size
\param[out] buf: the buffer for data read from EFUSE macro
\retval ErrStatus: ERROR or SUCCESS
*/
ErrStatus efuse_read(uint32_t ef_addr, uint32_t size, uint32_t buf[])
{
ErrStatus status = SUCCESS;
uint32_t timeout = EFUSE_TIMEOUT;
efuse_state_enum efuse_state;
uint32_t reg_addr = 0U;
uint32_t i = 0U;
uint32_t number = 0U;
switch(ef_addr) {
case USER_CTL_EFADDR:
status = ERROR;
break;
case MCU_RESERVED_EFADDR:
/* read MCU reserved data */
reg_addr = EFUSE_MCU_RSV_REG_ADDR;
number = 1U;
break;
case DP_EFADDR:
/* read debug password */
if(RESET != (EFUSE_USER_CTL & EFUSE_USER_CTL_DPLK)) {
if(RESET != (EFUSE_USER_CTL & EFUSE_USER_CTL_JTAGNSW)) {
if((RESET != (EFUSE_USER_CTL & USER_CTL_NDBG0))) {
status = ERROR;
}
}
}
if(SUCCESS == status) {
reg_addr = EFUSE_DP_REG_ADDR;
number = 2U;
}
break;
case USER_DATA_EFADDR:
/* read user data */
reg_addr = EFUSE_USER_DATA_REG_ADDR;
number = 4U;
break;
default:
status = ERROR;
break;
}
if(ERROR == status) {
return status;
}
/* clear the RDIF bit if it is SET */
efuse_flag_clear(EFUSE_FLAG_READ_COMPLETE_CLR);
/* reset the EFRW bit in EFUSE_CTL */
EFUSE_CTL &= ~EFUSE_CTL_EFRW;
/* write the desired efuse address and size to the EFUSE_ADDR register */
EFUSE_ADDR = (uint32_t)((size << EFUSE_ADDR_EFSIZE_OFFSET) | ef_addr);
/* start array read EFUSE operation */
EFUSE_CTL |= EFUSE_CTL_EFSTR;
/* wait for the operation to complete */
efuse_state = efuse_ready_wait(EFUSE_FLAG_READ_COMPLETE, timeout);
if(EFUSE_READY != efuse_state) {
status = ERROR;
}
/* read EFUSE register */
for(i = 0U; i < number; i++) {
buf[i] = REG32(reg_addr + (4U * i));
}
return status;
}
/*!
\brief program register values to EFUSE macro system parameters
\param[in] ef_addr: the EFUSE address to be programmed, pgm_addr cannot exceed 384, and must be an integral multiple of 8
\param[in] size: byte count to program, (1~16)
\param[in] buf: the buffer for data written to EFUSE macro
\param[out] none
\retval ErrStatus: ERROR or SUCCESS
*/
ErrStatus efuse_write(uint32_t ef_addr, uint32_t size, uint8_t *buf)
{
uint32_t i;
uint32_t reg_addr;
uint32_t byte_offset_in_reg;
uint32_t cnt;
ErrStatus status = SUCCESS;
uint32_t para_index;
uint32_t tmp_buf_8;
uint32_t buf_addr;
uint32_t timeout = EFUSE_TIMEOUT;
efuse_state_enum efuse_state;
if(0U == size) {
return ERROR;
}
/* the address should be on byte address boundary */
if(ef_addr % 8U) {
return ERROR;
}
if(MAX_EFADDR < ef_addr) {
return ERROR;
}
for(i = EFUSE_PARA_CNT; i > 0U; i--) {
if(ef_addr >= para_start_efaddr[i - 1U]) {
break;
}
}
/* get the index of parameter to be programmed */
para_index = i - 1U;
/* program range should not over parameter boundary */
if(para_index == (EFUSE_PARA_CNT - 1U)) {
if((ef_addr + size * 8U - 1U) > MAX_EFADDR) {
return ERROR;
}
} else {
if((ef_addr + size * 8U - 1U) > para_start_efaddr[para_index + 1U]) {
return ERROR;
}
}
if((AES_KEY_IDX == para_index) && (AES_KEY_SIZE != size)) {
/* AES key should be programmed in one time */
return ERROR;
}
reg_addr = (unsigned int)para_reg_start_addr[para_index] + (ef_addr - para_start_efaddr[para_index]) / 32U * 4U;
byte_offset_in_reg = ((ef_addr - para_start_efaddr[para_index]) / 8U) % 4U;
/* clear the PGIF bit if it is SET */
efuse_flag_clear(EFUSE_FLAG_PROGRAM_COMPLETE_CLR);
/* set the EFRW bit in EFUSE_CTL */
EFUSE_CTL |= EFUSE_CTL_EFRW;
/* write the desired efuse address and size to the EFUSE_ADDR register */
EFUSE_ADDR = (uint32_t)((size << EFUSE_ADDR_EFSIZE_OFFSET) | ef_addr);
buf_addr = (uint32_t)buf;
while(size) {
if((0U != byte_offset_in_reg) || ((0U == byte_offset_in_reg) && (size < 4U))) {
cnt = size < (4U - byte_offset_in_reg) ? size : 4U - byte_offset_in_reg;
for(i = 0U; i < cnt; i++) {
tmp_buf_8 = buf_addr;
/* write the data to the corresponding register */
tmp_buf_8 += i;
REG32(reg_addr) |= (((uint32_t)(*(uint8_t *)(tmp_buf_8))) << ((byte_offset_in_reg + i) * 8U));
}
size -= cnt;
reg_addr += 4U;
byte_offset_in_reg = 0U;
buf_addr += cnt;
} else {
cnt = size / 4U;
for(i = 0U; i < cnt; i++) {
tmp_buf_8 = buf_addr;
/* write the data to the corresponding register */
tmp_buf_8 += (i * 4U);
REG32(reg_addr) = (uint32_t)(*(uint32_t *)(tmp_buf_8));
reg_addr += 4U;
}
size -= cnt * 4U;
buf_addr += cnt * 4U;
}
}
/* start EFUSE program operation */
EFUSE_CTL |= EFUSE_CTL_EFSTR;
/* wait for the operation to complete */
efuse_state = efuse_ready_wait(EFUSE_FLAG_PROGRAM_COMPLETE, timeout);
if(EFUSE_READY != efuse_state) {
status = ERROR;
}
return status;
}
/*!
\brief program all user control parameters
\param[in] buf: the buffer of data written to efuse
\param[out] none
\retval ErrStatus: ERROR or SUCCESS
*/
ErrStatus efuse_user_control_write(uint8_t *buf)
{
return efuse_write(USER_CTL_EFADDR, USER_CTL_SIZE, buf);
}
/*!
\brief program all MCU reserved parameters
\param[in] buf: the buffer of data written to efuse
\param[out] none
\retval ErrStatus: ERROR or SUCCESS
*/
ErrStatus efuse_mcu_reserved_write(uint8_t *buf)
{
return efuse_write(MCU_RESERVED_EFADDR, MCU_RESERVED_SIZE, buf);
}
/*!
\brief program all debug password parameters
\param[in] buf: the buffer of data written to efuse
\param[out] none
\retval ErrStatus: ERROR or SUCCESS
*/
ErrStatus efuse_dp_write(uint8_t *buf)
{
return efuse_write(DP_EFADDR, DP_SIZE, buf);
}
/*!
\brief program all AES key parameters
\param[in] buf: the buffer of data written to efuse
\param[out] none
\retval ErrStatus: ERROR or SUCCESS
*/
ErrStatus efuse_aes_key_write(uint8_t *buf)
{
return efuse_write(AES_KEY_EFADDR, AES_KEY_SIZE, buf);
}
/*!
\brief program all user data parameters
\param[in] buf: the buffer of data written to efuse
\param[out] none
\retval ErrStatus: ERROR or SUCCESS
*/
ErrStatus efuse_user_data_write(uint8_t *buf)
{
return efuse_write(USER_DATA_EFADDR, USER_DATA_SIZE, buf);
}
/*!
\brief get 8-bits CRC calculation result value of AES key
\param[in] none
\param[out] none
\retval 8-bits CRC calculation result value of AES key
*/
uint8_t efuse_aes_key_crc_get(void)
{
return (uint8_t)((EFUSE_CTL & EFUSE_CTL_AES_KEY_CRC) >> EFUSE_CTL_AES_KEY_CRC_OFFSET);
}
/*!
\brief enable monitor program voltage function
\param[in] none
\param[out] none
\retval none
*/
void efuse_monitor_program_voltage_enable(void)
{
uint32_t ctl_reg;
ctl_reg = EFUSE_CTL;
/* enable monitor program voltage function */
ctl_reg |= EFUSE_CTL_MPVEN;
EFUSE_CTL = ctl_reg;
}
/*!
\brief disable monitor program voltage function
\param[in] none
\param[out] none
\retval none
*/
void efuse_monitor_program_voltage_disable(void)
{
uint32_t ctl_reg;
ctl_reg = EFUSE_CTL;
/* disable monitor program voltage function */
ctl_reg &= ~EFUSE_CTL_MPVEN;
EFUSE_CTL = ctl_reg;
}
/*!
\brief get monitor program voltage function
\param[in] none
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus efuse_monitor_program_voltage_get(void)
{
FlagStatus mpven_state = RESET;
if(EFUSE_CTL_MPVEN == (uint32_t)(EFUSE_CTL & EFUSE_CTL_MPVEN)) {
mpven_state = SET;
} else {
mpven_state = RESET;
}
return mpven_state;
}
/*!
\brief get ldo ready signal
\param[in] none
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus efuse_ldo_ready_get(void)
{
FlagStatus ldo_ready_state = RESET;
if(EFUSE_STAT_LDO_RDY == (uint32_t)(EFUSE_STAT & EFUSE_STAT_LDO_RDY)) {
ldo_ready_state = SET;
} else {
ldo_ready_state = RESET;
}
return ldo_ready_state;
}
/*!
\brief check EFUSE flag is set or not
\param[in] flag: specifies to get a flag
only one parameter can be selected which is shown as below:
\arg EFUSE_FLAG_ILLEGAL_ACCESS_ERR: illegal access error flag
\arg EFUSE_FLAG_PROGRAM_COMPLETE: programming operation completion flag
\arg EFUSE_FLAG_READ_COMPLETE: read operation completion flag
\arg EFUSE_FLAG_PROGRAM_VOLTAGE_ERR: program voltage setting error flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus efuse_flag_get(uint32_t flag)
{
if(EFUSE_STAT & (uint32_t)flag) {
return SET;
} else {
return RESET;
}
}
/*!
\brief clear EFUSE pending flag
\param[in] flag: specifies to clear a flag
only one parameter can be selected which is shown as below:
\arg EFUSE_FLAG_ILLEGAL_ACCESS_ERR_CLR: clear illegal access error flag
\arg EFUSE_FLAG_PROGRAM_COMPLETE_CLR: clear programming operation completion flag
\arg EFUSE_FLAG_READ_COMPLETE_CLR: clear read operation completion flag
\arg EFUSE_FLAG_PROGRAM_VOLTAGE_ERR_CLR: clear program voltage setting error interrupt flag
\param[out] none
\retval none
*/
void efuse_flag_clear(uint32_t flag)
{
EFUSE_STATC |= (uint32_t)flag;
}
/*!
\brief enable EFUSE interrupt
\param[in] interrupt: specifies an interrupt to enbale
only one parameter can be selected which is shown as below:
\arg EFUSE_INT_ILLEGAL_ACCESS_ERR: illegal access error interrupt
\arg EFUSE_INT_PROGRAM_COMPLETE: programming operation completion interrupt
\arg EFUSE_INT_READ_COMPLETE: read operation completion interrupt
\arg EFUSE_INT_PROGRAM_VOLTAGE_ERR: program voltage setting error interrupt
\param[out] none
\retval none
*/
void efuse_interrupt_enable(uint32_t interrupt)
{
EFUSE_CTL = (uint32_t)interrupt;
}
/*!
\brief disable EFUSE interrupt
\param[in] interrupt: specifies an interrupt to disbale
only one parameter can be selected which is shown as below:
\arg EFUSE_INT_ILLEGAL_ACCESS_ERR: illegal access error interrupt
\arg EFUSE_INT_PROGRAM_COMPLETE: programming operation completion interrupt
\arg EFUSE_INT_READ_COMPLETE: read operation completion interrupt
\arg EFUSE_INT_PROGRAM_VOLTAGE_ERR: program voltage setting error interrupt
\param[out] none
\retval none
*/
void efuse_interrupt_disable(uint32_t interrupt)
{
EFUSE_CTL &= ~(uint32_t)interrupt;
}
/*!
\brief check EFUSE interrupt flag is set or not
\param[in] int_flag: specifies to get a flag
only one parameter can be selected which is shown as below:
\arg EFUSE_INT_FLAG_ILLEGAL_ACCESS_ERR: illegal access error interrupt
\arg EFUSE_INT_FLAG_PROGRAM_COMPLETE: programming operation completion interrupt
\arg EFUSE_INT_FLAG_READ_COMPLETE: read operation completion interrupt
\arg EFUSE_INT_FLAG_PROGRAM_VOLTAGE_ERR: program voltage setting error interrupt
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus efuse_interrupt_flag_get(efuse_interrupt_flag_enum int_flag)
{
uint32_t intenable = 0U, flagstatus = 0U;
/* get the interrupt enable bit status */
intenable = (EFUSE_REG_VAL(int_flag) & BIT(EFUSE_BIT_POS(int_flag)));
/* get the corresponding flag bit status */
flagstatus = (EFUSE_REG_VAL2(int_flag) & BIT(EFUSE_BIT_POS2(int_flag)));
if(flagstatus && intenable) {
return SET;
} else {
return RESET;
}
}
/*!
\brief clear EFUSE pending interrupt flag
\param[in] int_flag: specifies to clear a flag
only one parameter can be selected which is shown as below:
\arg EFUSE_INT_FLAG_ILLEGAL_ACCESS_ERR_CLR: clear illegal access error interrupt flag
\arg EFUSE_INT_FLAG_PROGRAM_COMPLETE_CLR: clear programming operation completion interrupt flag
\arg EFUSE_INT_FLAG_READ_COMPLETE_CLR: clear operation completion interrupt flag
\arg EFUSE_INT_FLAG_PROGRAM_VOLTAGE_ERR_CLR: clear program voltage setting error interrupt flag
\param[out] none
\retval none
*/
void efuse_interrupt_flag_clear(uint32_t int_flag)
{
EFUSE_STATC |= (uint32_t)int_flag;
}
/*!
\brief check whether EFUSE is ready or not
\param[in] flag:
only one parameter can be selected which is shown as below:
\arg EFUSE_FLAG_ILLEGAL_ACCESS_ERR: illegal access error flag
\arg EFUSE_FLAG_PROGRAM_COMPLETE: programming operation completion flag
\arg EFUSE_FLAG_READ_COMPLETE: read operation completion flag
\arg EFUSE_FLAG_PROGRAM_VOLTAGE_ERR: program voltage setting error flag
\param[out] none
\retval state of EFUSE
\arg EFUSE_READY: EFUSE operation has been completed
\arg EFUSE_BUSY: EFUSE operation is in progress
\arg EFUSE_IAERR: illegal access error
\arg EFUSE_PVERR: program voltage setting error
\arg EFUSE_TOERR: EFUSE timeout error
*/
static efuse_state_enum efuse_ready_wait(uint32_t efuse_flag, uint32_t timeout)
{
efuse_state_enum efuse_state = EFUSE_BUSY;
/* wait for EFUSE ready */
do {
/* get EFUSE flag set or not */
if(EFUSE_STAT & (uint32_t)efuse_flag) {
efuse_state = EFUSE_READY;
} else if(EFUSE_STAT & EFUSE_STAT_IAERRIF) {
efuse_state = EFUSE_IAERR;
} else if(EFUSE_STAT & EFUSE_STAT_PVIF) {
efuse_state = EFUSE_PVERR;
} else {
/* illegal parameters */
}
timeout--;
} while((EFUSE_BUSY == efuse_state) && (0U != timeout));
if(EFUSE_BUSY == efuse_state) {
efuse_state = EFUSE_TOERR;
}
/* return the EFUSE state */
return efuse_state;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,942 @@
/*!
\file gd32h7xx_exmc.c
\brief EXMC driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 <stdlib.h>
#include "gd32h7xx_exmc.h"
/* EXMC bank0 register reset value */
#define BANK0_SNCTL_RESET ((uint32_t)0x000030DAU) /* SNCTL register reset value */
#define BANK0_SNTCFG_RESET ((uint32_t)0x0FFFFFFFU) /* SNTCFG register reset value */
#define BANK0_SNWTCFG_RESET ((uint32_t)0x0FFFFFFFU) /* SNWTCFG register reset value */
/* EXMC bank2 register reset value */
#define BANK2_NCTL_RESET ((uint32_t)0x00000008U) /* NCTL register reset value */
#define BANK2_NINTEN_RESET ((uint32_t)0x00000042U) /* NINTEN register reset value */
#define BANK2_NCTCFG_RESET ((uint32_t)0xFFFFFFFFU) /* NCTCFG register reset value */
#define BANK2_NATCFG_RESET ((uint32_t)0xFFFFFFFFU) /* NATCFG register reset value */
/* EXMC SDRAM device register reset value */
#define SDRAM_DEVICE_SDCTL_RESET ((uint32_t)0x000002D0U) /* SDCTL register reset value */
#define SDRAM_DEVICE_SDTCFG_RESET ((uint32_t)0x0FFFFFFFU) /* SDTCFG register reset value */
#define SDRAM_DEVICE_SDCMD_RESET ((uint32_t)0x00000000U) /* SDCMD register reset value */
#define SDRAM_DEVICE_SDARI_RESET ((uint32_t)0x00000000U) /* SDARI register reset value */
#define SDRAM_DEVICE_SDSTAT_RESET ((uint32_t)0x00000000U) /* SDSTAT register reset value */
#define SDRAM_DEVICE_SDRSCTL_RESET ((uint32_t)0x00000000U) /* SDRSCTL register reset value */
/* EXMC register bit offset */
/* EXMC_SNCTL register bit offset */
#define SNCTL_NRMUX_OFFSET ((uint32_t)0x00000001U) /* bit offset of NRMUX */
#define SNCTL_NREN_OFFSET ((uint32_t)0x00000006U) /* bit offset of NREN */
#define SNCTL_SBRSTEN_OFFSET ((uint32_t)0x00000008U) /* bit offset of SBRSTEN */
#define SNCTL_WREN_OFFSET ((uint32_t)0x0000000CU) /* bit offset of WREN */
#define SNCTL_NRWTEN_OFFSET ((uint32_t)0x0000000DU) /* bit offset of NRWTEN */
#define SNCTL_EXMODEN_OFFSET ((uint32_t)0x0000000EU) /* bit offset of EXMODEN */
#define SNCTL_ASYNCWAITEN_OFFSET ((uint32_t)0x0000000FU) /* bit offset of ASYNCWAITEN */
#define SNCTL_BKREMAP_OFFSET ((uint32_t)0x00000018U) /* bit offset of BKREMAP */
/* EXMC_SNTCFG register bit offset */
#define SNTCFG_AHLD_OFFSET ((uint32_t)0x00000004U) /* bit offset of AHLD */
#define SNTCFG_DSET_OFFSET ((uint32_t)0x00000008U) /* bit offset of DSET */
#define SNTCFG_BUSLAT_OFFSET ((uint32_t)0x00000010U) /* bit offset of BUSLAT */
/* EXMC_NCTL register bit offset */
#define NCTL_NDWTEN_OFFSET ((uint32_t)0x00000001U) /* bit offset of NDWTEN */
#define NCTL_ECCEN_OFFSET ((uint32_t)0x00000006U) /* bit offset of ECCEN */
/* EXMC_NCTCFG register bit offset */
#define NCTCFG_COMWAIT_OFFSET ((uint32_t)0x00000008U) /* bit offset of COMWAIT */
#define NCTCFG_COMHLD_OFFSET ((uint32_t)0x00000010U) /* bit offset of COMHLD */
#define NCTCFG_COMHIZ_OFFSET ((uint32_t)0x00000018U) /* bit offset of COMHIZ */
/* EXMC_NATCFG register bit offset */
#define NATCFG_ATTWAIT_OFFSET ((uint32_t)0x00000008U) /* bit offset of ATTWAIT */
#define NATCFG_ATTHLD_OFFSET ((uint32_t)0x00000010U) /* bit offset of ATTHLD */
#define NATCFG_ATTHIZ_OFFSET ((uint32_t)0x00000018U) /* bit offset of ATTHIZ */
/* EXMC_SDCTL register bit offset */
#define SDCTL_WPEN_OFFSET ((uint32_t)0x00000009U) /* bit offset of WPEN */
#define SDCTL_BRSTRD_OFFSET ((uint32_t)0x0000000CU) /* bit offset of BRSTRD */
/* EXMC_SDTCFG register bit offset */
#define SDTCFG_XSRD_OFFSET ((uint32_t)0x00000004U) /* bit offset of XSRD */
#define SDTCFG_RASD_OFFSET ((uint32_t)0x00000008U) /* bit offset of RASD */
#define SDTCFG_ARFD_OFFSET ((uint32_t)0x0000000CU) /* bit offset of ARFD */
#define SDTCFG_WRD_OFFSET ((uint32_t)0x00000010U) /* bit offset of WRD */
#define SDTCFG_RPD_OFFSET ((uint32_t)0x00000014U) /* bit offset of RPD */
#define SDTCFG_RCD_OFFSET ((uint32_t)0x00000018U) /* bit offset of RCD */
/* EXMC_SDCMD register bit offset */
#define SDCMD_NARF_OFFSET ((uint32_t)0x00000005U) /* bit offset of NARF */
#define SDCMD_MRC_OFFSET ((uint32_t)0x00000009U) /* bit offset of MRC */
/* EXMC_SDCMD register bit offset */
#define SDARI_ARINTV_OFFSET ((uint32_t)0x00000001U) /* bit offset of ARINTV */
/* EXMC_SDRSCTL register bit offset */
#define SDRSCTL_SSCR_OFFSET ((uint32_t)0x00000001U) /* bit offset of SSCR */
#define SDRSCTL_SDSC_OFFSET ((uint32_t)0x00000004U) /* bit offset of SDSC */
/* EXMC_SDSTAT register bit offset */
#define SDSTAT_STA0_OFFSET ((uint32_t)0x00000001U) /* bit offset of STA0 */
#define SDSTAT_STA1_OFFSET ((uint32_t)0x00000003U) /* bit offset of STA1 */
/* EXMC_NINTEN register interrupt enable bit and interrupt status bit interval */
#define NINTEN_INTEN_INTS_INTERVAL ((uint32_t)0x00000003U) /* bit offset of INTEN_INTS */
/*!
\brief deinitialize EXMC NOR/SRAM region
\param[in] exmc_norsram_region: select the region of bank0
only one parameter can be selected which is shown as below:
\arg EXMC_BANK0_NORSRAM_REGIONx(x=0..3): EXMC BANK0 REGIONx
\param[out] none
\retval none
*/
void exmc_norsram_deinit(uint32_t exmc_norsram_region)
{
/* reset the registers */
EXMC_SNCTL(exmc_norsram_region) = BANK0_SNCTL_RESET;
EXMC_SNTCFG(exmc_norsram_region) = BANK0_SNTCFG_RESET;
EXMC_SNWTCFG(exmc_norsram_region) = BANK0_SNWTCFG_RESET;
}
/*!
\brief initialize exmc_norsram_parameter_struct with the default values
\param[in] none
\param[out] exmc_norsram_init_struct: the initialized struct exmc_norsram_parameter_struct pointer
\retval none
*/
void exmc_norsram_struct_para_init(exmc_norsram_parameter_struct *exmc_norsram_init_struct)
{
/* configure control variables with default values */
exmc_norsram_init_struct->norsram_region = EXMC_BANK0_NORSRAM_REGION0;
exmc_norsram_init_struct->address_data_mux = ENABLE;
exmc_norsram_init_struct->memory_type = EXMC_MEMORY_TYPE_SRAM;
exmc_norsram_init_struct->databus_width = EXMC_NOR_DATABUS_WIDTH_8B;
exmc_norsram_init_struct->burst_mode = DISABLE;
exmc_norsram_init_struct->nwait_polarity = EXMC_NWAIT_POLARITY_LOW;
exmc_norsram_init_struct->nwait_config = EXMC_NWAIT_CONFIG_BEFORE;
exmc_norsram_init_struct->memory_write = ENABLE;
exmc_norsram_init_struct->nwait_signal = ENABLE;
exmc_norsram_init_struct->extended_mode = DISABLE;
exmc_norsram_init_struct->asyn_wait = DISABLE;
exmc_norsram_init_struct->cram_page_size = EXMC_CRAM_AUTO_SPLIT;
exmc_norsram_init_struct->write_mode = EXMC_ASYN_WRITE;
/* configure read/write timing */
exmc_norsram_init_struct->read_write_timing = NULL;
/* configure write timing when extended mode is used */
exmc_norsram_init_struct->write_timing = NULL;
}
/*!
\brief initialize EXMC NOR/SRAM region
\param[in] exmc_norsram_init_struct: configure the EXMC NOR/SRAM parameter
norsram_region: EXMC_BANK0_NORSRAM_REGIONx, x=0~3
write_mode: EXMC_ASYN_WRITE, EXMC_SYN_WRITE
extended_mode: ENABLE or DISABLE
asyn_wait: ENABLE or DISABLE
nwait_signal: ENABLE or DISABLE
memory_write: ENABLE or DISABLE
nwait_config: EXMC_NWAIT_CONFIG_BEFORE, EXMC_NWAIT_CONFIG_DURING
nwait_polarity: EXMC_NWAIT_POLARITY_LOW, EXMC_NWAIT_POLARITY_HIGH
burst_mode: ENABLE or DISABLE
databus_width: EXMC_NOR_DATABUS_WIDTH_8B, EXMC_NOR_DATABUS_WIDTH_16B
memory_type: EXMC_MEMORY_TYPE_SRAM, EXMC_MEMORY_TYPE_PSRAM, EXMC_MEMORY_TYPE_NOR
address_data_mux: ENABLE or DISABLE
cram_page_size: EXMC_CRAM_AUTO_SPLIT, EXMC_CRAM_PAGE_SIZE_128_BYTES, EXMC_CRAM_PAGE_SIZE_256_BYTES,
EXMC_CRAM_PAGE_SIZE_512_BYTES, EXMC_CRAM_PAGE_SIZE_1024_BYTES
read_write_timing: struct exmc_norsram_timing_parameter_struct set the time
asyn_access_mode: EXMC_ACCESS_MODE_A, EXMC_ACCESS_MODE_B, EXMC_ACCESS_MODE_C, EXMC_ACCESS_MODE_D
syn_data_latency: EXMC_DATALAT_x_CLK, x=2~17
syn_clk_division: EXMC_SYN_CLOCK_RATIO_x_CLK, x=2~16
bus_latency: 0x0U~0xFU
asyn_data_setuptime: 1~255
asyn_address_holdtime: 1~15
asyn_address_setuptime: 0~15
write_timing: struct exmc_norsram_timing_parameter_struct set the time
asyn_access_mode: EXMC_ACCESS_MODE_A, EXMC_ACCESS_MODE_B, EXMC_ACCESS_MODE_C, EXMC_ACCESS_MODE_D
syn_data_latency: EXMC_DATALAT_x_CLK, x=2~17
syn_clk_division: EXMC_SYN_CLOCK_RATIO_x_CLK, x=2~16
bus_latency: 0~15
asyn_data_setuptime: 1~255
asyn_address_holdtime: 1~15
asyn_address_setuptime: 0~15
\param[out] none
\retval none
*/
void exmc_norsram_init(exmc_norsram_parameter_struct *exmc_norsram_init_struct)
{
uint32_t snctl = 0x00000000U, sntcfg = 0x00000000U, snwtcfg = 0x00000000U;
/* get value of register EXMC_SNCTL */
snctl = EXMC_SNCTL(exmc_norsram_init_struct->norsram_region);
/* clear control bits */
snctl &= (uint32_t)(~(EXMC_SNCTL_NREN | EXMC_SNCTL_NRTP | EXMC_SNCTL_NRW | EXMC_SNCTL_SBRSTEN |
EXMC_SNCTL_NRWTPOL | EXMC_SNCTL_NRWTCFG | EXMC_SNCTL_WEN |
EXMC_SNCTL_NRWTEN | EXMC_SNCTL_EXMODEN | EXMC_SNCTL_ASYNCWTEN | EXMC_SNCTL_SYNCWR |
EXMC_SNCTL_NRMUX | EXMC_SNCTL_BKREMAP | EXMC_SNCTL_CCK | EXMC_SNCTL_CPS));
/* configure control bits */
snctl |= (uint32_t)((exmc_norsram_init_struct->address_data_mux << SNCTL_NRMUX_OFFSET) |
exmc_norsram_init_struct->memory_type |
exmc_norsram_init_struct->databus_width |
(exmc_norsram_init_struct->burst_mode << SNCTL_SBRSTEN_OFFSET) |
exmc_norsram_init_struct->nwait_polarity |
exmc_norsram_init_struct->nwait_config |
(exmc_norsram_init_struct->memory_write << SNCTL_WREN_OFFSET) |
(exmc_norsram_init_struct->nwait_signal << SNCTL_NRWTEN_OFFSET) |
(exmc_norsram_init_struct->extended_mode << SNCTL_EXMODEN_OFFSET) |
(exmc_norsram_init_struct->asyn_wait << SNCTL_ASYNCWAITEN_OFFSET) |
exmc_norsram_init_struct->write_mode |
exmc_norsram_init_struct->cram_page_size);
/* nor flash access enable */
if(EXMC_MEMORY_TYPE_NOR == exmc_norsram_init_struct->memory_type) {
snctl |= (uint32_t)EXMC_SNCTL_NREN;
}
/* configure timing */
sntcfg = (uint32_t)(exmc_norsram_init_struct->read_write_timing->asyn_address_setuptime |
(exmc_norsram_init_struct->read_write_timing->asyn_address_holdtime << SNTCFG_AHLD_OFFSET) |
(exmc_norsram_init_struct->read_write_timing->asyn_data_setuptime << SNTCFG_DSET_OFFSET) |
(exmc_norsram_init_struct->read_write_timing->bus_latency << SNTCFG_BUSLAT_OFFSET) |
exmc_norsram_init_struct->read_write_timing->syn_clk_division |
exmc_norsram_init_struct->read_write_timing->syn_data_latency |
exmc_norsram_init_struct->read_write_timing->asyn_access_mode);
if(ENABLE == exmc_norsram_init_struct->extended_mode) {
/* for extended mode, configure write timing */
snwtcfg = (uint32_t)(exmc_norsram_init_struct->write_timing->asyn_address_setuptime |
(exmc_norsram_init_struct->write_timing->asyn_address_holdtime << SNTCFG_AHLD_OFFSET) |
(exmc_norsram_init_struct->write_timing->asyn_data_setuptime << SNTCFG_DSET_OFFSET) |
(exmc_norsram_init_struct->write_timing->bus_latency << SNTCFG_BUSLAT_OFFSET) |
exmc_norsram_init_struct->write_timing->asyn_access_mode);
} else {
snwtcfg = BANK0_SNWTCFG_RESET;
}
/* configure the registers */
EXMC_SNCTL(exmc_norsram_init_struct->norsram_region) = snctl;
EXMC_SNTCFG(exmc_norsram_init_struct->norsram_region) = sntcfg;
EXMC_SNWTCFG(exmc_norsram_init_struct->norsram_region) = snwtcfg;
}
/*!
\brief enable EXMC NOR/PSRAM bank region
\param[in] exmc_norsram_region: specify the region of NOR/PSRAM bank
only one parameter can be selected which is shown as below:
\arg EXMC_BANK0_NORSRAM_REGIONx(x=0..3): EXMC BANK0 REGIONx
\param[out] none
\retval none
*/
void exmc_norsram_enable(uint32_t exmc_norsram_region)
{
EXMC_SNCTL(exmc_norsram_region) |= (uint32_t)EXMC_SNCTL_NRBKEN;
}
/*!
\brief disable EXMC NOR/PSRAM bank region
\param[in] exmc_norsram_region: specify the region of NOR/PSRAM Bank
only one parameter can be selected which is shown as below:
\arg EXMC_BANK0_NORSRAM_REGIONx(x=0..3): EXMC BANK0 REGIONx
\param[out] none
\retval none
*/
void exmc_norsram_disable(uint32_t exmc_norsram_region)
{
EXMC_SNCTL(exmc_norsram_region) &= ~(uint32_t)EXMC_SNCTL_NRBKEN;
}
/*!
\brief deinitialize EXMC NAND bank
\param[in] none
\param[out] none
\retval none
*/
void exmc_nand_deinit(void)
{
/* deinitialize EXMC_BANK2_NAND */
EXMC_NCTL = BANK2_NCTL_RESET;
EXMC_NINTEN = BANK2_NINTEN_RESET;
EXMC_NCTCFG = BANK2_NCTCFG_RESET;
EXMC_NATCFG = BANK2_NATCFG_RESET;
}
/*!
\brief initialize exmc_nand_parameter_struct with the default values
\param[in] none
\param[out] the initialized struct exmc_nand_parameter_struct pointer
\retval none
*/
void exmc_nand_struct_para_init(exmc_nand_parameter_struct *exmc_nand_init_struct)
{
/* configure the structure with default values */
exmc_nand_init_struct->wait_feature = DISABLE;
exmc_nand_init_struct->databus_width = EXMC_NAND_DATABUS_WIDTH_8B;
exmc_nand_init_struct->ecc_logic = DISABLE;
exmc_nand_init_struct->ecc_size = EXMC_ECC_SIZE_256BYTES;
exmc_nand_init_struct->ctr_latency = 0x00U;
exmc_nand_init_struct->atr_latency = 0x00U;
exmc_nand_init_struct->common_space_timing = NULL;
exmc_nand_init_struct->attribute_space_timing = NULL;
}
/*!
\brief initialize EXMC NAND bank
\param[in] exmc_nand_init_struct: configure the EXMC NAND parameter
ecc_size: EXMC_ECC_SIZE_xBYTES,x=256,512,1024,2048,4096
atr_latency: EXMC_ALE_RE_DELAY_x_CK_EXMC,x=1~16
ctr_latency: EXMC_CLE_RE_DELAY_x_CK_EXMC,x=1~16
ecc_logic: ENABLE or DISABLE
databus_width: EXMC_NAND_DATABUS_WIDTH_8B,EXMC_NAND_DATABUS_WIDTH_16B
wait_function: ENABLE or DISABLE
common_space_timing: struct exmc_nand_timing_parameter_struct set the time
databus_hiztime: 1~255
holdtime: 1~254
waittime: 2~255
setuptime: 1~255
attribute_space_timing: struct exmc_nand_timing_parameter_struct set the time
databus_hiztime: 0~254
holdtime: 1~254
waittime: 2~255
setuptime: 1~255
\param[out] none
\retval none
*/
void exmc_nand_init(exmc_nand_parameter_struct *exmc_nand_init_struct)
{
uint32_t nctl = 0x00000000U, nctcfg = 0x00000000U, natcfg = 0x00000000U;
/* configure nctl for EXMC_NCTL */
nctl = (uint32_t)((exmc_nand_init_struct->wait_feature << NCTL_NDWTEN_OFFSET) |
exmc_nand_init_struct->databus_width |
(exmc_nand_init_struct->ecc_logic << NCTL_ECCEN_OFFSET) |
exmc_nand_init_struct->ecc_size |
exmc_nand_init_struct->ctr_latency |
exmc_nand_init_struct->atr_latency);
/* configure nctcfg for EXMC_NCTCFG */
nctcfg = (uint32_t)(((exmc_nand_init_struct->common_space_timing->setuptime - 1U) & EXMC_NCTCFG_COMSET) |
(((exmc_nand_init_struct->common_space_timing->waittime - 1U) << NCTCFG_COMWAIT_OFFSET) & EXMC_NCTCFG_COMWAIT) |
((exmc_nand_init_struct->common_space_timing->holdtime << NCTCFG_COMHLD_OFFSET) & EXMC_NCTCFG_COMHLD) |
(((exmc_nand_init_struct->common_space_timing->databus_hiztime - 1U) << NCTCFG_COMHIZ_OFFSET) & EXMC_NCTCFG_COMHIZ));
/* configure natcfg for EXMC_NATCFG */
natcfg = (uint32_t)(((exmc_nand_init_struct->attribute_space_timing->setuptime - 1U) & EXMC_NATCFG_ATTSET) |
(((exmc_nand_init_struct->attribute_space_timing->waittime - 1U) << NATCFG_ATTWAIT_OFFSET) & EXMC_NATCFG_ATTWAIT) |
((exmc_nand_init_struct->attribute_space_timing->holdtime << NATCFG_ATTHLD_OFFSET) & EXMC_NATCFG_ATTHLD) |
((exmc_nand_init_struct->attribute_space_timing->databus_hiztime << NATCFG_ATTHIZ_OFFSET) & EXMC_NATCFG_ATTHIZ));
/* initialize EXMC_BANK2_NAND */
EXMC_NCTL = nctl;
EXMC_NCTCFG = nctcfg;
EXMC_NATCFG = natcfg;
}
/*!
\brief enable NAND bank
\param[in] none
\param[out] none
\retval none
*/
void exmc_nand_enable(void)
{
EXMC_NCTL |= EXMC_NCTL_NDBKEN;
}
/*!
\brief disable NAND bank
\param[in] none
\param[out] none
\retval none
*/
void exmc_nand_disable(void)
{
EXMC_NCTL &= ~EXMC_NCTL_NDBKEN;
}
/*!
\brief deinitialize EXMC SDRAM device
\param[in] exmc_sdram_device: select the SRAM device
only one parameter can be selected which is shown as below:
\arg EXMC_SDRAM_DEVICEx(x=0, 1)
\param[in] none
\param[out] none
\retval none
*/
void exmc_sdram_deinit(uint32_t exmc_sdram_device)
{
/* reset SDRAM registers */
EXMC_SDCTL(exmc_sdram_device) = SDRAM_DEVICE_SDCTL_RESET;
EXMC_SDTCFG(exmc_sdram_device) = SDRAM_DEVICE_SDTCFG_RESET;
EXMC_SDCMD = SDRAM_DEVICE_SDCMD_RESET;
EXMC_SDARI = SDRAM_DEVICE_SDARI_RESET;
EXMC_SDRSCTL = SDRAM_DEVICE_SDRSCTL_RESET;
}
/*!
\brief initialize exmc_sdram_parameter_struct with the default values
\param[in] none
\param[out] the initialized struct exmc_parameter_struct pointer
\retval none
*/
void exmc_sdram_struct_para_init(exmc_sdram_parameter_struct *exmc_sdram_init_struct)
{
/* configure the structure with default values */
exmc_sdram_init_struct->sdram_device = EXMC_SDRAM_DEVICE0;
exmc_sdram_init_struct->column_address_width = EXMC_SDRAM_COW_ADDRESS_8;
exmc_sdram_init_struct->row_address_width = EXMC_SDRAM_ROW_ADDRESS_11;
exmc_sdram_init_struct->data_width = EXMC_SDRAM_DATABUS_WIDTH_16B;
exmc_sdram_init_struct->internal_bank_number = EXMC_SDRAM_4_INTER_BANK;
exmc_sdram_init_struct->cas_latency = EXMC_CAS_LATENCY_1_SDCLK;
exmc_sdram_init_struct->write_protection = ENABLE;
exmc_sdram_init_struct->sdclock_config = EXMC_SDCLK_DISABLE;
exmc_sdram_init_struct->burst_read_switch = DISABLE;
exmc_sdram_init_struct->pipeline_read_delay = EXMC_PIPELINE_DELAY_0_CK_EXMC;
exmc_sdram_init_struct->timing = NULL;
}
/*!
\brief initialize EXMC SDRAM device
\param[in] exmc_sdram_init_struct: configure the EXMC SDRAM parameter
sdram_device: EXMC_SDRAM_DEVICE0,EXMC_SDRAM_DEVICE1
pipeline_read_delay: EXMC_PIPELINE_DELAY_x_CK_EXMC,x=0~2
burst_read_switch: ENABLE or DISABLE
sdclock_config: EXMC_SDCLK_DISABLE,EXMC_SDCLK_PERIODS_2_CK_EXMC,EXMC_SDCLK_PERIODS_3_CK_EXMC,EXMC_SDCLK_PERIODS_4_CK_EXMC,EXMC_SDCLK_PERIODS_5_CK_EXMC
write_protection: ENABLE or DISABLE
cas_latency: EXMC_CAS_LATENCY_x_SDCLK,x=1~3
internal_bank_number: EXMC_SDRAM_2_INTER_BANK,EXMC_SDRAM_4_INTER_BANK
data_width: EXMC_SDRAM_DATABUS_WIDTH_8B,EXMC_SDRAM_DATABUS_WIDTH_16B,EXMC_SDRAM_DATABUS_WIDTH_32B
row_address_width: EXMC_SDRAM_ROW_ADDRESS_x,x=11~13
column_address_width: EXMC_SDRAM_COW_ADDRESS_x,x=8~11
timing: exmc_sdram_timing_parameter_struct set the time
row_to_column_delay: 1~16
row_precharge_delay: 1~16
write_recovery_delay: 1~16
auto_refresh_delay: 1~16
row_address_select_delay: 1~16
exit_selfrefresh_delay: 1~16
load_mode_register_delay: 1~16
\param[out] none
\retval none
*/
void exmc_sdram_init(exmc_sdram_parameter_struct *exmc_sdram_init_struct)
{
uint32_t sdctl0, sdctl1, sdtcfg0, sdtcfg1;
/* configure EXMC_SDCTL0 or EXMC_SDCTL1 */
if(EXMC_SDRAM_DEVICE0 == exmc_sdram_init_struct->sdram_device) {
/* configure EXMC_SDCTL0 */
EXMC_SDCTL(EXMC_SDRAM_DEVICE0) = (uint32_t)(exmc_sdram_init_struct->column_address_width |
exmc_sdram_init_struct->row_address_width |
exmc_sdram_init_struct->data_width |
exmc_sdram_init_struct->internal_bank_number |
exmc_sdram_init_struct->cas_latency |
(exmc_sdram_init_struct->write_protection << SDCTL_WPEN_OFFSET) |
exmc_sdram_init_struct->sdclock_config |
(exmc_sdram_init_struct->burst_read_switch << SDCTL_BRSTRD_OFFSET) |
exmc_sdram_init_struct->pipeline_read_delay);
/* configure EXMC_SDTCFG0 */
EXMC_SDTCFG(EXMC_SDRAM_DEVICE0) = (uint32_t)((exmc_sdram_init_struct->timing->load_mode_register_delay) - 1U) |
(((exmc_sdram_init_struct->timing->exit_selfrefresh_delay) - 1U) << SDTCFG_XSRD_OFFSET) |
(((exmc_sdram_init_struct->timing->row_address_select_delay) - 1U) << SDTCFG_RASD_OFFSET) |
(((exmc_sdram_init_struct->timing->auto_refresh_delay) - 1U) << SDTCFG_ARFD_OFFSET) |
(((exmc_sdram_init_struct->timing->write_recovery_delay) - 1U) << SDTCFG_WRD_OFFSET) |
(((exmc_sdram_init_struct->timing->row_precharge_delay) - 1U) << SDTCFG_RPD_OFFSET) |
(((exmc_sdram_init_struct->timing->row_to_column_delay) - 1U) << SDTCFG_RCD_OFFSET);
} else {
/* configure EXMC_SDCTL0 and EXMC_SDCTL1 */
/* some bits in the EXMC_SDCTL1 register are reserved */
sdctl0 = EXMC_SDCTL(EXMC_SDRAM_DEVICE0) & (~(EXMC_SDCTL_PIPED | EXMC_SDCTL_BRSTRD | EXMC_SDCTL_SDCLK | EXMC_SDCTL_SDCLK_2));
sdctl0 |= (uint32_t)(exmc_sdram_init_struct->sdclock_config |
(exmc_sdram_init_struct->burst_read_switch << SDCTL_BRSTRD_OFFSET) |
exmc_sdram_init_struct->pipeline_read_delay);
sdctl1 = (uint32_t)(exmc_sdram_init_struct->column_address_width |
exmc_sdram_init_struct->row_address_width |
exmc_sdram_init_struct->data_width |
exmc_sdram_init_struct->internal_bank_number |
exmc_sdram_init_struct->cas_latency |
(exmc_sdram_init_struct->write_protection << SDCTL_WPEN_OFFSET));
EXMC_SDCTL(EXMC_SDRAM_DEVICE0) = sdctl0;
EXMC_SDCTL(EXMC_SDRAM_DEVICE1) = sdctl1;
/* configure EXMC_SDTCFG0 and EXMC_SDTCFG1 */
/* some bits in the EXMC_SDTCFG1 register are reserved */
sdtcfg0 = EXMC_SDTCFG(EXMC_SDRAM_DEVICE0) & (~(EXMC_SDTCFG_RPD | EXMC_SDTCFG_WRD | EXMC_SDTCFG_ARFD));
sdtcfg0 |= (uint32_t)((((exmc_sdram_init_struct->timing->auto_refresh_delay) - 1U) << SDTCFG_ARFD_OFFSET) |
(((exmc_sdram_init_struct->timing->row_precharge_delay) - 1U) << SDTCFG_RPD_OFFSET) |
(((exmc_sdram_init_struct->timing->write_recovery_delay) - 1U) << SDTCFG_WRD_OFFSET));
sdtcfg1 = (uint32_t)(((exmc_sdram_init_struct->timing->load_mode_register_delay) - 1U) |
(((exmc_sdram_init_struct->timing->exit_selfrefresh_delay) - 1U) << SDTCFG_XSRD_OFFSET) |
(((exmc_sdram_init_struct->timing->row_address_select_delay) - 1U) << SDTCFG_RASD_OFFSET) |
(((exmc_sdram_init_struct->timing->row_to_column_delay) - 1U) << SDTCFG_RCD_OFFSET));
EXMC_SDTCFG(EXMC_SDRAM_DEVICE0) = sdtcfg0;
EXMC_SDTCFG(EXMC_SDRAM_DEVICE1) = sdtcfg1;
}
}
/*!
\brief configure NOR/PSRAM and SDRAM remap
\param[in] bank_remap: NOR/PSRAM and SDRAM map address
only one parameter can be selected which is shown as below:
\arg EXMC_BANK_REMAP_DEFAULT: default mapping
\arg EXMC_BANK_NORPSRAM_SDRAM_SWAP: NOR/PSRAM bank and SDRAM device 0 swapped
\param[out] none
\retval none
*/
void exmc_norsram_sdram_remap_config(uint32_t bank_remap)
{
/* reset BKREMAP bits */
EXMC_SNCTL(EXMC_BANK0_NORSRAM_REGION0) &= (uint32_t)(~EXMC_SNCTL_BKREMAP);
EXMC_SNCTL(EXMC_BANK0_NORSRAM_REGION0) |= bank_remap;
}
/*!
\brief get NOR/PSRAM and SDRAM remap configuration
\param[in] none
\param[out] none
\retval bank remap value
\arg EXMC_BANK_REMAP_DEFAULT: default mapping
\arg EXMC_BANK_NORPSRAM_SDRAM_SWAP: NOR/PSRAM bank and SDRAM device 0 swapped
*/
uint32_t exmc_norsram_sdram_remap_get(void)
{
uint32_t bank_remap;
bank_remap = EXMC_SNCTL(EXMC_BANK0_NORSRAM_REGION0) & EXMC_SNCTL_BKREMAP;
return bank_remap;
}
/*!
\brief configure consecutive clock mode (consecutive clock is only supported in EXMC BANK0 REGION0)
\param[in] clock_mode: specify when the clock is generated
only one parameter can be selected which is shown as below:
\arg EXMC_CLOCK_SYN_MODE: the clock is generated only during synchronous access
\arg EXMC_CLOCK_UNCONDITIONALLY: the clock is generated unconditionally
\param[out] none
\retval none
*/
void exmc_norsram_consecutive_clock_config(uint32_t clock_mode)
{
if(EXMC_CLOCK_UNCONDITIONALLY == clock_mode) {
EXMC_SNCTL(EXMC_BANK0_NORSRAM_REGION0) |= EXMC_CLOCK_UNCONDITIONALLY;
} else {
EXMC_SNCTL(EXMC_BANK0_NORSRAM_REGION0) &= ~EXMC_CLOCK_UNCONDITIONALLY;
}
}
/*!
\brief configure CRAM page size
\param[in] exmc_norsram_region: select the region of bank0
only one parameter can be selected which is shown as below:
\arg EXMC_BANK0_NORSRAM_REGIONx(x=0..3)
\param[in] page_size: CRAM page size
only one parameter can be selected which is shown as below:
\arg EXMC_CRAM_AUTO_SPLIT: the clock is generated only during synchronous access
\arg EXMC_CRAM_PAGE_SIZE_128_BYTES: page size is 128 bytes
\arg EXMC_CRAM_PAGE_SIZE_256_BYTES: page size is 256 bytes
\arg EXMC_CRAM_PAGE_SIZE_512_BYTES: page size is 512 bytes
\arg EXMC_CRAM_PAGE_SIZE_1024_BYTES: page size is 1024 bytes
\param[out] none
\retval none
*/
void exmc_norsram_page_size_config(uint32_t exmc_norsram_region, uint32_t page_size)
{
/* reset the bits */
EXMC_SNCTL(exmc_norsram_region) &= ~EXMC_SNCTL_CPS;
EXMC_SNCTL(exmc_norsram_region) |= page_size;
}
/*!
\brief enable or disable the EXMC NAND ECC function
\param[in] newvalue: ENABLE or DISABLE
\param[out] none
\retval none
*/
void exmc_nand_ecc_config(ControlStatus newvalue)
{
if(ENABLE == newvalue) {
/* enable NAND bank ECC function */
EXMC_NCTL |= EXMC_NCTL_ECCEN;
} else {
/* disable NAND bank ECC function */
EXMC_NCTL &= ~EXMC_NCTL_ECCEN;
}
}
/*!
\brief get the EXMC ECC value
\param[in] none
\param[out] none
\retval the error correction code(ECC) value
*/
uint32_t exmc_ecc_get(void)
{
return(EXMC_NECC);
}
/*!
\brief enable read sample function
\param[in] none
\param[out] none
\retval none
*/
void exmc_sdram_readsample_enable(void)
{
EXMC_SDRSCTL |= EXMC_SDRSCTL_RSEN;
}
/*!
\brief disable read sample function
\param[in] none
\param[out] none
\retval none
*/
void exmc_sdram_readsample_disable(void)
{
EXMC_SDRSCTL &= (uint32_t)(~EXMC_SDRSCTL_RSEN);
}
/*!
\brief configure the delayed sample clock of read data
\param[in] delay_cell: SDRAM the delayed sample clock of read data
only one parameter can be selected which is shown as below:
\arg EXMC_SDRAM_x_DELAY_CELL(x=0..15)
\param[in] extra_clk: sample cycle of read data
only one parameter can be selected which is shown as below:
\arg EXMC_SDRAM_READSAMPLE_0_EXTRACK: add 0 extra CK_EXMC cycle to the read data sample clock besides the delay chain
\arg EXMC_SDRAM_READSAMPLE_1_EXTRACK: add 1 extra CK_EXMC cycle to the read data sample clock besides the delay chain
\param[out] none
\retval none
*/
void exmc_sdram_readsample_config(uint32_t delay_cell, uint32_t extra_clk)
{
uint32_t sdrsctl = 0U;
/* reset the bits */
sdrsctl = EXMC_SDRSCTL & (~(EXMC_SDRSCTL_SDSC | EXMC_SDRSCTL_SSCR));
/* set the bits */
sdrsctl |= (uint32_t)(delay_cell | extra_clk);
EXMC_SDRSCTL = sdrsctl;
}
/*!
\brief configure the SDRAM memory command
\param[in] exmc_sdram_command_init_struct: initialize EXMC SDRAM command
mode_register_content:
auto_refresh_number: EXMC_SDRAM_AUTO_REFLESH_x_SDCLK, x=1~15
bank_select: EXMC_SDRAM_DEVICE0_SELECT, EXMC_SDRAM_DEVICE1_SELECT, EXMC_SDRAM_DEVICE0_1_SELECT
command: EXMC_SDRAM_NORMAL_OPERATION, EXMC_SDRAM_CLOCK_ENABLE, EXMC_SDRAM_PRECHARGE_ALL,
EXMC_SDRAM_AUTO_REFRESH, EXMC_SDRAM_LOAD_MODE_REGISTER, EXMC_SDRAM_SELF_REFRESH,
EXMC_SDRAM_POWERDOWN_ENTRY
\param[out] none
\retval none
*/
void exmc_sdram_command_config(exmc_sdram_command_parameter_struct *exmc_sdram_command_init_struct)
{
/* configure command register */
EXMC_SDCMD = (uint32_t)((exmc_sdram_command_init_struct->command) |
(exmc_sdram_command_init_struct->bank_select) |
((exmc_sdram_command_init_struct->auto_refresh_number)) |
((exmc_sdram_command_init_struct->mode_register_content) << SDCMD_MRC_OFFSET));
}
/*!
\brief set auto-refresh interval
\param[in] exmc_count: the number SDRAM clock cycles unit between two successive auto-refresh commands, 0x00000000~0x00001FFF
\param[out] none
\retval none
*/
void exmc_sdram_refresh_count_set(uint32_t exmc_count)
{
uint32_t sdari;
sdari = EXMC_SDARI & (~EXMC_SDARI_ARINTV);
EXMC_SDARI = sdari | (uint32_t)((exmc_count << SDARI_ARINTV_OFFSET) & EXMC_SDARI_ARINTV);
}
/*!
\brief set the number of successive auto-refresh command
\param[in] exmc_number: the number of successive Auto-refresh cycles will be send, 1~15
\param[out] none
\retval none
*/
void exmc_sdram_autorefresh_number_set(uint32_t exmc_number)
{
uint32_t sdcmd;
sdcmd = EXMC_SDCMD & (~EXMC_SDCMD_NARF);
EXMC_SDCMD = sdcmd | (uint32_t)((exmc_number << SDCMD_NARF_OFFSET) & EXMC_SDCMD_NARF);
}
/*!
\brief configure the write protection function
\param[in] exmc_sdram_device: specify the SDRAM device
only one parameter can be selected which is shown as below:
\arg EXMC_SDRAM_DEVICEx(x=0,1)
\param[in] newvalue: ENABLE or DISABLE
\param[out] none
\retval none
*/
void exmc_sdram_write_protection_config(uint32_t exmc_sdram_device, ControlStatus newvalue)
{
if(ENABLE == newvalue) {
EXMC_SDCTL(exmc_sdram_device) |= (uint32_t)EXMC_SDCTL_WPEN;
} else {
EXMC_SDCTL(exmc_sdram_device) &= ~((uint32_t)EXMC_SDCTL_WPEN);
}
}
/*!
\brief get the status of SDRAM device0 or device1
\param[in] exmc_sdram_device: specify the SDRAM device
only one parameter can be selected which is shown as below:
\arg EXMC_SDRAM_DEVICEx(x=0,1)
\param[out] none
\retval the status of SDRAM device
*/
uint32_t exmc_sdram_bankstatus_get(uint32_t exmc_sdram_device)
{
uint32_t sdstat = 0U;
if(EXMC_SDRAM_DEVICE0 == exmc_sdram_device) {
sdstat = ((uint32_t)(EXMC_SDSTAT & EXMC_SDSDAT_STA0) >> SDSTAT_STA0_OFFSET);
} else {
sdstat = ((uint32_t)(EXMC_SDSTAT & EXMC_SDSDAT_STA1) >> SDSTAT_STA1_OFFSET);
}
return sdstat;
}
/*!
\brief get EXMC flag status
\param[in] exmc_bank: specify the NAND bank or SDRAM device
only one parameter can be selected which is shown as below:
\arg EXMC_BANK2_NAND: the NAND bank2
\arg EXMC_SDRAM_DEVICE0: the SDRAM device0
\arg EXMC_SDRAM_DEVICE1: the SDRAM device1
\param[in] flag: EXMC status and flag
only one parameter can be selected which is shown as below:
\arg EXMC_NAND_FLAG_LEVEL: interrupt high-level status
\arg EXMC_NAND_FLAG_RISE: interrupt rising edge status
\arg EXMC_NAND_FLAG_FALL: interrupt falling edge status
\arg EXMC_NAND_FLAG_FIFOE: FIFO empty flag
\arg EXMC_SDRAM_FLAG_REFRESH: refresh error interrupt flag
\arg EXMC_SDRAM_FLAG_NREADY: not ready status
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus exmc_flag_get(uint32_t exmc_bank, uint32_t flag)
{
uint32_t status = 0x00000000U;
if(EXMC_BANK2_NAND == exmc_bank) {
/* NAND bank2 */
status = EXMC_NINTEN;
} else {
/* SDRAM device0 or device1 */
status = EXMC_SDSTAT;
}
if((status & flag) != (uint32_t)flag) {
/* flag is reset */
return RESET;
} else {
/* flag is set */
return SET;
}
}
/*!
\brief clear EXMC flag status
\param[in] exmc_bank: specify the NAND bank or SDRAM device
only one parameter can be selected which is shown as below:
\arg EXMC_BANK2_NAND: the NAND bank2
\arg EXMC_SDRAM_DEVICE0: the SDRAM device0
\arg EXMC_SDRAM_DEVICE1: the SDRAM device1
\param[in] flag: EXMC status and flag
only one parameter can be selected which is shown as below:
\arg EXMC_NAND_FLAG_LEVEL: interrupt high-level status
\arg EXMC_NAND_FLAG_RISE: interrupt rising edge status
\arg EXMC_NAND_FLAG_FALL: interrupt falling edge status
\arg EXMC_NAND_FLAG_FIFOE: FIFO empty flag
\arg EXMC_SDRAM_FLAG_REFRESH: refresh error interrupt flag
\param[out] none
\retval none
*/
void exmc_flag_clear(uint32_t exmc_bank, uint32_t flag)
{
if(EXMC_BANK2_NAND == exmc_bank) {
/* NAND bank2 */
EXMC_NINTEN &= ~flag;
} else {
/* SDRAM device0 or device1 */
EXMC_SDARI |= EXMC_SDARI_REC;
}
}
/*!
\brief enable EXMC interrupt
\param[in] exmc_bank: specify the NAND bank or SDRAM device
only one parameter can be selected which is shown as below:
\arg EXMC_BANK2_NAND: the NAND bank2
\arg EXMC_SDRAM_DEVICE0: the SDRAM device0
\arg EXMC_SDRAM_DEVICE1: the SDRAM device1
\param[in] interrupt: specify get which interrupt flag
only one parameter can be selected which is shown as below:
\arg EXMC_NAND_INT_FLAG_LEVEL: high-level interrupt flag
\arg EXMC_NAND_INT_FLAG_RISE: rising edge interrupt flag
\arg EXMC_NAND_INT_FLAG_FALL: falling edge interrupt flag
\arg EXMC_SDRAM_INT_FLAG_REFRESH: refresh error interrupt flag
\param[out] none
\retval none
*/
void exmc_interrupt_enable(uint32_t exmc_bank, uint32_t interrupt)
{
if(EXMC_BANK2_NAND == exmc_bank) {
/* NAND bank2 */
EXMC_NINTEN |= interrupt;
} else {
/* SDRAM device0 or device1 */
EXMC_SDARI |= EXMC_SDARI_REIE;
}
}
/*!
\brief disable EXMC interrupt
\param[in] exmc_bank: specify the NAND bank or SDRAM device
only one parameter can be selected which is shown as below:
\arg EXMC_BANK2_NAND: the NAND bank2
\arg EXMC_SDRAM_DEVICE0: the SDRAM device0
\arg EXMC_SDRAM_DEVICE1: the SDRAM device1
\param[in] interrupt: specify get which interrupt flag
only one parameter can be selected which is shown as below:
\arg EXMC_NAND_INT_LEVEL: high-level interrupt
\arg EXMC_NAND_INT_RISE: rising edge interrupt
\arg EXMC_NAND_INT_FALL: falling edge interrupt
\arg EXMC_SDRAM_INT_REFRESH: refresh error interrupt
\param[out] none
\retval none
*/
void exmc_interrupt_disable(uint32_t exmc_bank, uint32_t interrupt)
{
if(EXMC_BANK2_NAND == exmc_bank) {
/* NAND bank2 */
EXMC_NINTEN &= ~interrupt;
} else {
/* SDRAM device0 or device1 */
EXMC_SDARI &= ~EXMC_SDARI_REIE;
}
}
/*!
\brief get EXMC interrupt flag
\param[in] exmc_bank: specify the NAND bank or SDRAM device
only one parameter can be selected which is shown as below:
\arg EXMC_BANK2_NAND: the NAND bank2
\arg EXMC_SDRAM_DEVICE0: the SDRAM device0
\arg EXMC_SDRAM_DEVICE1: the SDRAM device1
\param[in] interrupt: EXMC interrupt flag
only one parameter can be selected which is shown as below:
\arg EXMC_NAND_INT_FLAG_LEVEL: high-level interrupt flag
\arg EXMC_NAND_INT_FLAG_RISE: rising edge interrupt flag
\arg EXMC_NAND_INT_FLAG_FALL: falling edge interrupt flag
\arg EXMC_SDRAM_INT_FLAG_REFRESH: refresh error interrupt and flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus exmc_interrupt_flag_get(uint32_t exmc_bank, uint32_t interrupt)
{
uint32_t reg_value = 0x00000000U;
uint32_t interrupt_enable = 0x00000000U;
uint32_t interrupt_status = 0x00000000U;
if(EXMC_BANK2_NAND == exmc_bank) {
/* NAND bank2 */
reg_value = EXMC_NINTEN;
interrupt_status = (reg_value & (interrupt >> NINTEN_INTEN_INTS_INTERVAL));
} else {
/* SDRAM device0 or device1 */
reg_value = EXMC_SDARI;
interrupt_status = (EXMC_SDSTAT & EXMC_SDSDAT_REIF);
}
interrupt_enable = (reg_value & interrupt);
if((interrupt_enable) && (interrupt_status)) {
/* interrupt flag is set */
return SET;
} else {
/* interrupt flag is reset */
return RESET;
}
}
/*!
\brief clear EXMC interrupt flag
\param[in] exmc_bank: specify the NAND bank or SDRAM device
only one parameter can be selected which is shown as below:
\arg EXMC_BANK2_NAND: the NAND bank2
\arg EXMC_SDRAM_DEVICE0: the SDRAM device0
\arg EXMC_SDRAM_DEVICE1: the SDRAM device1
\param[in] interrupt: EXMC interrupt flag
only one parameter can be selected which is shown as below:
\arg EXMC_NAND_INT_FLAG_LEVEL: high-level interrupt and flag
\arg EXMC_NAND_INT_FLAG_RISE: rising edge interrupt and flag
\arg EXMC_NAND_INT_FLAG_FALL: falling edge interrupt and flag
\arg EXMC_SDRAM_INT_FLAG_REFRESH: refresh error interrupt and flag
\param[out] none
\retval none
*/
void exmc_interrupt_flag_clear(uint32_t exmc_bank, uint32_t interrupt)
{
if(EXMC_BANK2_NAND == exmc_bank) {
/* NAND bank2 */
EXMC_NINTEN &= ~(interrupt >> NINTEN_INTEN_INTS_INTERVAL);
} else {
/* SDRAM device0 or device1 */
EXMC_SDARI |= EXMC_SDARI_REC;
}
}
@@ -0,0 +1,254 @@
/*!
\file gd32h7xx_exti.c
\brief EXTI driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_exti.h"
#define EXTI_REG_RESET_VALUE ((uint32_t)0x00000000U)
/*!
\brief deinitialize the EXTI
\param[in] none
\param[out] none
\retval none
*/
void exti_deinit(void)
{
/* reset the value of all the EXTI registers */
EXTI_INTEN0 = EXTI_REG_RESET_VALUE;
EXTI_EVEN0 = EXTI_REG_RESET_VALUE;
EXTI_RTEN0 = EXTI_REG_RESET_VALUE;
EXTI_FTEN0 = EXTI_REG_RESET_VALUE;
EXTI_SWIEV0 = EXTI_REG_RESET_VALUE;
EXTI_INTEN1 = EXTI_REG_RESET_VALUE;
EXTI_EVEN1 = EXTI_REG_RESET_VALUE;
EXTI_RTEN1 = EXTI_REG_RESET_VALUE;
EXTI_FTEN1 = EXTI_REG_RESET_VALUE;
EXTI_SWIEV1 = EXTI_REG_RESET_VALUE;
}
/*!
\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..37): 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 and event 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(EXTI_REG_VAL(linex)) &= ~EXTI_BIT_POS(linex);
EXTI_EVEN(EXTI_REG_VAL(linex)) &= ~EXTI_BIT_POS(linex);
EXTI_RTEN(EXTI_REG_VAL(linex)) &= ~EXTI_BIT_POS(linex);
EXTI_FTEN(EXTI_REG_VAL(linex)) &= ~EXTI_BIT_POS(linex);
/* set the EXTI mode and enable the interrupts or events from EXTI line x */
switch(mode) {
case EXTI_INTERRUPT:
EXTI_INTEN(EXTI_REG_VAL(linex)) |= EXTI_BIT_POS(linex);
break;
case EXTI_EVENT:
EXTI_EVEN(EXTI_REG_VAL(linex)) |= EXTI_BIT_POS(linex);
break;
default:
break;
}
/* set the EXTI trigger type */
switch(trig_type) {
case EXTI_TRIG_RISING:
EXTI_RTEN(EXTI_REG_VAL(linex)) |= EXTI_BIT_POS(linex);
EXTI_FTEN(EXTI_REG_VAL(linex)) &= ~EXTI_BIT_POS(linex);
break;
case EXTI_TRIG_FALLING:
EXTI_RTEN(EXTI_REG_VAL(linex)) &= ~EXTI_BIT_POS(linex);
EXTI_FTEN(EXTI_REG_VAL(linex)) |= EXTI_BIT_POS(linex);
break;
case EXTI_TRIG_BOTH:
EXTI_RTEN(EXTI_REG_VAL(linex)) |= EXTI_BIT_POS(linex);
EXTI_FTEN(EXTI_REG_VAL(linex)) |= EXTI_BIT_POS(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..37): EXTI line x
\param[out] none
\retval none
*/
void exti_interrupt_enable(exti_line_enum linex)
{
EXTI_INTEN(EXTI_REG_VAL(linex)) |= EXTI_BIT_POS(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..37): EXTI line x
\param[out] none
\retval none
*/
void exti_interrupt_disable(exti_line_enum linex)
{
EXTI_INTEN(EXTI_REG_VAL(linex)) &= ~EXTI_BIT_POS(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..37): EXTI line x
\param[out] none
\retval none
*/
void exti_event_enable(exti_line_enum linex)
{
EXTI_EVEN(EXTI_REG_VAL(linex)) |= EXTI_BIT_POS(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..37): EXTI line x
\param[out] none
\retval none
*/
void exti_event_disable(exti_line_enum linex)
{
EXTI_EVEN(EXTI_REG_VAL(linex)) &= ~EXTI_BIT_POS(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..37): EXTI line x
\param[out] none
\retval none
*/
void exti_software_interrupt_enable(exti_line_enum linex)
{
EXTI_SWIEV(EXTI_REG_VAL(linex)) |= EXTI_BIT_POS(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..37): EXTI line x
\param[out] none
\retval none
*/
void exti_software_interrupt_disable(exti_line_enum linex)
{
EXTI_SWIEV(EXTI_REG_VAL(linex)) &= ~EXTI_BIT_POS(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..37): 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(EXTI_REG_VAL(linex)) & EXTI_BIT_POS(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..37): EXTI line x
\param[out] none
\retval none
*/
void exti_flag_clear(exti_line_enum linex)
{
EXTI_PD(EXTI_REG_VAL(linex)) = EXTI_BIT_POS(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..37): 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(EXTI_REG_VAL(linex)) & EXTI_BIT_POS(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..37): EXTI line x
\param[out] none
\retval none
*/
void exti_interrupt_flag_clear(exti_line_enum linex)
{
EXTI_PD(EXTI_REG_VAL(linex)) = EXTI_BIT_POS(linex);
}
@@ -0,0 +1,659 @@
/*!
\file gd32h7xx_fac.c
\brief FAC driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_fac.h"
#include <stdio.h>
/*!
\brief reset FAC peripheral
\param[in] none
\param[out] none
\retval none
*/
void fac_deinit(void)
{
rcu_periph_reset_enable(RCU_FACRST);
rcu_periph_reset_disable(RCU_FACRST);
}
/*!
\brief initialize the FAC filter parameter struct with the default values
\param[in] fac_parameter: fac parameter struct
\param[out] none
\retval none
*/
void fac_struct_para_init(fac_parameter_struct *fac_parameter)
{
fac_parameter->input_addr = 0U;
fac_parameter->input_size = 0U;
fac_parameter->input_threshold = 0U;
fac_parameter->coeff_addr = 0U;
fac_parameter->coeff_size = 0U;
fac_parameter->output_addr = 0U;
fac_parameter->output_size = 0U;
fac_parameter->output_threshold = 0U;
fac_parameter->clip = 0U;
fac_parameter->func = 0U;
fac_parameter->ipp = 0U;
fac_parameter->ipq = 0U;
fac_parameter->ipr = 0U;
}
/*!
\brief initialize the FAC fixed data preload parameter struct with the default values
\param[in] fac_parameter: fac parameter struct
\param[out] none
\retval none
*/
void fac_fixed_data_preload_init(fac_fixed_data_preload_struct *init_struct)
{
init_struct->coeffa_size = 0U;
init_struct->coeffa_ctx = 0U;
init_struct->coeffb_size = 0U;
init_struct->coeffb_ctx = 0U;
init_struct->input_size = 0U;
init_struct->input_ctx = 0U;
init_struct->output_size = 0U;
init_struct->output_ctx = 0U;
}
/*!
\brief initialize the FAC float data preload parameter struct with the default values
\param[in] fac_parameter: fac parameter struct
\param[out] none
\retval none
*/
void fac_float_data_preload_init(fac_float_data_preload_struct *init_struct)
{
init_struct->coeffa_size = 0U;
init_struct->coeffa_ctx = 0U;
init_struct->coeffb_size = 0U;
init_struct->coeffb_ctx = 0U;
init_struct->input_size = 0U;
init_struct->input_ctx = 0U;
init_struct->output_size = 0U;
init_struct->output_ctx = 0U;
}
/*!
\brief initialize the FAC peripheral
\param[in] init_struct: the data needed to initialize FAC
input_addr: x0 buffer base address, 0..255
input_size: x0 buffer size, 0..255
input_threshold: FAC_THRESHOLD_1, FAC_THRESHOLD_2,
FAC_THRESHOLD_4, FAC_THRESHOLD_8
coeff_addr: x1 buffer base address, 0..255
coeff_size: x1 buffer size, 0..255
output_addr: Y buffer base address, 0..255
output_size: Y buffer size, 0..255
output_threshold: FAC_THRESHOLD_1, FAC_THRESHOLD_2,
FAC_THRESHOLD_4, FAC_THRESHOLD_8
clip: enable or disable the clipping feature
ipp: value IPP (vector length, number of filter taps, etc.)
ipq: value IPQ (vector length, etc.)
ipr: value IPR (gain, etc.)
\param[out] none
\retval none
*/
void fac_init(fac_parameter_struct *fac_parameter)
{
/* FAC_X0BCFG: configure the input X0 buffer */
FAC_X0BCFG = ((((uint32_t)fac_parameter->input_addr) & FAC_X0BCFG_X0B_ADDR) | \
((((uint32_t)fac_parameter->input_size) << 8U) & FAC_X0BCFG_X0B_SIZE));
/* FAC_X0BCFG: configure the input X0 threshold */
FAC_X0BCFG |= (((uint32_t)fac_parameter->input_threshold) & FAC_X0BCFG_X0_WBFF);
/* FAC_X1BCFG: configure the coefficient X1 buffer */
FAC_X1BCFG = ((((uint32_t)fac_parameter->coeff_addr) & FAC_X1BCFG_X1B_ADDR) | \
((((uint32_t)fac_parameter->coeff_size) << 8U) & FAC_X1BCFG_X1B_SIZE));
/* FAC_YBCFG: configure the output Y buffer */
FAC_YBCFG = ((((uint32_t)fac_parameter->output_addr) & FAC_YBCFG_YB_ADDR) | \
((((uint32_t)fac_parameter->output_size) << 8U) & FAC_YBCFG_YB_SIZE));
/* FAC_YBCFG: configure the output Y threshold */
FAC_YBCFG |= (((uint32_t)fac_parameter->output_threshold) & FAC_YBCFG_Y_WBEF);
/* FAC_CTL: configure the state of clip */
FAC_CTL |= ((((uint32_t)fac_parameter->clip) << 15U) & FAC_CTL_CPEN);
}
/*!
\brief FAC preload X0 X1 Y fixed buffer
\param[in] init_struct: FAC preload init struct
coeffa_size: size of the coefficient vector A,0~255
coeffa_ctx: [IIR only] content of the coefficient vector A
coeffb_size: size of the coefficient vector B
coeffb_ctx: size of the coefficient vector B
input_size: size of the input data,0~255
input_ctx: content of the input data
output_size: size of the output data,0~255
output_ctx: content of the output data
only one parameter can be selected which is shown as below:
\arg PRELOAD_DMA_MODE: preload access buffer mode with dma
\arg PRELOAD_POLLING_MODE: preload access buffer mode with polling
\param[out] none
\retval none
*/
void fac_fixed_buffer_preload(fac_fixed_data_preload_struct *init_struct)
{
/* FAC_PARACFG: configure parameter of filter preload */
FAC_PARACFG = ((uint32_t)init_struct->input_size & FAC_PARACFG_IPP) | \
FUNC_LOAD_X0 | FAC_PARACFG_EXE;
/* load the X0 buffer for input data */
fac_fixed_data_preload(init_struct->input_size, init_struct->input_ctx);
/* configure dma for X0 preload */
/* FAC_PARACFG: configure parameter of filter preload */
FAC_PARACFG = (((uint32_t)init_struct->coeffb_size) & FAC_PARACFG_IPP) | \
((((uint32_t)init_struct->coeffa_size) << 8) & FAC_PARACFG_IPQ) | \
FUNC_LOAD_X1 | FAC_PARACFG_EXE;
/* load the x1 buffer for cofficientB */
fac_fixed_data_preload(init_struct->coeffb_size, (init_struct->coeffb_ctx));
/* load the x1 buffer for cofficientA */
if((NULL != init_struct->coeffa_ctx) && (0U != init_struct->coeffa_size)) {
/* Load the buffer into the internal memory */
fac_fixed_data_preload(init_struct->coeffa_size, (init_struct->coeffa_ctx));
}
/* if need configure to preload output buffer */
if((NULL != init_struct->output_ctx) && (0U != init_struct->output_size)) {
FAC_PARACFG = ((uint32_t)init_struct->output_size & FAC_PARACFG_IPP) | \
FUNC_LOAD_Y | FAC_PARACFG_EXE;
/* load the Y buffer for input data */
fac_fixed_data_preload(init_struct->output_size, init_struct->output_ctx);
}
}
/*!
\brief FAC preload X0 X1 Y float buffer
\param[in] init_struct: FAC preload init struct
coeffa_size: size of the coefficient vector A,0~255
coeffa_ctx: [IIR only] content of the coefficient vector A
coeffb_size: size of the coefficient vector B
coeffb_ctx: size of the coefficient vector B
input_size: size of the input data,0~255
input_ctx: content of the input data
output_size: size of the output data,0~255
output_ctx: content of the output data
only one parameter can be selected which is shown as below:
\arg PRELOAD_DMA_MODE: preload access buffer mode with dma
\arg PRELOAD_POLLING_MODE: preload access buffer mode with polling
\param[out] none
\retval none
*/
void fac_float_buffer_preload(fac_float_data_preload_struct *init_struct)
{
/* FAC_PARACFG: Config parameter of filter preload */
FAC_PARACFG = ((uint32_t)init_struct->input_size & FAC_PARACFG_IPP) | \
FUNC_LOAD_X0 | FAC_PARACFG_EXE;
/* load the x0 buffer for input data */
fac_float_data_preload(init_struct->input_size, init_struct->input_ctx);
/* configure dma for x0 preload */
/* FAC_PARACFG: Config parameter of filter preload */
FAC_PARACFG = (((uint32_t)init_struct->coeffb_size) & FAC_PARACFG_IPP) | \
((((uint32_t)init_struct->coeffa_size) << 8) & FAC_PARACFG_IPQ) | \
FUNC_LOAD_X1 | FAC_PARACFG_EXE;
/* load the x1 buffer for cofficientB */
fac_float_data_preload(init_struct->coeffb_size, (init_struct->coeffb_ctx));
/* load the x1 buffer for cofficientA */
if((NULL != init_struct->coeffa_ctx) && (0U != init_struct->coeffa_size)) {
/* load the buffer into the internal memory */
fac_float_data_preload(init_struct->coeffa_size, (init_struct->coeffa_ctx));
}
/* if need configure to preload output buffer */
if((NULL != init_struct->output_ctx) && (0U != init_struct->output_size)) {
FAC_PARACFG = ((uint32_t)init_struct->output_size & FAC_PARACFG_IPP) | \
FUNC_LOAD_Y | FAC_PARACFG_EXE;
/* load the Y buffer for input data */
fac_float_data_preload(init_struct->output_size, init_struct->output_ctx);
}
}
/*!
\brief FAC preload fixed data pointer
\param[in] array: 16-bit data
\param[in] size: size of data
\param[out] none
\retval none
*/
void fac_fixed_data_preload(uint8_t size, int16_t array[])
{
uint8_t i;
for(i = 0U; i < size; i++) {
FAC_WDATA = ((*((uint16_t*)&array[i])) & FAC_WDATA_WDATA);
}
}
/*!
\brief FAC preload float data pointer
\param[in] data: 32-bit data
\param[in] size: size of data
\param[out] none
\retval none
*/
void fac_float_data_preload(uint8_t size, float array[])
{
uint8_t i;
for(i = 0U; i < size; i++) {
FAC_WDATA = ((*((uint32_t*) & array[i])));
}
}
/*!
\brief FAC reset write and read pointers. the internal control logic,FAC_STAT register and the FAC_PARACFG register is reset
\param[in] none
\param[out] none
\retval none
*/
void fac_reset(void)
{
FAC_CTL |= FAC_CTL_RST;
}
/*!
\brief configure the FAC clip feature
\param[in] cpmod: the state of clip
only one parameter can be selected which is shown as below:
\arg FAC_CP_ENABLE: ENABLE CLIP
\arg FAC_CP_DISABLE: DISABLE CLIP
\param[out] none
\retval none
*/
void fac_clip_config(uint8_t cpmod)
{
if(FAC_CP_ENABLE == cpmod) {
FAC_CTL |= FAC_CTL_CPEN;
} else {
FAC_CTL &= ~(FAC_CTL_CPEN);
}
}
/*!
\brief enable FAC float point format
\param[in] none
\param[out] none
\retval none
*/
void fac_float_enable(void)
{
FAC_CTL |= FAC_CTL_FLTEN;
}
/*!
\brief disable FAC float point format
\param[in] none
\param[out] none
\retval none
*/
void fac_float_disable(void)
{
FAC_CTL &= ~FAC_CTL_FLTEN;
}
/*!
\brief enable the FAC DMA
\param[in] dma_req: dma transfer type
only one parameter can be selected which is shown as below:
\arg FAC_DMA_READ: read buffer dma
\arg FAC_DMA_WRITE: write buffer dma
\param[out] none
\retval none
*/
void fac_dma_enable(uint32_t dma_req)
{
FAC_CTL |= dma_req;
}
/*!
\brief disable the FAC DMA
\param[in] dma_req: dma transfer type
only one parameter can be selected which is shown as below:
\arg FAC_DMA_READ: read buffer dma
\arg FAC_DMA_WRITE: write buffer dma
\param[out] none
\retval none
*/
void fac_dma_disable(uint32_t dma_req)
{
FAC_CTL &= ~dma_req;
}
/*!
\brief FAC configure input buffer
\param[in] watermark: threshold of input buffer
FAC_THRESHOLD_1, FAC_THRESHOLD_2,
FAC_THRESHOLD_4, FAC_THRESHOLD_8
\param[in] baseaddr: base address of input buffer, 0..255
\param[in] bufsize: buffer size of input buffer, 0..255
\param[out] none
\retval none
*/
void fac_x0_config(uint32_t watermark, uint8_t baseaddr, uint8_t bufsize)
{
/* set base address */
FAC_X0BCFG &= ~FAC_X0BCFG_X0B_ADDR;
FAC_X0BCFG |= ((uint32_t)baseaddr);
/* set buffer size */
FAC_X0BCFG &= ~FAC_X0BCFG_X0B_SIZE;
FAC_X0BCFG |= (((uint32_t)bufsize) << 8U);
/* set watermark */
FAC_X0BCFG &= ~FAC_X0BCFG_X0_WBFF;
FAC_X0BCFG |= watermark;
}
/*!
\brief FAC configure coefficient buffer
\param[in] baseaddr: base address of coefficient buffer, 0..255
\param[in] bufsize: buffer size of coefficient buffer, 0..255
\param[out] none
\retval none
*/
void fac_x1_config(uint8_t baseaddr, uint8_t bufsize)
{
/* set base address */
FAC_X1BCFG &= ~FAC_X1BCFG_X1B_ADDR;
FAC_X1BCFG |= ((uint32_t)baseaddr);
/* set buffer size */
FAC_X1BCFG &= ~FAC_X1BCFG_X1B_SIZE;
FAC_X1BCFG |= (((uint32_t)bufsize) << 8U);
}
/*!
\brief FAC configure output buffer
\param[in] watermark: threshold of output buffer
FAC_THRESHOLD_1, FAC_THRESHOLD_2,
FAC_THRESHOLD_4, FAC_THRESHOLD_8
\param[in] baseaddr: base address of output buffer, 0..255
\param[in] bufsize: buffer size of output buffer, 0..255
\param[out] none
\retval none
*/
void fac_y_config(uint32_t watermark, uint8_t baseaddr, uint8_t bufsize)
{
/* set base address */
FAC_YBCFG &= ~FAC_YBCFG_YB_ADDR;
FAC_YBCFG |= ((uint32_t)baseaddr);
/* set buffer size */
FAC_YBCFG &= ~FAC_YBCFG_YB_SIZE;
FAC_YBCFG |= (((uint32_t)bufsize) << 8U);
/* set watermark */
FAC_YBCFG &= ~FAC_YBCFG_Y_WBEF;
FAC_YBCFG |= watermark;
}
/*!
\brief FAC configure execute function
\param[in] func: select function to excute
FUNC_CONVO_FIR, FUNC_IIR_DIRECT_FORM_1
\param[in] ipp: parameter of forward coefficient, 2..64
\param[in] ipq: parameter of backward coefficient, 1..63
\param[in] ipr: parameter of gain, 0..7
\param[out] none
\retval none
*/
void fac_function_config(fac_parameter_struct *fac_parameter)
{
/* set function */
FAC_PARACFG &= ~FAC_PARACFG_FUN;
FAC_PARACFG |= fac_parameter->func;
/* set filter parameter */
FAC_PARACFG &= ~(FAC_PARACFG_IPP | FAC_PARACFG_IPQ | FAC_PARACFG_IPR);
FAC_PARACFG |= ((uint32_t)fac_parameter->ipp) | (((uint32_t)fac_parameter->ipq) << 8U) | (((uint32_t)fac_parameter->ipr) << 16U);
}
/*!
\brief start the fac
\param[in] none
\param[out] none
\retval none
*/
void fac_start(void)
{
/* set start */
FAC_PARACFG |= FAC_PARACFG_EXE;
}
/*!
\brief stop the fac
\param[in] none
\param[out] none
\retval none
*/
void fac_stop(void)
{
/* set start */
FAC_PARACFG &= ~FAC_PARACFG_EXE;
}
/*!
\brief finish the filter calculate
\param[in] none
\param[out] none
\retval none
*/
void fac_finish_calculate(void)
{
/* clear execute */
FAC_PARACFG &= ~FAC_PARACFG_EXE;
/* disable read and write interrupt */
fac_interrupt_disable(FAC_CTL_RIE | FAC_CTL_WIE);
/* disable read and write dma */
fac_dma_disable(FAC_DMA_READ);
fac_dma_disable(FAC_DMA_WRITE);
/* reset register and pointer */
FAC_CTL |= FAC_CTL_RST;
}
/*!
\brief FAC write data with fixed ponit format
\param[in] data: 16-bit data
\param[out] none
\retval none
*/
void fac_fixed_data_write(int16_t data)
{
FAC_WDATA_INT = (int16_t)data;
}
/*!
\brief FAC read data with fixed point format
\param[in] none
\param[out] none
\retval 16-bit data
*/
int16_t fac_fixed_data_read(void)
{ int16_t value;
value = (int16_t)FAC_RDATA_INT;
return value;
}
/*!
\brief FAC write data with float ponit format
\param[in] data: 16-bit data
\param[out] none
\retval none
*/
void fac_float_data_write(float data)
{
FAC_WDATA_FLOAT = (float)data;
}
/*!
\brief FAC read data with fixed point format
\param[in] none
\param[out] none
\retval 16-bit data
*/
float fac_float_data_read(void)
{
float value;
value = (float)FAC_RDATA_FLOAT;
return value;
}
/*!
\brief enable the FAC Interrupt
\param[in] interrupt: FAC Interrupt
only one parameter can be selected which is shown as below:
\arg FAC_CTL_RIE: Read buffer interrupt
\arg FAC_CTL_WIE: Write buffer interrupt
\arg FAC_CTL_OFEIE: Overflow error interrupt
\arg FAC_CTL_UFEIE: Underflow error interrupt
\arg FAC_CTL_STEIE: Saturation error interrupt
\arg FAC_CTL_GSTEIE: gain saturation error interrupt
\param[out] none
\retval none
*/
void fac_interrupt_enable(uint32_t interrupt)
{
FAC_CTL |= interrupt;
}
/*!
\brief disable the FAC Interrupt
\param[in] interrupt: FAC Interrupt
only one parameter can be selected which is shown as below:
\arg FAC_CTL_RIE: Read buffer interrupt
\arg FAC_CTL_WIE: Write buffer interrupt
\arg FAC_CTL_OFEIE: Overflow error interrupt
\arg FAC_CTL_UFEIE: Underflow error interrupt
\arg FAC_CTL_STEIE: Saturation error interrupt
\arg FAC_CTL_GSTEIE: gain saturation error interrupt
\param[out] none
\retval none
*/
void fac_interrupt_disable(uint32_t interrupt)
{
FAC_CTL &= ~interrupt;
}
/*!
\brief get FAC interrupt flag status
\param[in] interrupt: FAC interrupt flag status
only one parameter can be selected which is shown as below:
\arg FAC_INT_FLAG_YBEF: Y buffer read interrupt flag
\arg FAC_INT_FLAG_X0BFF: X0 buffer write interrupt flag
\arg FAC_INT_FLAG_OFEF: overflow error interrupt flag
\arg FAC_INT_FLAG_UFEF: underflow error interrupt flag
\arg FAC_INT_FLAG_STEF: saturation error interrupt flag
\arg FAC_INT_FLAG_GSTEF: gain saturation error interrupt flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus fac_interrupt_flag_get(uint8_t interrupt)
{
uint32_t reg1 = FAC_CTL;
uint32_t reg2 = FAC_STAT;
switch(interrupt) {
/* Y buffer read interrupt */
case FAC_INT_FLAG_YBEF:
reg1 = reg1 & FAC_CTL_RIE;
reg2 = (((reg2 & FAC_STAT_YBEF) == 0U)?FAC_STAT_YBEF:0U);
break;
/* X0 buffer write interrupt */
case FAC_INT_FLAG_X0BFF:
reg1 = reg1 & FAC_CTL_WIE;
reg2 = (((reg2 & FAC_STAT_X0BFF) == 0U)?FAC_STAT_X0BFF:0U);
break;
/* overflow error interrupt */
case FAC_INT_FLAG_OFEF:
reg1 = reg1 & FAC_CTL_OFEIE;
reg2 = reg2 & FAC_STAT_OFEF;
break;
/* underflow error interrupt */
case FAC_INT_FLAG_UFEF:
reg1 = reg1 & FAC_CTL_UFEIE;
reg2 = reg2 & FAC_STAT_UFEF;
break;
/* saturation error interrupt */
case FAC_INT_FLAG_STEF:
reg1 = reg1 & FAC_CTL_STEIE;
reg2 = reg2 & FAC_STAT_STEF;
break;
/* saturation error interrupt */
case FAC_INT_FLAG_GSTEF:
reg1 = reg1 & FAC_CTL_GSTEIE;
reg2 = reg2 & FAC_STAT_GSTEF;
break;
default :
break;
}
/*get FAC interrupt flag status */
if(reg1 && reg2) {
return SET;
} else {
return RESET;
}
}
/*!
\brief get FAC flag status
\param[in] flag: FAC flag status
only one parameter can be selected which is shown as below:
\arg FAC_FLAG_YBEF: Y buffer empty flag
\arg FAC_FLAG_X0BFF: X0 buffer full flag
\arg FAC_FLAG_OFEF: overflow error flag
\arg FAC_FLAG_UFEF: underflow error flag
\arg FAC_FLAG_STEF: saturation error flag
\arg FAC_FLAG_GSTEF: gain saturation error flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus fac_flag_get(uint32_t flag)
{
if(FAC_STAT & flag) {
return SET;
} else {
return RESET;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,250 @@
/*!
\file gd32h7xx_fwdgt.c
\brief FWDGT driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_fwdgt.h"
/* write value to FWDGT_CTL_CMD bit field */
#define CTL_CMD(regval) (BITS(0,15) & ((uint32_t)(regval) << 0U))
/* write value to FWDGT_RLD_RLD bit field */
#define RLD_RLD(regval) (BITS(0,11) & ((uint32_t)(regval) << 0U))
/* write value to FWDGT_WND_WND bit field */
#define WND_WND(regval) (BITS(0,11) & ((uint32_t)(regval) << 0U))
/*!
\brief enable write access to FWDGT_PSC, 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 FWDGT counter
\param[in] none
\param[out] none
\retval none
*/
void fwdgt_enable(void)
{
FWDGT_CTL = FWDGT_KEY_ENABLE;
}
/*!
\brief configure the FWDGT 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 > (uint32_t)0x00000000U) && (RESET != flag_status));
if(RESET != flag_status){
return ERROR;
}
/* configure FWDGT */
FWDGT_PSC = (uint32_t)prescaler_value;
return SUCCESS;
}
/*!
\brief configure the FWDGT 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 > (uint32_t)0x00000000U) && ((uint32_t)RESET != flag_status));
if ((uint32_t)RESET != flag_status){
return ERROR;
}
FWDGT_RLD = RLD_RLD(reload_value);
return SUCCESS;
}
/*!
\brief configure the FWDGT 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 > (uint32_t)0x00000000U) && ((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 > (uint32_t)0x00000000U) && ((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 > (uint32_t)0x00000000U) && ((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;
}
@@ -0,0 +1,492 @@
/*!
\file gd32h7xx_gpio.c
\brief GPIO driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_gpio.h"
/*!
\brief reset GPIO port
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G,H,J,K)
only one parameter can be selected which is shown as below:
\arg GPIOx(x = A,B,C,D,E,F,G,H,J,K)
\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 GPIOD:
/* reset GPIOD */
rcu_periph_reset_enable(RCU_GPIODRST);
rcu_periph_reset_disable(RCU_GPIODRST);
break;
case GPIOE:
/* reset GPIOE */
rcu_periph_reset_enable(RCU_GPIOERST);
rcu_periph_reset_disable(RCU_GPIOERST);
break;
case GPIOF:
/* reset GPIOF */
rcu_periph_reset_enable(RCU_GPIOFRST);
rcu_periph_reset_disable(RCU_GPIOFRST);
break;
case GPIOG:
/* reset GPIOG */
rcu_periph_reset_enable(RCU_GPIOGRST);
rcu_periph_reset_disable(RCU_GPIOGRST);
break;
case GPIOH:
/* reset GPIOH */
rcu_periph_reset_enable(RCU_GPIOHRST);
rcu_periph_reset_disable(RCU_GPIOHRST);
break;
case GPIOJ:
/* reset GPIOJ */
rcu_periph_reset_enable(RCU_GPIOJRST);
rcu_periph_reset_disable(RCU_GPIOJRST);
break;
case GPIOK:
/* reset GPIOK */
rcu_periph_reset_enable(RCU_GPIOKRST);
rcu_periph_reset_disable(RCU_GPIOKRST);
break;
default:
break;
}
}
/*!
\brief set GPIO mode
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G,H,J,K)
only one parameter can be selected which is shown as below:
\arg GPIOx(x = A,B,C,D,E,F,G,H,J,K)
\param[in] mode: gpio pin mode
only one parameter can be selected which is shown as below:
\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
only one parameter can be selected which is shown as below:
\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,D,E,F,G,H,J,K)
only one parameter can be selected which is shown as below:
\arg GPIOx(x = A,B,C,D,E,F,G,H,J,K)
\param[in] otype: gpio pin output mode
only one parameter can be selected which is shown as below:
\arg GPIO_OTYPE_PP: push pull mode
\arg GPIO_OTYPE_OD: open drain mode
\param[in] speed: gpio pin output max speed
only one parameter can be selected which is shown as below:
\arg GPIO_OSPEED_12MHZ: output max speed 12MHz
\arg GPIO_OSPEED_60MHZ: output max speed 60MHz
\arg GPIO_OSPEED_85MHZ: output max speed 85MHz
\arg GPIO_OSPEED_100_220MHZ: output max speed 100/220MHz
\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,D,E,F,G,H,J,K)
only one parameter can be selected which is shown as below:
\arg GPIOx(x = A,B,C,D,E,F,G,H,J,K)
\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,D,E,F,G,H,J,K)
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,D,E,F,G,H,J,K)
only one parameter can be selected which is shown as below:
\arg GPIOx(x = A,B,C,D,E,F,G,H,J,K)
\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
only one parameter can be selected which is shown as below:
\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,D,E,F,G,H,J,K)
only one parameter can be selected which is shown as below:
\arg GPIOx(x = A,B,C,D,E,F,G,H,J,K)
\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 set GPIO input filter
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G,H,J,K)
only one parameter can be selected which is shown as below:
\arg GPIOx(x = A,B,C,D,E,F,G,H,J,K)
\param[in] speriod: gpio pin input sample period
only one parameter can be selected which is shown as below:
\arg GPIO_ISPERIOD(x): x = 0 ~ 255
\param[in] iftype: gpio pin input filtering type
only one parameter can be selected which is shown as below:
\arg GPIO_IFTYPE_SYNC: input filter type synchronization
\arg GPIO_IFTYPE_3_SAMPLE: input filter type filter 3 samples
\arg GPIO_IFTYPE_6_SAMPLE: input filter type filter 6 samples
\arg GPIO_IFTYPE_ASYNC: input filter type asynchronous
\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_input_filter_set(uint32_t gpio_periph, uint8_t speriod, uint32_t iftype, uint32_t pin)
{
uint16_t i;
uint32_t isperiod;
uint32_t iftp;
isperiod = GPIO_IFL(gpio_periph);
if(pin & 0x000000FFU){
isperiod &= ~GPIO_IFL_FLPRD0;
isperiod |= (uint32_t)speriod;
}
if(pin & 0x0000FF00U){
isperiod &= ~GPIO_IFL_FLPRD1;
isperiod |= ((uint32_t)speriod << 8U);
}
GPIO_IFL(gpio_periph) = isperiod;
/* get the specified pin output speed bits value */
iftp = GPIO_IFTP(gpio_periph);
for(i = 0U;i < 16U;i++){
if((1U << i) & pin){
/* clear the specified pin output speed bits */
iftp &= ~GPIO_IFTYPE_MASK(i);
/* set the specified pin output speed bits */
iftp |= GPIO_IFTYPE_SET(i,iftype);
}
}
GPIO_IFTP(gpio_periph) = iftp;
}
/*!
\brief get GPIO pin input status
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G,H,J,K)
only one parameter can be selected which is shown as below:
\arg GPIOx(x = A,B,C,D,E,F,G,H,J,K)
\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 port input status
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G,H,J,K)
only one parameter can be selected which is shown as below:
\arg GPIOx(x = A,B,C,D,E,F,G,H,J,K)
\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,D,E,F,G,H,J,K)
only one parameter can be selected which is shown as below:
\arg GPIOx(x = A,B,C,D,E,F,G,H,J,K)
\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 port output status
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G,H,J,K)
only one parameter can be selected which is shown as below:
\arg GPIOx(x = A,B,C,D,E,F,G,H,J,K)
\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,D,E,F,G,H,J,K)
only one parameter can be selected which is shown as below:
\arg GPIOx(x = A,B,C,D,E,F,G,H,J,K)
\param[in] alt_func_num: GPIO pin af function, please refer to specific device datasheet
only one parameter can be selected which is shown as below:
\arg GPIO_AF_0: SYSTEM, TIMER40, TIMER41, TIMER42, TIMER43, TIMER44
\arg GPIO_AF_1: TIMER0, TIMER1, TIMER15, TIMER16, EXMC, SAI1, SAI2
\arg GPIO_AF_2: TIMER2, TIMER3, TIMER4, TIMER7, TIMER14, TLI, CAN2, SAI0, EXMC
\arg GPIO_AF_3: TIMER7, TIMER9, EDOUT, EXMC, TLI, HPDF, OSPIM
\arg GPIO_AF_4: TIMER14, TIMER30, TIMER31, I2C0, I2C1, I2C2, I2C3, USART0, HPDF, OSPIM, TLI
\arg GPIO_AF_5: SPI0, SPI1, SPI2, SPI3, SPI4, SPI5, CAN2
\arg GPIO_AF_6: UART3, SPI2, I2C3, HPDF, SAI0, ETH1, EDOUT, OSPIM
\arg GPIO_AF_7: USART0, USART1, USART2, USART5, UART6, TIMER40, TIMER41, TIMER42, TIMER43,
SPI1, SPI2, SPI5, SDIO0, USBHS1
\arg GPIO_AF_8: UART3, UART4, UART7, SPI5, SDIO0, RSPDIF, TIMER44, USBHS1, SAI1, SAI2
\arg GPIO_AF_9: SDIO1, TRGSEL, CAN0, CAN1, TLI, OPSIM, EXMC, RSPDIF, SAI2
\arg GPIO_AF_10: SAI1, SAI2, SDIO1, CMP, USBHS0, OPSIM, EXMC
\arg GPIO_AF_11: ETH0, MDIO, CMP, UART6, EXMC, HPDF, I2C3, TLI, SDIO1, OPSIM
\arg GPIO_AF_12: TIMER0, MDIOS, SDIO0, EXMC, OPSIM, CMP, TLI, USBHS1
\arg GPIO_AF_13: TRGSEL, DCI, COMP0, CMP, TIMER22
\arg GPIO_AF_14: TLI, UART4, TIMER23
\arg GPIO_AF_15: EVENTOUT
\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,C,D,E,F,G,H,J,K)
only one parameter can be selected which is shown as below:
\arg GPIOx(x = A,B,C,D,E,F,G,H,J,K)
\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,D,E,F,G,H,J,K)
only one parameter can be selected which is shown as below:
\arg GPIOx(x = A,B,C,D,E,F,G,H,J,K)
\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,D,E,F,G,H,J,K)
only one parameter can be selected which is shown as below:
\arg GPIOx(x = A,B,C,D,E,F,G,H,J,K)
\param[out] none
\retval none
*/
void gpio_port_toggle(uint32_t gpio_periph)
{
GPIO_TG(gpio_periph) = 0x0000FFFFU;
}
@@ -0,0 +1,398 @@
/*!
\file gd32h7xx_hau.c
\brief HAU driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_hau.h"
#include "gd32h7xx_rcu.h"
#define HASH_CONTEXT_INTERNAL_REG 37U
#define HMAC_CONTEXT_INTERNAL_REG 53U
/*!
\brief reset the HAU peripheral
\param[in] none
\param[out] none
\retval none
*/
void hau_deinit(void)
{
/* enable HAU reset state */
rcu_periph_reset_enable(RCU_HAURST);
/* release HAU from reset state */
rcu_periph_reset_disable(RCU_HAURST);
}
/*!
\brief initialize the HAU peripheral parameters
\param[in] initpara: HAU init parameter struct
members of the structure and the member values are shown as below:
algo: HAU_ALGO_SHA1, HAU_ALGO_SHA224, HAU_ALGO_SHA256, HAU_ALGO_MD5
mode: HAU_MODE_HASH, HAU_MODE_HMAC
datatype: HAU_SWAPPING_32BIT, HAU_SWAPPING_16BIT, HAU_SWAPPING_8BIT, HAU_SWAPPING_1BIT
keytype: HAU_KEY_SHORTER_64, HAU_KEY_LONGGER_64
\param[out] none
\retval none
*/
void hau_init(hau_init_parameter_struct* initpara)
{
/* configure the algorithm, mode and the data type */
HAU_CTL &= (~(uint32_t)(HAU_CTL_ALGM_0 | HAU_CTL_ALGM_1 | HAU_CTL_DATAM | HAU_CTL_HMS));
HAU_CTL |= (initpara->algo | initpara->datatype | initpara->mode);
/* when mode is HMAC, set the key */
if(HAU_MODE_HMAC == initpara->mode){
HAU_CTL &= (~(uint32_t)HAU_CTL_KLM);
HAU_CTL |= initpara->keytype;
}
/* start the digest of a new message */
HAU_CTL |= HAU_CTL_START;
}
/*!
\brief initialize the structure hau_initpara with default value
\param[in] none
\param[out] initpara: HAU init parameter struct
\retval none
*/
void hau_init_struct_para_init(hau_init_parameter_struct* initpara)
{
initpara->algo = HAU_ALGO_SHA1;
initpara->mode = HAU_MODE_HASH;
initpara->datatype = HAU_SWAPPING_32BIT;
initpara->keytype = HAU_KEY_SHORTER_64;
}
/*!
\brief reset the HAU processor core
\param[in] none
\param[out] none
\retval none
*/
void hau_reset(void)
{
/* set to 1 to reset the HAU processor core, then it is ready to start the digest calculation */
HAU_CTL |= HAU_CTL_START;
}
/*!
\brief configure the number of valid bits in last word of the message
\param[in] valid_num: number of valid bits in last word of the message
only one parameter can be selected which is shown as below:
\arg 0x00: all 32 bits of the last data written are valid
\arg 0x01: only bit [31] of the last data written to HAU_DI after data swapping are valid
\arg 0x02: only bits [31:30] of the last data written to HAU_DI after data swapping are valid
\arg 0x03: only bits [31:29] of the last data written to HAU_DI after data swapping are valid
...
\arg 0x1F: only bits [31:1] of the last data written to HAU_DI after data swapping are valid
\param[out] none
\retval none
*/
void hau_last_word_validbits_num_config(uint32_t valid_num)
{
HAU_CFG &= (~(uint32_t)HAU_CFG_VBL);
HAU_CFG |= CFG_VBL(valid_num);
}
/*!
\brief write data to the IN FIFO
\param[in] data: data to write
\param[out] none
\retval none
*/
void hau_data_write(uint32_t data)
{
HAU_DI = data;
}
/*!
\brief return the number of words already written into the IN FIFO
\param[in] none
\param[out] none
\retval number of words in the input FIFO
*/
uint32_t hau_infifo_words_num_get(void)
{
uint32_t ret = 0U;
ret = GET_CTL_NWIF(HAU_CTL);
return ret;
}
/*!
\brief read the message digest result
\param[in] none
\param[out] digestpara: HAU digest parameter struct
out[x](x = 0...7): message digest result 0-7
\retval none
*/
void hau_digest_read(hau_digest_parameter_struct* digestpara)
{
digestpara->out[0] = HAU_DO0;
digestpara->out[1] = HAU_DO1;
digestpara->out[2] = HAU_DO2;
digestpara->out[3] = HAU_DO3;
digestpara->out[4] = HAU_DO4;
digestpara->out[5] = HAU_DO5;
digestpara->out[6] = HAU_DO6;
digestpara->out[7] = HAU_DO7;
}
/*!
\brief enable digest calculation
\param[in] none
\param[out] none
\retval none
*/
void hau_digest_calculation_enable(void)
{
HAU_CFG |= HAU_CFG_CALEN;
}
/*!
\brief configure single or multiple DMA is used, and digest calculation at the end of a DMA transfer or not
\param[in] multi_single
only one parameter can be selected which is shown as below:
\arg SINGLE_DMA_AUTO_DIGEST: message padding and message digest calculation at the end of a DMA transfer
\arg MULTIPLE_DMA_NO_DIGEST: multiple DMA transfers needed and CALEN bit is not automatically set at the end of a DMA transfer
\param[out] none
\retval none
*/
void hau_multiple_single_dma_config(uint32_t multi_single)
{
HAU_CTL &= (~(uint32_t)HAU_CTL_MDS);
HAU_CTL |= multi_single;
}
/*!
\brief enable the HAU DMA interface
\param[in] none
\param[out] none
\retval none
*/
void hau_dma_enable(void)
{
HAU_CTL |= HAU_CTL_DMAE;
}
/*!
\brief disable the HAU DMA interface
\param[in] none
\param[out] none
\retval none
*/
void hau_dma_disable(void)
{
HAU_CTL &= (~(uint32_t)HAU_CTL_DMAE);
}
/*!
\brief initialize the struct context
\param[in] none
\param[out] context: HAU context parameter struct
\retval none
*/
void hau_context_struct_para_init(hau_context_parameter_struct* context)
{
uint8_t i = 0U;
/* initialize context parameter struct */
context->hau_inten_bak = 0U;
context->hau_cfg_bak = 0U;
context->hau_ctl_bak = 0U;
for(i = 0U; i <= HMAC_CONTEXT_INTERNAL_REG; i++){
context->hau_ctxs_bak[i] = 0U;
}
}
/*!
\brief save the HAU peripheral context
\param[in] none
\param[out] context_save: pointer to a hau_context structure that contains the repository for current context
\retval none
*/
void hau_context_save(hau_context_parameter_struct* context_save)
{
uint8_t i = 0U;
uint8_t i_max = HASH_CONTEXT_INTERNAL_REG;
hau_context_struct_para_init(context_save);
/* save context registers */
context_save->hau_inten_bak = HAU_INTEN;
context_save->hau_cfg_bak = HAU_CFG;
context_save->hau_ctl_bak = HAU_CTL;
if(0U != (HAU_CTL & HAU_CTL_HMS)){
i_max = HMAC_CONTEXT_INTERNAL_REG;
}
for(i = 0U; i <= i_max; i++){
context_save->hau_ctxs_bak[i] = HAU_CTXS(i);
}
}
/*!
\brief restore the HAU peripheral context
\param[in] context_restore: pointer to a hau_context_parameter_struct structure that contains the repository for saved context
\param[out] none
\retval none
*/
void hau_context_restore(hau_context_parameter_struct* context_restore)
{
uint8_t i = 0U;
uint8_t i_max = HASH_CONTEXT_INTERNAL_REG;
/* restore context registers */
HAU_INTEN = context_restore->hau_inten_bak;
HAU_CFG = context_restore->hau_cfg_bak;
HAU_CTL = context_restore->hau_ctl_bak;
/* Initialize the hash processor */
HAU_CTL |= HAU_CTL_START;
/* continue restoring context registers */
if(0U != (HAU_CTL & HAU_CTL_HMS)){
i_max = HMAC_CONTEXT_INTERNAL_REG;
}
for(i = 0U; i <= i_max; i++){
HAU_CTXS(i) = context_restore->hau_ctxs_bak[i];
}
}
/*!
\brief get the HAU flag status
\param[in] flag: HAU flag status
only one parameter can be selected which is shown as below:
\arg HAU_FLAG_DATA_INPUT: there is enough space (16 bytes) in the input FIFO
\arg HAU_FLAG_CALCULATION_COMPLETE: digest calculation is completed
\arg HAU_FLAG_DMA: DMA is enabled (DMAE =1) or a transfer is processing
\arg HAU_FLAG_BUSY: data block is in process
\arg HAU_FLAG_INFIFO_NO_EMPTY: the input FIFO is not empty
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus hau_flag_get(uint32_t flag)
{
uint32_t ret = 0U;
FlagStatus ret_flag = RESET;
/* check if the flag is in HAU_CTL register */
if(RESET != (flag & HAU_FLAG_INFIFO_NO_EMPTY)){
ret = HAU_CTL;
}else{
ret = HAU_STAT;
}
if (RESET != (ret & flag)){
ret_flag = SET;
}
return ret_flag;
}
/*!
\brief clear the HAU flag status
\param[in] flag: HAU flag status
one or more parameters can be selected which are shown as below:
\arg HAU_FLAG_DATA_INPUT: there is enough space (16 bytes) in the input FIFO
\arg HAU_FLAG_CALCULATION_COMPLETE: digest calculation is completed
\param[out] none
\retval none
*/
void hau_flag_clear(uint32_t flag)
{
HAU_STAT = ~(uint32_t)(flag);
}
/*!
\brief enable the HAU interrupts
\param[in] interrupt: specify the HAU interrupt source to be enabled
one or more parameters can be selected which are shown as below:
\arg HAU_INT_DATA_INPUT: a new block can be entered into the IN buffer
\arg HAU_INT_CALCULATION_COMPLETE: calculation complete
\param[out] none
\retval none
*/
void hau_interrupt_enable(uint32_t interrupt)
{
HAU_INTEN |= interrupt;
}
/*!
\brief disable the HAU interrupts
\param[in] interrupt: specify the HAU interrupt source to be disabled
one or more parameters can be selected which are shown as below:
\arg HAU_INT_DATA_INPUT: a new block can be entered into the IN buffer
\arg HAU_INT_CALCULATION_COMPLETE: calculation complete
\param[out] none
\retval none
*/
void hau_interrupt_disable(uint32_t interrupt)
{
HAU_INTEN &= ~(uint32_t)(interrupt);
}
/*!
\brief get the HAU interrupt flag status
\param[in] int_flag: HAU interrupt flag status
only one parameter can be selected which is shown as below:
\arg HAU_INT_FLAG_DATA_INPUT: there is enough space (16 bytes) in the input FIFO
\arg HAU_INT_FLAG_CALCULATION_COMPLETE: digest calculation is completed
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus hau_interrupt_flag_get(uint32_t int_flag)
{
uint32_t ret = 0U;
FlagStatus flag = RESET;
/* return the status of the interrupt */
ret = HAU_STAT;
if(RESET != ((HAU_INTEN & ret) & int_flag)){
flag = SET;
}
return flag;
}
/*!
\brief clear the HAU interrupt flag status
\param[in] int_flag: HAU interrupt flag status
one or more parameters can be selected which are shown as below:
\arg HAU_INT_FLAG_DATA_INPUT: there is enough space (16 bytes) in the input FIFO
\arg HAU_INT_FLAG_CALCULATION_COMPLETE: digest calculation is completed
\param[out] none
\retval none
*/
void hau_interrupt_flag_clear(uint32_t int_flag)
{
HAU_STAT = ~(uint32_t)(int_flag);
}
@@ -0,0 +1,422 @@
/*!
\file gd32h7xx_hau_sha_md5.c
\brief HAU_SHA_MD5 driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_hau.h"
#define SHAMD5_BSY_TIMEOUT ((uint32_t)0x00010000U)
/* HAU SHA/MD5 digest read in HASH mode */
static void hau_sha_md5_digest_read(uint32_t algo, uint8_t output[]);
/* HAU digest calculate process in HASH mode */
static ErrStatus hau_hash_calculate(uint32_t algo, uint8_t input[], uint32_t in_length, uint8_t output[]);
/* HAU digest calculate process in HMAC mode */
static ErrStatus hau_hmac_calculate(uint32_t algo, uint8_t key[], uint32_t keysize, uint8_t input[], uint32_t in_length, uint8_t output[]);
/*!
\brief calculate digest using SHA1 in HASH mode
\param[in] input: pointer to the input buffer
\param[in] in_length: length of the input buffer
\param[out] output: the result digest
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus hau_hash_sha_1(uint8_t input[], uint32_t in_length, uint8_t output[])
{
ErrStatus ret = ERROR;
ret = hau_hash_calculate(HAU_ALGO_SHA1, input, in_length, output);
return ret;
}
/*!
\brief calculate digest using SHA1 in HMAC mode
\param[in] key: pointer to the key used for HMAC
\param[in] keysize: length of the key used for HMAC
\param[in] input: pointer to the input buffer
\param[in] in_length: length of the input buffer
\param[out] output: the result digest
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus hau_hmac_sha_1(uint8_t key[], uint32_t keysize, uint8_t input[], uint32_t in_length, uint8_t output[])
{
ErrStatus ret = ERROR;
ret = hau_hmac_calculate(HAU_ALGO_SHA1, key, keysize, input, in_length, output);
return ret;
}
/*!
\brief calculate digest using SHA224 in HASH mode
\param[in] input: pointer to the input buffer
\param[in] in_length: length of the input buffer
\param[out] output: the result digest
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus hau_hash_sha_224(uint8_t input[], uint32_t in_length, uint8_t output[])
{
ErrStatus ret = ERROR;
ret = hau_hash_calculate(HAU_ALGO_SHA224, input, in_length, output);
return ret;
}
/*!
\brief calculate digest using SHA224 in HMAC mode
\param[in] key: pointer to the key used for HMAC
\param[in] keysize: length of the key used for HMAC
\param[in] input: pointer to the input buffer
\param[in] in_length: length of the input buffer
\param[out] output: the result digest
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus hau_hmac_sha_224(uint8_t key[], uint32_t keysize, uint8_t input[], uint32_t in_length, uint8_t output[])
{
ErrStatus ret = ERROR;
ret = hau_hmac_calculate(HAU_ALGO_SHA224, key, keysize, input, in_length, output);
return ret;
}
/*!
\brief calculate digest using SHA256 in HASH mode
\param[in] input: pointer to the input buffer
\param[in] in_length: length of the input buffer
\param[out] output: the result digest
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus hau_hash_sha_256(uint8_t input[], uint32_t in_length, uint8_t output[])
{
ErrStatus ret = ERROR;
ret = hau_hash_calculate(HAU_ALGO_SHA256, input, in_length, output);
return ret;
}
/*!
\brief calculate digest using SHA256 in HMAC mode
\param[in] key: pointer to the key used for HMAC
\param[in] keysize: length of the key used for HMAC
\param[in] input: pointer to the input buffer
\param[in] in_length: length of the input buffer
\param[out] output: the result digest
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus hau_hmac_sha_256(uint8_t key[], uint32_t keysize, uint8_t input[], uint32_t in_length, uint8_t output[])
{
ErrStatus ret = ERROR;
ret = hau_hmac_calculate(HAU_ALGO_SHA256, key, keysize, input, in_length, output);
return ret;
}
/*!
\brief calculate digest using MD5 in HASH mode
\param[in] input: pointer to the input buffer
\param[in] in_length: length of the input buffer
\param[out] output: the result digest
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus hau_hash_md5(uint8_t input[], uint32_t in_length, uint8_t output[])
{
ErrStatus ret = ERROR;
ret = hau_hash_calculate(HAU_ALGO_MD5, input, in_length, output);
return ret;
}
/*!
\brief calculate digest using MD5 in HMAC mode
\param[in] key: pointer to the key used for HMAC
\param[in] keysize: length of the key used for HMAC
\param[in] input: pointer to the input buffer
\param[in] in_length: length of the input buffer
\param[out] output: the result digest
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus hau_hmac_md5(uint8_t key[], uint32_t keysize, uint8_t input[], uint32_t in_length, uint8_t output[])
{
ErrStatus ret = ERROR;
ret = hau_hmac_calculate(HAU_ALGO_MD5, key, keysize, input, in_length, output);
return ret;
}
/*!
\brief HAU SHA/MD5 digest read
\param[in] algo: algorithm selection
only one parameter can be selected which is shown as below
\arg HAU_ALGO_SHA1: SHA1 algorithm
\arg HAU_ALGO_SHA224: SHA224 algorithm
\arg HAU_ALGO_SHA256: SHA256 algorithm
\arg HAU_ALGO_MD5: MD5 algorithm
\param[out] output: the result digest
\retval none
*/
static void hau_sha_md5_digest_read(uint32_t algo, uint8_t output[])
{
hau_digest_parameter_struct digest_para;
uint32_t outputaddr = (uint32_t)output;
switch(algo){
case HAU_ALGO_SHA1:
/* read the message digest result */
hau_digest_read(&digest_para);
/* reverse byte order, copy result to outputaddr */
*(uint32_t*)(outputaddr) = __REV(digest_para.out[0]);
outputaddr += 4U;
*(uint32_t*)(outputaddr) = __REV(digest_para.out[1]);
outputaddr += 4U;
*(uint32_t*)(outputaddr) = __REV(digest_para.out[2]);
outputaddr += 4U;
*(uint32_t*)(outputaddr) = __REV(digest_para.out[3]);
outputaddr += 4U;
*(uint32_t*)(outputaddr) = __REV(digest_para.out[4]);
break;
case HAU_ALGO_SHA224:
/* read the message digest result */
hau_digest_read(&digest_para);
/* reverse byte order, copy result to outputaddr */
*(uint32_t*)(outputaddr) = __REV(digest_para.out[0]);
outputaddr += 4U;
*(uint32_t*)(outputaddr) = __REV(digest_para.out[1]);
outputaddr += 4U;
*(uint32_t*)(outputaddr) = __REV(digest_para.out[2]);
outputaddr += 4U;
*(uint32_t*)(outputaddr) = __REV(digest_para.out[3]);
outputaddr += 4U;
*(uint32_t*)(outputaddr) = __REV(digest_para.out[4]);
outputaddr += 4U;
*(uint32_t*)(outputaddr) = __REV(digest_para.out[5]);
outputaddr += 4U;
*(uint32_t*)(outputaddr) = __REV(digest_para.out[6]);
break;
case HAU_ALGO_SHA256:
/* read the message digest result */
hau_digest_read(&digest_para);
/* reverse byte order, copy result to outputaddr */
*(uint32_t*)(outputaddr) = __REV(digest_para.out[0]);
outputaddr += 4U;
*(uint32_t*)(outputaddr) = __REV(digest_para.out[1]);
outputaddr += 4U;
*(uint32_t*)(outputaddr) = __REV(digest_para.out[2]);
outputaddr += 4U;
*(uint32_t*)(outputaddr) = __REV(digest_para.out[3]);
outputaddr += 4U;
*(uint32_t*)(outputaddr) = __REV(digest_para.out[4]);
outputaddr += 4U;
*(uint32_t*)(outputaddr) = __REV(digest_para.out[5]);
outputaddr += 4U;
*(uint32_t*)(outputaddr) = __REV(digest_para.out[6]);
outputaddr += 4U;
*(uint32_t*)(outputaddr) = __REV(digest_para.out[7]);
break;
case HAU_ALGO_MD5:
/* read the message digest result */
hau_digest_read(&digest_para);
/* reverse byte order, copy result to outputaddr */
*(uint32_t*)(outputaddr) = __REV(digest_para.out[0]);
outputaddr += 4U;
*(uint32_t*)(outputaddr) = __REV(digest_para.out[1]);
outputaddr += 4U;
*(uint32_t*)(outputaddr) = __REV(digest_para.out[2]);
outputaddr += 4U;
*(uint32_t*)(outputaddr) = __REV(digest_para.out[3]);
break;
default:
break;
}
}
/*!
\brief HAU digest calculate process in HASH mode
\param[in] algo: algorithm selection
\param[in] input: pointer to the input buffer
\param[in] in_length: length of the input buffer
\param[out] output: the result digest
\retval ErrStatus: SUCCESS or ERROR
*/
static ErrStatus hau_hash_calculate(uint32_t algo, uint8_t input[], uint32_t in_length, uint8_t output[])
{
hau_init_parameter_struct init_para;
__IO uint32_t num_last_valid = 0U;
uint32_t i = 0U;
__IO uint32_t counter = 0U;
uint32_t busystatus = 0U;
uint32_t inputaddr = (uint32_t)input;
/* number of valid bits in last word */
num_last_valid = 8U * (in_length % 4U);
/* HAU peripheral initialization */
hau_deinit();
/* HAU configuration */
init_para.algo = algo;
init_para.mode = HAU_MODE_HASH;
init_para.datatype = HAU_SWAPPING_8BIT;
hau_init(&init_para);
/* configure the number of valid bits in last word of the message */
hau_last_word_validbits_num_config(num_last_valid);
/* write data to the IN FIFO */
for(i = 0U; i < in_length; i += 4U){
hau_data_write(*(uint32_t*)inputaddr);
inputaddr += 4U;
}
/* enable digest calculation */
hau_digest_calculation_enable();
/* wait until the busy flag is reset */
do{
busystatus = hau_flag_get(HAU_FLAG_BUSY);
counter++;
}while((SHAMD5_BSY_TIMEOUT != counter) && (RESET != busystatus));
if(RESET != busystatus){
return ERROR;
}else{
/* read the message digest */
hau_sha_md5_digest_read(algo, output);
}
return SUCCESS;
}
/*!
\brief HAU digest calculate process in HMAC mode
\param[in] algo: algorithm selection
\param[in] key: pointer to the key used for HMAC
\param[in] keysize: length of the key used for HMAC
\param[in] input: pointer to the input buffer
\param[in] in_length: length of the input buffer
\param[out] output: the result digest
\retval ErrStatus: SUCCESS or ERROR
*/
static ErrStatus hau_hmac_calculate(uint32_t algo, uint8_t key[], uint32_t keysize, uint8_t input[], uint32_t in_length, uint8_t output[])
{
hau_init_parameter_struct init_para;
__IO uint16_t num_last_valid = 0U;
__IO uint16_t num_key_valid = 0U;
uint32_t i = 0U;
__IO uint32_t counter = 0U;
uint32_t busystatus = 0U;
uint32_t keyaddr = (uint32_t)key;
uint32_t inputaddr = (uint32_t)input;
/* number of valid bits in last word of the message */
num_last_valid = 8U * (uint16_t)(in_length % 4U);
/* number of valid bits in last word of the key */
num_key_valid = 8U * (uint16_t)(keysize % 4U);
/* HAU peripheral initialization */
hau_deinit();
/* HAU configuration */
init_para.algo = algo;
init_para.mode = HAU_MODE_HMAC;
init_para.datatype = HAU_SWAPPING_8BIT;
if(keysize > 64U){
init_para.keytype = HAU_KEY_LONGGER_64;
}else{
init_para.keytype = HAU_KEY_SHORTER_64;
}
hau_init(&init_para);
/* configure the number of valid bits in last word of the key */
hau_last_word_validbits_num_config((uint32_t)num_key_valid);
/* write the key */
for(i = 0U; i < keysize; i += 4U){
hau_data_write(*(uint32_t*)keyaddr);
keyaddr += 4U;
}
/* enable digest calculation */
hau_digest_calculation_enable();
/* wait until the busy flag is reset */
do{
busystatus = hau_flag_get(HAU_FLAG_BUSY);
counter++;
}while((SHAMD5_BSY_TIMEOUT != counter) && (RESET != busystatus));
if(RESET != busystatus){
return ERROR;
}else{
/* configure the number of valid bits in last word of the message */
hau_last_word_validbits_num_config((uint32_t)num_last_valid);
/* write data to the IN FIFO */
for(i = 0U; i < in_length; i += 4U){
hau_data_write(*(uint32_t*)inputaddr);
inputaddr += 4U;
}
/* enable digest calculation */
hau_digest_calculation_enable();
/* wait until the busy flag is reset */
counter = 0U;
do{
busystatus = hau_flag_get(HAU_FLAG_BUSY);
counter++;
}while((SHAMD5_BSY_TIMEOUT != counter) && (RESET != busystatus));
if(RESET != busystatus){
return ERROR;
}else{
/* configure the number of valid bits in last word of the key */
hau_last_word_validbits_num_config((uint32_t)num_key_valid);
/* write the key */
keyaddr = (uint32_t)key;
for(i = 0U; i < keysize; i += 4U){
hau_data_write(*(uint32_t*)keyaddr);
keyaddr += 4U;
}
/* enable digest calculation */
hau_digest_calculation_enable();
/* wait until the busy flag is reset */
counter = 0U;
do{
busystatus = hau_flag_get(HAU_FLAG_BUSY);
counter++;
}while((SHAMD5_BSY_TIMEOUT != counter) && (RESET != busystatus));
if(RESET != busystatus){
return ERROR;
}else{
/* read the message digest */
hau_sha_md5_digest_read(algo, output);
}
}
}
return SUCCESS;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,286 @@
/*!
\file gd32h7xx_hwsem.c
\brief HWSEM driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_hwsem.h"
/*!
\brief try to lock the specific semaphore by writing process ID
\param[in] semaphore: semaphore index, refer to hwsem_semaphore_enum
only one parameter can be selected which is shown as below:
\arg SEMx (x=0..31): semaphore x
\param[in] process: the process to lock the semaphore
only one parameter can be selected which is shown as below:
\arg 0 - 0xFF
\param[out] none
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus hwsem_lock_set(hwsem_semaphore_enum semaphore, uint8_t process)
{
uint32_t temp_mid = 0U, temp_pid = 0U;
ErrStatus ret = ERROR;
/* try to lock the semaphore */
HWSEM_CTL(semaphore) = (uint32_t)(HWSEM_LOCK | CTL_MID(HWSEM_MASTER_ID) | CTL_PID(process));
/* read the control register to confirm the semaphore is locked by target process or not */
temp_mid = hwsem_master_id_get(semaphore);
temp_pid = hwsem_process_id_get(semaphore);
if((HWSEM_MASTER_ID == temp_mid) && (process == temp_pid)) {
ret = SUCCESS;
}
return ret;
}
/*!
\brief try to release the lock of the semaphore by writing process ID
\param[in] semaphore: semaphore index, refer to hwsem_semaphore_enum
only one parameter can be selected which is shown as below:
\arg SEMx (x=0..31): semaphore x
\param[in] process: the process to unlock the semaphore
only one parameter can be selected which is shown as below:
\arg 0 - 0xFF
\param[out] none
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus hwsem_lock_release(hwsem_semaphore_enum semaphore, uint8_t process)
{
uint32_t lock_state = 0U;
ErrStatus ret = ERROR;
HWSEM_CTL(semaphore) = (uint32_t)(CTL_MID(HWSEM_MASTER_ID) | CTL_PID(process));
lock_state = HWSEM_CTL(semaphore) & HWSEM_CTL_LK;
if(0U == lock_state) {
ret = SUCCESS;
}
return ret;
}
/*!
\brief try to lock the semaphore by reading
\param[in] semaphore: semaphore index, refer to hwsem_semaphore_enum
only one parameter can be selected which is shown as below:
\arg SEMx (x=0..31): semaphore x
\param[out] none
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus hwsem_lock_by_reading(hwsem_semaphore_enum semaphore)
{
ErrStatus ret = ERROR;
if((uint32_t)(HWSEM_LOCK | CTL_MID(HWSEM_MASTER_ID)) == HWSEM_RLK(semaphore)) {
ret = SUCCESS;
}
return ret;
}
/*!
\brief unlock all semaphores of the master ID
\param[in] key: key value
\arg 0 - 0xFFFF
\param[out] none
\retval none
*/
ErrStatus hwsem_unlock_all(uint16_t key)
{
ErrStatus ret = ERROR;
HWSEM_UNLK = UNLK_KEY(key) | UNLK_MID(HWSEM_MASTER_ID);
if(key == hwsem_key_get()) {
ret = SUCCESS;
}
return ret;
}
/*!
\brief get process ID of the specific semaphore
\param[in] semaphore: semaphore index, refer to hwsem_semaphore_enum
only one parameter can be selected which is shown as below:
\arg SEMx (x=0..31): semaphore x
\param[out] none
\retval uint32_t: process ID of semaphore
*/
uint32_t hwsem_process_id_get(hwsem_semaphore_enum semaphore)
{
return (uint32_t)(GET_CTL_PID(HWSEM_CTL(semaphore)));
}
/*!
\brief get master ID of the specific semaphore
\param[in] semaphore: semaphore index, refer to hwsem_semaphore_enum
only one parameter can be selected which is shown as below:
\arg SEMx (x=0..31): semaphore x
\param[out] none
\retval uint32_t: master ID of semaphore
*/
uint32_t hwsem_master_id_get(hwsem_semaphore_enum semaphore)
{
return (uint32_t)(GET_CTL_MID(HWSEM_CTL(semaphore)));
}
/*!
\brief get the lock status of the semaphore
\param[in] semaphore: semaphore index, refer to hwsem_semaphore_enum
only one parameter can be selected which is shown as below:
\arg SEMx (x=0..31): semaphore x
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus hwsem_lock_status_get(hwsem_semaphore_enum semaphore)
{
FlagStatus ret = RESET;
if(0U != (HWSEM_CTL(semaphore) & HWSEM_LOCK)) {
ret = SET;
}
return ret;
}
/*!
\brief set the key
\param[in] key: key value
\arg 0 - 0xFFFF
\param[out] none
\retval none
*/
void hwsem_key_set(uint16_t key)
{
HWSEM_KEY = KEY_KEY(key);
}
/*!
\brief get the key
\param[in] none
\param[out] none
\retval uint16_t: key to unlock all semaphores
*/
uint16_t hwsem_key_get(void)
{
return ((uint16_t)GET_KEY_KEY(HWSEM_KEY));
}
/*!
\brief get the HWSEM flag status
\param[in] semaphore: semaphore index, refer to hwsem_semaphore_enum
only one parameter can be selected which is shown as below:
\arg SEMx (x=0..31): semaphore x
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus hwsem_flag_get(hwsem_semaphore_enum semaphore)
{
FlagStatus ret = RESET;
if(RESET != ((HWSEM_STAT >> semaphore) & 0x1U)) {
return SET;
}
return ret;
}
/*!
\brief clear HWSEM flag status
\param[in] semaphore: semaphore index, refer to hwsem_semaphore_enum
only one parameter can be selected which is shown as below:
\arg SEMx (x=0..31): semaphore x
\param[out] none
\retval none
*/
void hwsem_flag_clear(hwsem_semaphore_enum semaphore)
{
HWSEM_INTC = (1U << semaphore);
}
/*!
\brief get HWSEM interrupt flag status
\param[in] semaphore: semaphore index, refer to hwsem_semaphore_enum
only one parameter can be selected which is shown as below:
\arg SEMx (x=0..31): semaphore x
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus hwsem_interrupt_flag_get(hwsem_semaphore_enum semaphore)
{
FlagStatus ret = RESET;
if(RESET != ((HWSEM_INTF >> semaphore) & 0x1U)) {
ret = SET;
}
return ret;
}
/*!
\brief clear HWSEM interrupt flag
\param[in] semaphore: semaphore index, refer to hwsem_semaphore_enum
only one parameter can be selected which is shown as below:
\arg SEMx (x=0..31): semaphore x
\param[out] none
\retval none
*/
void hwsem_interrupt_flag_clear(hwsem_semaphore_enum semaphore)
{
HWSEM_INTC = (1U << semaphore);
}
/*!
\brief enable HWSEM interrupt
\param[in] semaphore: semaphore index, refer to hwsem_semaphore_enum
only one parameter can be selected which is shown as below:
\arg SEMx (x=0..31): semaphore x
\param[out] none
\retval none
*/
void hwsem_interrupt_enable(hwsem_semaphore_enum semaphore)
{
HWSEM_INTEN |= (1U << semaphore);
}
/*!
\brief disable HWSEM interrupt
\param[in] semaphore: semaphore index, refer to hwsem_semaphore_enum
only one parameter can be selected which is shown as below:
\arg SEMx (x=0..31): semaphore x
\param[out] none
\retval none
*/
void hwsem_interrupt_disable(hwsem_semaphore_enum semaphore)
{
HWSEM_INTEN &= (uint32_t)(~((uint32_t)1U << semaphore));
}
@@ -0,0 +1,968 @@
/*!
\file gd32h7xx_i2c.c
\brief I2C driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_i2c.h"
/* I2C register bit 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 CTL0_DNF_OFFSET ((uint32_t)0x00000008U) /*!< bit offset of DNF in I2C_CTL0 */
#define CTL1_BYTENUM_OFFSET ((uint32_t)0x00000010U) /*!< bit offset of BYTENUM in I2C_CTL1 */
#define STAT_READDR_OFFSET ((uint32_t)0x00000011U) /*!< bit offset of READDR in I2C_STAT */
#define TIMING_SCLL_OFFSET ((uint32_t)0x00000000U) /*!< bit offset of SCLL in I2C_TIMING */
#define TIMING_SCLH_OFFSET ((uint32_t)0x00000008U) /*!< bit offset of SCLH in I2C_TIMING */
#define TIMING_SDADELY_OFFSET ((uint32_t)0x00000010U) /*!< bit offset of SDADELY in I2C_TIMING */
#define TIMING_SCLDELY_OFFSET ((uint32_t)0x00000014U) /*!< bit offset of SCLDELY in I2C_TIMING */
#define TIMING_PSC_OFFSET ((uint32_t)0x0000001CU) /*!< bit offset of PSC in I2C_TIMING */
#define SADDR1_ADDMSK_OFFSET ((uint32_t)0x00000008U) /*!< bit offset of ADDMSK in I2C_SADDR1 */
#define TIMEOUT_BUSTOB_OFFSET ((uint32_t)0x00000010U) /*!< bit offset of BUSTOB in I2C_TIMEOUT */
/*!
\brief reset I2C
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_deinit(uint32_t i2c_periph)
{
switch(i2c_periph) {
/* reset I2C0 */
case I2C0:
rcu_periph_reset_enable(RCU_I2C0RST);
rcu_periph_reset_disable(RCU_I2C0RST);
break;
/* reset I2C1 */
case I2C1:
rcu_periph_reset_enable(RCU_I2C1RST);
rcu_periph_reset_disable(RCU_I2C1RST);
break;
/* reset I2C2 */
case I2C2:
rcu_periph_reset_enable(RCU_I2C2RST);
rcu_periph_reset_disable(RCU_I2C2RST);
break;
/* reset I2C3 */
case I2C3:
rcu_periph_reset_enable(RCU_I2C3RST);
rcu_periph_reset_disable(RCU_I2C3RST);
break;
default:
break;
}
}
/*!
\brief configure the timing parameters
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[in] psc: 0-0x0000000F, timing prescaler
\param[in] scl_dely: 0-0x0000000F, data setup time
\param[in] sda_dely: 0-0x0000000F, data hold time
\param[out] none
\retval none
*/
void i2c_timing_config(uint32_t i2c_periph, uint32_t psc, uint32_t scl_dely, uint32_t sda_dely)
{
/* clear PSC, SCLDELY, SDADELY bits in I2C_TIMING register */
I2C_TIMING(i2c_periph) &= ~I2C_TIMING_PSC;
I2C_TIMING(i2c_periph) &= ~I2C_TIMING_SCLDELY;
I2C_TIMING(i2c_periph) &= ~I2C_TIMING_SDADELY;
/* mask PSC, SCLDELY, SDADELY bits in I2C_TIMING register */
psc = (uint32_t)(psc << TIMING_PSC_OFFSET) & I2C_TIMING_PSC;
scl_dely = (uint32_t)(scl_dely << TIMING_SCLDELY_OFFSET) & I2C_TIMING_SCLDELY;
sda_dely = (uint32_t)(sda_dely << TIMING_SDADELY_OFFSET) & I2C_TIMING_SDADELY;
/* write PSC, SCLDELY, SDADELY bits in I2C_TIMING register */
I2C_TIMING(i2c_periph) |= (psc | scl_dely | sda_dely);
}
/*!
\brief configure digital noise filter
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[in] filter_length: the length of filter spikes
only one parameter can be selected which is shown as below:
\arg FILTER_DISABLE: digital filter is disabled
\arg FILTER_LENGTH_1: digital filter is enabled and filter spikes with a length of up to 1 tI2CCLK
\arg FILTER_LENGTH_2: digital filter is enabled and filter spikes with a length of up to 2 tI2CCLK
\arg FILTER_LENGTH_3: digital filter is enabled and filter spikes with a length of up to 3 tI2CCLK
\arg FILTER_LENGTH_4: digital filter is enabled and filter spikes with a length of up to 4 tI2CCLK
\arg FILTER_LENGTH_5: digital filter is enabled and filter spikes with a length of up to 5 tI2CCLK
\arg FILTER_LENGTH_6: digital filter is enabled and filter spikes with a length of up to 6 tI2CCLK
\arg FILTER_LENGTH_7: digital filter is enabled and filter spikes with a length of up to 7 tI2CCLK
\arg FILTER_LENGTH_8: digital filter is enabled and filter spikes with a length of up to 8 tI2CCLK
\arg FILTER_LENGTH_9: digital filter is enabled and filter spikes with a length of up to 9 tI2CCLK
\arg FILTER_LENGTH_10: digital filter is enabled and filter spikes with a length of up to 10 tI2CCLK
\arg FILTER_LENGTH_11: digital filter is enabled and filter spikes with a length of up to 11 tI2CCLK
\arg FILTER_LENGTH_12: digital filter is enabled and filter spikes with a length of up to 12 tI2CCLK
\arg FILTER_LENGTH_13: digital filter is enabled and filter spikes with a length of up to 13 tI2CCLK
\arg FILTER_LENGTH_14: digital filter is enabled and filter spikes with a length of up to 14 tI2CCLK
\arg FILTER_LENGTH_15: digital filter is enabled and filter spikes with a length of up to 15 tI2CCLK
\param[out] none
\retval none
*/
void i2c_digital_noise_filter_config(uint32_t i2c_periph, uint32_t filter_length)
{
I2C_CTL0(i2c_periph) &= (uint32_t)(~I2C_CTL0_DNF);
I2C_CTL0(i2c_periph) |= (uint32_t)(filter_length << CTL0_DNF_OFFSET);
}
/*!
\brief enable analog noise filter
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_analog_noise_filter_enable(uint32_t i2c_periph)
{
I2C_CTL0(i2c_periph) &= ~I2C_CTL0_ANOFF;
}
/*!
\brief disable analog noise filter
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_analog_noise_filter_disable(uint32_t i2c_periph)
{
I2C_CTL0(i2c_periph) |= I2C_CTL0_ANOFF;
}
/*!
\brief configure the SCL high and low period of clock in master mode
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[in] sclh: 0-0x000000FF, SCL high period
\param[in] scll: 0-0x000000FF, SCL low period
\param[out] none
\retval none
*/
void i2c_master_clock_config(uint32_t i2c_periph, uint32_t sclh, uint32_t scll)
{
/* clear SCLH, SCLL bits in I2C_TIMING register */
I2C_TIMING(i2c_periph) &= ~I2C_TIMING_SCLH;
I2C_TIMING(i2c_periph) &= ~I2C_TIMING_SCLL;
/* mask SCLH, SCLL bits in I2C_TIMING register */
sclh = (uint32_t)(sclh << TIMING_SCLH_OFFSET) & I2C_TIMING_SCLH;
scll = (uint32_t)(scll << TIMING_SCLL_OFFSET) & I2C_TIMING_SCLL;
/* write SCLH, SCLL bits in I2C_TIMING register */
I2C_TIMING(i2c_periph) |= (sclh | scll);
}
/*!
\brief configure I2C slave address and transfer direction in master mode
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[in] address: 0-0x3FF except reserved address, I2C slave address to be sent
\param[in] trans_direction: I2C transfer direction in master mode
only one parameter can be selected which is shown as below:
\arg I2C_MASTER_TRANSMIT: master transmit
\arg I2C_MASTER_RECEIVE: master receive
\param[out] none
\retval none
*/
void i2c_master_addressing(uint32_t i2c_periph, uint32_t address, uint32_t trans_direction)
{
/* configure slave address */
I2C_CTL1(i2c_periph) &= ~I2C_CTL1_SADDRESS;
I2C_CTL1(i2c_periph) |= address;
/* configure transfer direction */
I2C_CTL1(i2c_periph) &= ~I2C_CTL1_TRDIR;
I2C_CTL1(i2c_periph) |= trans_direction;
}
/*!
\brief 10-bit address header executes read direction only in master receive mode
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_address10_header_enable(uint32_t i2c_periph)
{
I2C_CTL1(i2c_periph) |= I2C_CTL1_HEAD10R;
}
/*!
\brief 10-bit address header executes complete sequence in master receive mode
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_address10_header_disable(uint32_t i2c_periph)
{
I2C_CTL1(i2c_periph) &= ~I2C_CTL1_HEAD10R;
}
/*!
\brief enable 10-bit addressing mode in master mode
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_address10_enable(uint32_t i2c_periph)
{
I2C_CTL1(i2c_periph) |= I2C_CTL1_ADD10EN;
}
/*!
\brief disable 10-bit addressing mode in master mode
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_address10_disable(uint32_t i2c_periph)
{
I2C_CTL1(i2c_periph) &= ~I2C_CTL1_ADD10EN;
}
/*!
\brief enable I2C automatic end mode in master mode
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_automatic_end_enable(uint32_t i2c_periph)
{
I2C_CTL1(i2c_periph) |= I2C_CTL1_AUTOEND;
}
/*!
\brief disable I2C automatic end mode in master mode
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_automatic_end_disable(uint32_t i2c_periph)
{
I2C_CTL1(i2c_periph) &= ~I2C_CTL1_AUTOEND;
}
/*!
\brief enable the response to a general call
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_slave_response_to_gcall_enable(uint32_t i2c_periph)
{
I2C_CTL0(i2c_periph) |= I2C_CTL0_GCEN;
}
/*!
\brief disable the response to a general call
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_slave_response_to_gcall_disable(uint32_t i2c_periph)
{
I2C_CTL0(i2c_periph) &= ~I2C_CTL0_GCEN;
}
/*!
\brief enable to stretch SCL low when data is not ready in slave mode
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_stretch_scl_low_enable(uint32_t i2c_periph)
{
I2C_CTL0(i2c_periph) &= ~I2C_CTL0_SS;
}
/*!
\brief disable to stretch SCL low when data is not ready in slave mode
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_stretch_scl_low_disable(uint32_t i2c_periph)
{
I2C_CTL0(i2c_periph) |= I2C_CTL0_SS;
}
/*!
\brief configure I2C slave address
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[in] address: I2C address
\param[in] addr_format: 7 bits or 10 bits
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[out] none
\retval none
*/
void i2c_address_config(uint32_t i2c_periph, uint32_t address, uint32_t addr_format)
{
/* configure ADDRESS[7:1] and address format */
address = address & I2C_ADDRESS_MASK;
I2C_SADDR0(i2c_periph) = (addr_format | address);
/* enable I2C address in slave mode */
I2C_SADDR0(i2c_periph) |= I2C_SADDR0_ADDRESSEN;
}
/*!
\brief define which bits of ADDRESS[7:1] need to compare with the incoming address byte
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[in] compare_bits: the bits need to compare
only one parameter can be selected which is shown as below:
\arg ADDRESS_BIT1_COMPARE: address bit1 needs compare
\arg ADDRESS_BIT2_COMPARE: address bit2 needs compare
\arg ADDRESS_BIT3_COMPARE: address bit3 needs compare
\arg ADDRESS_BIT4_COMPARE: address bit4 needs compare
\arg ADDRESS_BIT5_COMPARE: address bit5 needs compare
\arg ADDRESS_BIT6_COMPARE: address bit6 needs compare
\arg ADDRESS_BIT7_COMPARE: address bit7 needs compare
\param[out] none
\retval none
*/
void i2c_address_bit_compare_config(uint32_t i2c_periph, uint32_t compare_bits)
{
I2C_CTL2(i2c_periph) &= ~I2C_CTL2_ADDM;
I2C_CTL2(i2c_periph) |= compare_bits;
}
/*!
\brief disable I2C address in slave mode
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_address_disable(uint32_t i2c_periph)
{
I2C_SADDR0(i2c_periph) &= ~I2C_SADDR0_ADDRESSEN;
}
/*!
\brief configure I2C second slave address
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[in] address: I2C address
\param[in] addr_mask: the bits not need to compare
only one parameter can be selected which is shown as below:
\arg ADDRESS2_NO_MASK: no mask, all the bits must be compared
\arg ADDRESS2_MASK_BIT1: ADDRESS2[1] is masked, only ADDRESS2[7:2] are compared
\arg ADDRESS2_MASK_BIT1_2: ADDRESS2[2:1] is masked, only ADDRESS2[7:3] are compared
\arg ADDRESS2_MASK_BIT1_3: ADDRESS2[3:1] is masked, only ADDRESS2[7:4] are compared
\arg ADDRESS2_MASK_BIT1_4: ADDRESS2[4:1] is masked, only ADDRESS2[7:5] are compared
\arg ADDRESS2_MASK_BIT1_5: ADDRESS2[5:1] is masked, only ADDRESS2[7:6] are compared
\arg ADDRESS2_MASK_BIT1_6: ADDRESS2[6:1] is masked, only ADDRESS2[7] are compared
\arg ADDRESS2_MASK_ALL: all the ADDRESS2[7:1] bits are masked
\param[out] none
\retval none
*/
void i2c_second_address_config(uint32_t i2c_periph, uint32_t address, uint32_t addr_mask)
{
/* configure ADDRESS2[7:1] */
address = address & I2C_ADDRESS2_MASK;
I2C_SADDR1(i2c_periph) |= address;
/* configure ADDRESS2[7:1] mask */
I2C_SADDR1(i2c_periph) &= ~I2C_SADDR1_ADDMSK2;
I2C_SADDR1(i2c_periph) |= (uint32_t)(addr_mask << SADDR1_ADDMSK_OFFSET);
/* enable i2c second address in slave mode */
I2C_SADDR1(i2c_periph) |= I2C_SADDR1_ADDRESS2EN;
}
/*!
\brief disable I2C second address in slave mode
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_second_address_disable(uint32_t i2c_periph)
{
I2C_SADDR1(i2c_periph) &= ~I2C_SADDR1_ADDRESS2EN;
}
/*!
\brief get received match address in slave mode
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval uint32_t: received match address
*/
uint32_t i2c_recevied_address_get(uint32_t i2c_periph)
{
return (uint32_t)((I2C_STAT(i2c_periph) & I2C_STAT_READDR) >> STAT_READDR_OFFSET);
}
/*!
\brief enable slave byte control
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_slave_byte_control_enable(uint32_t i2c_periph)
{
I2C_CTL0(i2c_periph) |= I2C_CTL0_SBCTL;
}
/*!
\brief disable slave byte control
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_slave_byte_control_disable(uint32_t i2c_periph)
{
I2C_CTL0(i2c_periph) &= ~I2C_CTL0_SBCTL;
}
/*!
\brief generate a NACK in slave mode
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_nack_enable(uint32_t i2c_periph)
{
I2C_CTL1(i2c_periph) |= I2C_CTL1_NACKEN;
}
/*!
\brief generate an ACK in slave mode
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_nack_disable(uint32_t i2c_periph)
{
I2C_CTL1(i2c_periph) &= ~I2C_CTL1_NACKEN;
}
/*!
\brief enable wakeup from deep-sleep mode
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_wakeup_from_deepsleep_enable(uint32_t i2c_periph)
{
I2C_CTL0(i2c_periph) |= I2C_CTL0_WUEN;
}
/*!
\brief disable wakeup from deep-sleep mode
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_wakeup_from_deepsleep_disable(uint32_t i2c_periph)
{
I2C_CTL0(i2c_periph) &= ~I2C_CTL0_WUEN;
}
/*!
\brief enable I2C
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\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,2,3)
\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,2,3)
\param[out] none
\retval none
*/
void i2c_start_on_bus(uint32_t i2c_periph)
{
I2C_CTL1(i2c_periph) |= I2C_CTL1_START;
}
/*!
\brief generate a STOP condition on I2C bus
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_stop_on_bus(uint32_t i2c_periph)
{
I2C_CTL1(i2c_periph) |= I2C_CTL1_STOP;
}
/*!
\brief I2C transmit data
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[in] data: data to be transmitted
\param[out] none
\retval none
*/
void i2c_data_transmit(uint32_t i2c_periph, uint32_t data)
{
I2C_TDATA(i2c_periph) = (I2C_TDATA_TDATA & data);
}
/*!
\brief I2C receive data
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval uint32_t: 0x0-0xFF
*/
uint32_t i2c_data_receive(uint32_t i2c_periph)
{
return (I2C_RDATA(i2c_periph) & I2C_RDATA_RDATA);
}
/*!
\brief enable I2C reload mode
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_reload_enable(uint32_t i2c_periph)
{
I2C_CTL1(i2c_periph) |= I2C_CTL1_RELOAD;
}
/*!
\brief disable I2C reload mode
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_reload_disable(uint32_t i2c_periph)
{
I2C_CTL1(i2c_periph) &= ~I2C_CTL1_RELOAD;
}
/*!
\brief configure number of bytes to be transferred
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[in] byte_number: 0x0-0xFF, number of bytes to be transferred
\param[out] none
\retval none
*/
void i2c_transfer_byte_number_config(uint32_t i2c_periph, uint32_t byte_number)
{
I2C_CTL1(i2c_periph) &= (uint32_t)(~I2C_CTL1_BYTENUM);
I2C_CTL1(i2c_periph) |= (uint32_t)(byte_number << CTL1_BYTENUM_OFFSET);
}
/*!
\brief enable I2C DMA for transmission or reception
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[in] dma: I2C DMA
only one parameter can be selected which is shown as below:
\arg I2C_DMA_TRANSMIT: transmit data using DMA
\arg I2C_DMA_RECEIVE: receive data using DMA
\param[out] none
\retval none
*/
void i2c_dma_enable(uint32_t i2c_periph, uint8_t dma)
{
if(I2C_DMA_TRANSMIT == dma) {
I2C_CTL0(i2c_periph) |= I2C_CTL0_DENT;
} else {
I2C_CTL0(i2c_periph) |= I2C_CTL0_DENR;
}
}
/*!
\brief disable I2C DMA for transmission or reception
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[in] dma: I2C DMA
only one parameter can be selected which is shown as below:
\arg I2C_DMA_TRANSMIT: transmit data using DMA
\arg I2C_DMA_RECEIVE: receive data using DMA
\param[out] none
\retval none
*/
void i2c_dma_disable(uint32_t i2c_periph, uint8_t dma)
{
if(I2C_DMA_TRANSMIT == dma) {
I2C_CTL0(i2c_periph) &= ~I2C_CTL0_DENT;
} else {
I2C_CTL0(i2c_periph) &= ~I2C_CTL0_DENR;
}
}
/*!
\brief I2C transfers PEC value
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_pec_transfer(uint32_t i2c_periph)
{
I2C_CTL1(i2c_periph) |= I2C_CTL1_PECTRANS;
}
/*!
\brief enable I2C PEC calculation
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_pec_enable(uint32_t i2c_periph)
{
I2C_CTL0(i2c_periph) |= I2C_CTL0_PECEN;
}
/*!
\brief disable I2C PEC calculation
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_pec_disable(uint32_t i2c_periph)
{
I2C_CTL0(i2c_periph) &= ~I2C_CTL0_PECEN;
}
/*!
\brief get packet error checking value
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval uint32_t: 0x0-0xFF
*/
uint32_t i2c_pec_value_get(uint32_t i2c_periph)
{
return (I2C_PEC(i2c_periph) & I2C_PEC_PECV);
}
/*!
\brief enable SMBus alert
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_smbus_alert_enable(uint32_t i2c_periph)
{
I2C_CTL0(i2c_periph) |= I2C_CTL0_SMBALTEN;
}
/*!
\brief disable SMBus alert
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_smbus_alert_disable(uint32_t i2c_periph)
{
I2C_CTL0(i2c_periph) &= ~I2C_CTL0_SMBALTEN;
}
/*!
\brief enable SMBus device default address
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_smbus_default_addr_enable(uint32_t i2c_periph)
{
I2C_CTL0(i2c_periph) |= I2C_CTL0_SMBDAEN;
}
/*!
\brief disable SMBus device default address
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_smbus_default_addr_disable(uint32_t i2c_periph)
{
I2C_CTL0(i2c_periph) &= ~I2C_CTL0_SMBDAEN;
}
/*!
\brief enable SMBus host address
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_smbus_host_addr_enable(uint32_t i2c_periph)
{
I2C_CTL0(i2c_periph) |= I2C_CTL0_SMBHAEN;
}
/*!
\brief disable SMBus host address
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_smbus_host_addr_disable(uint32_t i2c_periph)
{
I2C_CTL0(i2c_periph) &= ~I2C_CTL0_SMBHAEN;
}
/*!
\brief enable extended clock timeout detection
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_extented_clock_timeout_enable(uint32_t i2c_periph)
{
I2C_TIMEOUT(i2c_periph) |= I2C_TIMEOUT_EXTOEN;
}
/*!
\brief disable extended clock timeout detection
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_extented_clock_timeout_disable(uint32_t i2c_periph)
{
I2C_TIMEOUT(i2c_periph) &= ~I2C_TIMEOUT_EXTOEN;
}
/*!
\brief enable clock timeout detection
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_clock_timeout_enable(uint32_t i2c_periph)
{
I2C_TIMEOUT(i2c_periph) |= I2C_TIMEOUT_TOEN;
}
/*!
\brief disable clock timeout detection
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[out] none
\retval none
*/
void i2c_clock_timeout_disable(uint32_t i2c_periph)
{
I2C_TIMEOUT(i2c_periph) &= ~I2C_TIMEOUT_TOEN;
}
/*!
\brief configure bus timeout B
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[in] timeout: bus timeout B
\param[out] none
\retval none
*/
void i2c_bus_timeout_b_config(uint32_t i2c_periph, uint32_t timeout)
{
I2C_TIMEOUT(i2c_periph) &= ~I2C_TIMEOUT_BUSTOB;
I2C_TIMEOUT(i2c_periph) |= (uint32_t)(timeout << TIMEOUT_BUSTOB_OFFSET);
}
/*!
\brief configure bus timeout A
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[in] timeout: bus timeout A
\param[out] none
\retval none
*/
void i2c_bus_timeout_a_config(uint32_t i2c_periph, uint32_t timeout)
{
I2C_TIMEOUT(i2c_periph) &= ~I2C_TIMEOUT_BUSTOA;
I2C_TIMEOUT(i2c_periph) |= timeout;
}
/*!
\brief configure idle clock timeout detection
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[in] timeout: bus timeout A
\arg BUSTOA_DETECT_SCL_LOW: BUSTOA is used to detect SCL low timeout
\arg BUSTOA_DETECT_IDLE: BUSTOA is used to detect both SCL and SDA high timeout when the bus is idle
\param[out] none
\retval none
*/
void i2c_idle_clock_timeout_config(uint32_t i2c_periph, uint32_t timeout)
{
I2C_TIMEOUT(i2c_periph) &= ~I2C_TIMEOUT_TOIDLE;
I2C_TIMEOUT(i2c_periph) |= timeout;
}
/*!
\brief get I2C flag status
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[in] flag: I2C flags
only one parameter can be selected which is shown as below:
\arg I2C_FLAG_TBE: I2C_TDATA is empty during transmitting
\arg I2C_FLAG_TI: transmit interrupt
\arg I2C_FLAG_RBNE: I2C_RDATA is not empty during receiving
\arg I2C_FLAG_ADDSEND: address received matches in slave mode
\arg I2C_FLAG_NACK: not acknowledge flag
\arg I2C_FLAG_STPDET: STOP condition detected in slave mode
\arg I2C_FLAG_TC: transfer complete in master mode
\arg I2C_FLAG_TCR: transfer complete reload
\arg I2C_FLAG_BERR: bus error
\arg I2C_FLAG_LOSTARB: arbitration Lost
\arg I2C_FLAG_OUERR: overrun/underrun error in slave mode
\arg I2C_FLAG_PECERR: PEC error
\arg I2C_FLAG_TIMEOUT: timeout flag
\arg I2C_FLAG_SMBALT: SMBus alert
\arg I2C_FLAG_I2CBSY: busy flag
\arg I2C_FLAG_TR: whether the I2C is a transmitter or a receiver in slave mode
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus i2c_flag_get(uint32_t i2c_periph, uint32_t flag)
{
if(RESET != (I2C_STAT(i2c_periph) & flag)) {
return SET;
} else {
return RESET;
}
}
/*!
\brief clear I2C flag status
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[in] flag: I2C flags
only one parameter can be selected which is shown as below:
\arg I2C_FLAG_ADDSEND: address received matches in slave mode
\arg I2C_FLAG_NACK: not acknowledge flag
\arg I2C_FLAG_STPDET: STOP condition detected in slave mode
\arg I2C_FLAG_BERR: bus error
\arg I2C_FLAG_LOSTARB: arbitration Lost
\arg I2C_FLAG_OUERR: overrun/underrun error in slave mode
\arg I2C_FLAG_PECERR: PEC error
\arg I2C_FLAG_TIMEOUT: timeout flag
\arg I2C_FLAG_SMBALT: SMBus Alert
\param[out] none
\retval none
*/
void i2c_flag_clear(uint32_t i2c_periph, uint32_t flag)
{
I2C_STATC(i2c_periph) |= flag;
}
/*!
\brief enable I2C interrupt
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[in] interrupt: I2C interrupts
only one parameter can be selected which is shown as below:
\arg I2C_INT_ERR: error interrupt
\arg I2C_INT_TC: transfer complete interrupt
\arg I2C_INT_STPDET: stop detection interrupt
\arg I2C_INT_NACK: not acknowledge received interrupt
\arg I2C_INT_ADDM: address match interrupt
\arg I2C_INT_RBNE: receive interrupt
\arg I2C_INT_TI: transmit interrupt
\param[out] none
\retval none
*/
void i2c_interrupt_enable(uint32_t i2c_periph, uint32_t interrupt)
{
I2C_CTL0(i2c_periph) |= interrupt;
}
/*!
\brief disable I2C interrupt
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[in] interrupt: I2C interrupts
only one parameter can be selected which is shown as below:
\arg I2C_INT_ERR: error interrupt
\arg I2C_INT_TC: transfer complete interrupt
\arg I2C_INT_STPDET: stop detection interrupt
\arg I2C_INT_NACK: not acknowledge received interrupt
\arg I2C_INT_ADDM: address match interrupt
\arg I2C_INT_RBNE: receive interrupt
\arg I2C_INT_TI: transmit interrupt
\param[out] none
\retval none
*/
void i2c_interrupt_disable(uint32_t i2c_periph, uint32_t interrupt)
{
I2C_CTL0(i2c_periph) &= ~interrupt;
}
/*!
\brief get I2C interrupt flag status
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[in] int_flag: I2C interrupt flags
only one parameter can be selected which is shown as below:
\arg I2C_INT_FLAG_TI: transmit interrupt flag
\arg I2C_INT_FLAG_RBNE: I2C_RDATA is not empty during receiving interrupt flag
\arg I2C_INT_FLAG_ADDSEND: address received matches in slave mode interrupt flag
\arg I2C_INT_FLAG_NACK: not acknowledge interrupt flag
\arg I2C_INT_FLAG_STPDET: stop condition detected in slave mode interrupt flag
\arg I2C_INT_FLAG_TC: transfer complete in master mode interrupt flag
\arg I2C_INT_FLAG_TCR: transfer complete reload interrupt flag
\arg I2C_INT_FLAG_BERR: bus error interrupt flag
\arg I2C_INT_FLAG_LOSTARB: arbitration lost interrupt flag
\arg I2C_INT_FLAG_OUERR: overrun/underrun error in slave mode interrupt flag
\arg I2C_INT_FLAG_PECERR: PEC error interrupt flag
\arg I2C_INT_FLAG_TIMEOUT: timeout interrupt flag
\arg I2C_INT_FLAG_SMBALT: SMBus Alert 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 ret1 = RESET;
uint32_t ret2 = RESET;
/* get the status of interrupt enable bit */
ret1 = (I2C_REG_VAL(i2c_periph, int_flag) & BIT(I2C_BIT_POS(int_flag)));
/* get the status of interrupt flag */
ret2 = (I2C_REG_VAL2(i2c_periph, int_flag) & BIT(I2C_BIT_POS2(int_flag)));
if(ret1 && ret2) {
return SET;
} else {
return RESET;
}
}
/*!
\brief clear I2C interrupt flag status
\param[in] i2c_periph: I2Cx(x=0,1,2,3)
\param[in] int_flag: I2C interrupt flags
only one parameter can be selected which is shown as below:
\arg I2C_INT_FLAG_ADDSEND: address received matches in slave mode interrupt flag
\arg I2C_INT_FLAG_NACK: not acknowledge interrupt flag
\arg I2C_INT_FLAG_STPDET: stop condition detected in slave mode interrupt flag
\arg I2C_INT_FLAG_BERR: bus error interrupt flag
\arg I2C_INT_FLAG_LOSTARB: arbitration lost interrupt flag
\arg I2C_INT_FLAG_OUERR: overrun/underrun error in slave mode interrupt flag
\arg I2C_INT_FLAG_PECERR: PEC error interrupt flag
\arg I2C_INT_FLAG_TIMEOUT: timeout interrupt flag
\arg I2C_INT_FLAG_SMBALT: SMBus Alert interrupt flag
\param[out] none
\retval none
*/
void i2c_interrupt_flag_clear(uint32_t i2c_periph, i2c_interrupt_flag_enum int_flag)
{
I2C_STATC(i2c_periph) |= BIT(I2C_BIT_POS2(int_flag));
}
@@ -0,0 +1,823 @@
/*!
\file gd32h7xx_ipa.c
\brief IPA driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_ipa.h"
#define IPA_DEFAULT_VALUE 0x00000000U
#define IPA_DEFAULT_SCALE 0x00001000U
#define IPA_DEFAULT_YUV_CONV_YOFFSET 0x00000000U
#define IPA_DEFAULT_YUV_CONV_UVOFFSET 0x00000000U
#define IPA_DEFAULT_YUV_CONV_C0OFFSET 0x00000100U
#define IPA_DEFAULT_YUV_CONV_C1OFFSET 0x00000123U
#define IPA_DEFAULT_YUV_CONV_C2OFFSET 0x0000076BU
#define IPA_DEFAULT_YUV_CONV_C3OFFSET 0x0000079CU
#define IPA_DEFAULT_YUV_CONV_C4OFFSET 0x00000208U
#define IPA_DEFAULT_YCBCR_CONV_YOFFSET 0x000001F0U
#define IPA_DEFAULT_YCBCR_CONV_UVOFFSET 0x00000180U
#define IPA_DEFAULT_YCBCR_CONV_C0OFFSET 0x0000012AU
#define IPA_DEFAULT_YCBCR_CONV_C1OFFSET 0x00000198U
#define IPA_DEFAULT_YCBCR_CONV_C2OFFSET 0x00000730U
#define IPA_DEFAULT_YCBCR_CONV_C3OFFSET 0x0000079CU
#define IPA_DEFAULT_YCBCR_CONV_C4OFFSET 0x00000204U
/*!
\brief deinitialize IPA registers
\param[in] none
\param[out] none
\retval none
*/
void ipa_deinit(void)
{
rcu_periph_reset_enable(RCU_IPARST);
rcu_periph_reset_disable(RCU_IPARST);
}
/*!
\brief enable IPA transfer
\param[in] none
\param[out] none
\retval none
*/
void ipa_transfer_enable(void)
{
IPA_CTL |= IPA_CTL_TEN;
}
/*!
\brief enable IPA transfer hang up
\param[in] none
\param[out] none
\retval none
*/
void ipa_transfer_hangup_enable(void)
{
IPA_CTL |= IPA_CTL_THU;
}
/*!
\brief disable IPA transfer hang up
\param[in] none
\param[out] none
\retval none
*/
void ipa_transfer_hangup_disable(void)
{
IPA_CTL &= ~(IPA_CTL_THU);
}
/*!
\brief enable IPA transfer stop
\param[in] none
\param[out] none
\retval none
*/
void ipa_transfer_stop_enable(void)
{
IPA_CTL |= IPA_CTL_TST;
}
/*!
\brief disable IPA transfer stop
\param[in] none
\param[out] none
\retval none
*/
void ipa_transfer_stop_disable(void)
{
IPA_CTL &= ~(IPA_CTL_TST);
}
/*!
\brief enable IPA foreground LUT loading
\param[in] none
\param[out] none
\retval none
*/
void ipa_foreground_lut_loading_enable(void)
{
IPA_FPCTL |= IPA_FPCTL_FLLEN;
}
/*!
\brief enable IPA background LUT loading
\param[in] none
\param[out] none
\retval none
*/
void ipa_background_lut_loading_enable(void)
{
IPA_BPCTL |= IPA_BPCTL_BLLEN;
}
/*!
\brief set pixel format convert mode, the function is invalid when the IPA transfer is enabled
\param[in] pfcm: pixel format convert mode
only one parameter can be selected which is shown as below:
\arg IPA_FGTODE: foreground memory to destination memory without pixel format convert
\arg IPA_FGTODE_PF_CONVERT: foreground memory to destination memory with pixel format convert
\arg IPA_FGBGTODE: blending foreground and background memory to destination memory
\arg IPA_FILL_UP_DE: fill up destination memory with specific color
\param[out] none
\retval none
*/
void ipa_pixel_format_convert_mode_set(uint32_t pfcm)
{
IPA_CTL &= ~(IPA_CTL_PFCM);
IPA_CTL |= pfcm;
}
/*!
\brief enable foreground interlace mode
\param[in] none
\param[out] none
\retval none
*/
void ipa_foreground_interlace_mode_enable(void)
{
IPA_FPCTL |= IPA_FPCTL_FIIMEN;
}
/*!
\brief disable foreground interlace mode
\param[in] none
\param[out] none
\retval none
*/
void ipa_foreground_interlace_mode_disable(void)
{
IPA_FPCTL &= ~(IPA_FPCTL_FIIMEN);
}
/*!
\brief initialize the structure of IPA foreground parameter struct with the default values, it is
suggested that call this function after an ipa_foreground_parameter_struct structure is defined
\param[in] none
\param[out] foreground_struct: the data needed to initialize foreground
\retval none
*/
void ipa_foreground_struct_para_init(ipa_foreground_parameter_struct* foreground_struct)
{
/* initialize the struct parameters with default values */
foreground_struct->foreground_memaddr = IPA_DEFAULT_VALUE;
foreground_struct->foreground_lineoff = IPA_DEFAULT_VALUE;
foreground_struct->foreground_prealpha = IPA_DEFAULT_VALUE;
foreground_struct->foreground_alpha_algorithm = IPA_FG_ALPHA_MODE_0;
foreground_struct->foreground_pf = FOREGROUND_PPF_ARGB8888;
foreground_struct->foreground_prered = IPA_DEFAULT_VALUE;
foreground_struct->foreground_pregreen = IPA_DEFAULT_VALUE;
foreground_struct->foreground_preblue = IPA_DEFAULT_VALUE;
foreground_struct->foreground_interlace_mode = DISABLE;
foreground_struct->foreground_efuv_memaddr = IPA_DEFAULT_VALUE;
}
/*!
\brief initialize foreground parameters
\param[in] foreground_struct: the data needed to initialize foreground
foreground_memaddr: foreground memory base address
foreground_lineoff: foreground line offset
foreground_prealpha: foreground pre-defined alpha value
foreground_alpha_algorithm: IPA_FG_ALPHA_MODE_0,IPA_FG_ALPHA_MODE_1,IPA_FG_ALPHA_MODE_2
foreground_pf: foreground pixel format(FOREGROUND_PPF_ARGB8888, FOREGROUND_PPF_RGB888, FOREGROUND_PPF_RGB565,
FOREGROUND_PPF_ARGB1555, FOREGROUND_PPF_ARGB4444, FOREGROUND_PPF_L8, FOREGROUND_PPF_AL44,
FOREGROUND_PPF_AL88, FOREGROUND_PPF_L4, FOREGROUND_PPF_A8, FOREGROUND_PPF_A4,
FOREGROUND_PPF_YUV444_1P, FOREGROUND_PPF_UYVY422_1P, FOREGROUND_PPF_VYUY422_1P,
FOREGROUND_PPF_YUV420_2P, FOREGROUND_PPF_YVU420_2P)
foreground_prered: foreground pre-defined red value
foreground_pregreen: foreground pre-defined green value
foreground_preblue: foreground pre-defined blue value
foreground_interlace_mode: ENABLE, DISABLE
foreground_efuv_memaddr: foreground even frame / UV memory base address
\param[out] none
\retval none
*/
void ipa_foreground_init(ipa_foreground_parameter_struct* foreground_struct)
{
FlagStatus tempflag = RESET;
if(RESET != (IPA_CTL & IPA_CTL_TEN)){
tempflag = SET;
/* reset the TEN in order to configure the following bits */
IPA_CTL &= ~IPA_CTL_TEN;
}
/* foreground memory base address configuration */
IPA_FMADDR &= ~(IPA_FMADDR_FMADDR);
IPA_FMADDR = foreground_struct->foreground_memaddr;
/* foreground line offset configuration */
IPA_FLOFF &= ~(IPA_FLOFF_FLOFF);
IPA_FLOFF = foreground_struct->foreground_lineoff;
/* foreground pixel format pre-defined alpha, alpha calculation algorithm configuration */
IPA_FPCTL &= ~(IPA_FPCTL_FPDAV | IPA_FPCTL_FAVCA | IPA_FPCTL_FPF | IPA_FPCTL_FIIMEN);
IPA_FPCTL |= (foreground_struct->foreground_prealpha << 24U);
IPA_FPCTL |= foreground_struct->foreground_alpha_algorithm;
IPA_FPCTL |= foreground_struct->foreground_pf;
if(ENABLE == foreground_struct->foreground_interlace_mode){
IPA_FPCTL |= IPA_FPCTL_FIIMEN;
}
/* foreground pre-defined red green blue configuration */
IPA_FPV &= ~(IPA_FPV_FPDRV | IPA_FPV_FPDGV| IPA_FPV_FPDBV);
IPA_FPV |= ((foreground_struct->foreground_prered << 16U) | (foreground_struct->foreground_pregreen << 8U)
| (foreground_struct->foreground_preblue));
/* foreground even frame / UV memory base address configuration */
IPA_EF_UV_MADDR &= ~(IPA_EF_UV_MADDR_EFUVMADDR);
IPA_EF_UV_MADDR = foreground_struct->foreground_efuv_memaddr;
if(SET == tempflag){
/* restore the state of TEN */
IPA_CTL |= IPA_CTL_TEN;
}
}
/*!
\brief initialize the structure of IPA background parameter struct with the default values, it is
suggested that call this function after an ipa_background_parameter_struct structure is defined
\param[in] none
\param[out] background_struct: the data needed to initialize background
\retval none
*/
void ipa_background_struct_para_init(ipa_background_parameter_struct* background_struct)
{
/* initialize the struct parameters with default values */
background_struct->background_memaddr = IPA_DEFAULT_VALUE;
background_struct->background_lineoff = IPA_DEFAULT_VALUE;
background_struct->background_prealpha = IPA_DEFAULT_VALUE;
background_struct->background_alpha_algorithm = IPA_BG_ALPHA_MODE_0;
background_struct->background_pf = BACKGROUND_PPF_ARGB8888;
background_struct->background_prered = IPA_DEFAULT_VALUE;
background_struct->background_pregreen = IPA_DEFAULT_VALUE;
background_struct->background_preblue = IPA_DEFAULT_VALUE;
}
/*!
\brief initialize background parameters
\param[in] background_struct: the data needed to initialize background
background_memaddr: background memory base address
background_lineoff: background line offset
background_prealpha: background pre-defined alpha value
background_alpha_algorithm: IPA_BG_ALPHA_MODE_0, IPA_FG_ALPHA_MODE_1, IPA_FG_ALPHA_MODE_2
background_pf: background pixel format(BACKGROUND_PPF_ARGB8888, BACKGROUND_PPF_RGB888, BACKGROUND_PPF_RGB565,
BACKGROUND_PPF_ARGB1555, BACKGROUND_PPF_ARGB4444, BACKGROUND_PPF_L8, BACKGROUND_PPF_AL44,
BACKGROUND_PPF_AL88, BACKGROUND_PPF_L4, BACKGROUND_PPF_A8, BACKGROUND_PPF_A4)
background_prered: background pre-defined red value
background_pregreen: background pre-defined green value
background_preblue: background pre-defined blue value
\param[out] none
\retval none
*/
void ipa_background_init(ipa_background_parameter_struct* background_struct)
{
FlagStatus tempflag = RESET;
if(RESET != (IPA_CTL & IPA_CTL_TEN)){
tempflag = SET;
/* reset the TEN in order to configure the following bits */
IPA_CTL &= ~IPA_CTL_TEN;
}
/* background memory base address configuration */
IPA_BMADDR &= ~(IPA_BMADDR_BMADDR);
IPA_BMADDR = background_struct->background_memaddr;
/* background line offset configuration */
IPA_BLOFF &= ~(IPA_BLOFF_BLOFF);
IPA_BLOFF = background_struct->background_lineoff;
/* background pixel format pre-defined alpha, alpha calculation algorithm configuration */
IPA_BPCTL &= ~(IPA_BPCTL_BPDAV | IPA_BPCTL_BAVCA | IPA_BPCTL_BPF);
IPA_BPCTL |= (background_struct->background_prealpha << 24U);
IPA_BPCTL |= background_struct->background_alpha_algorithm;
IPA_BPCTL |= background_struct->background_pf;
/* background pre-defined red green blue configuration */
IPA_BPV &= ~(IPA_BPV_BPDRV|IPA_BPV_BPDGV | IPA_BPV_BPDBV);
IPA_BPV |= ((background_struct->background_prered << 16U) | (background_struct->background_pregreen << 8U)
| (background_struct->background_preblue));
if(SET == tempflag){
/* restore the state of TEN */
IPA_CTL |= IPA_CTL_TEN;
}
}
/*!
\brief initialize the structure of IPA destination parameter struct with the default values, it is
suggested that call this function after an ipa_destination_parameter_struct structure is defined
\param[in] none
\param[out] destination_struct: the data needed to initialize destination parameter
\retval none
*/
void ipa_destination_struct_para_init(ipa_destination_parameter_struct* destination_struct)
{
/* initialize the struct parameters with default values */
destination_struct->destination_pf = IPA_DPF_ARGB8888;
destination_struct->destination_lineoff = IPA_DEFAULT_VALUE;
destination_struct->destination_prealpha = IPA_DEFAULT_VALUE;
destination_struct->destination_prered = IPA_DEFAULT_VALUE;
destination_struct->destination_pregreen = IPA_DEFAULT_VALUE;
destination_struct->destination_preblue = IPA_DEFAULT_VALUE;
destination_struct->destination_memaddr = IPA_DEFAULT_VALUE;
destination_struct->image_width = IPA_DEFAULT_VALUE;
destination_struct->image_height = IPA_DEFAULT_VALUE;
destination_struct->image_rotate = DESTINATION_ROTATE_0;
destination_struct->image_hor_decimation = DESTINATION_HORDECIMATE_DISABLE;
destination_struct->image_ver_decimation = DESTINATION_VERDECIMATE_DISABLE;
destination_struct->image_bilinear_xscale = IPA_DEFAULT_SCALE;
destination_struct->image_bilinear_yscale = IPA_DEFAULT_SCALE;
destination_struct->image_scaling_width = IPA_DEFAULT_VALUE;
destination_struct->image_scaling_height = IPA_DEFAULT_VALUE;
}
/*!
\brief initialize destination parameters
\param[in] destination_struct: the data needed to initialize destination parameters
destination_pf: IPA_DPF_ARGB8888, IPA_DPF_RGB888, IPA_DPF_RGB565, IPA_DPF_ARGB1555,
IPA_DPF_ARGB4444, refer to ipa_dpf_enum
destination_lineoff: destination line offset
destination_prealpha: destination pre-defined alpha value
destination_prered: destination pre-defined red value
destination_pregreen: destination pre-defined green value
destination_preblue: destination pre-defined blue value
destination_memaddr: destination memory base address
image_width: width of the image to be processed
image_height: height of the image to be processed
image_rotate: DESTINATION_ROTATE_0, DESTINATION_ROTATE_90,
DESTINATION_ROTATE_180, DESTINATION_ROTATE_270
image_hor_decimation: DESTINATION_HORDECIMATE_DISABLE, DESTINATION_HORDECIMATE_2,
DESTINATION_HORDECIMATE_4, DESTINATION_HORDECIMATE_8
image_ver_decimation: DESTINATION_VERDECIMATE_DISABLE, DESTINATION_VERDECIMATE_2,
DESTINATION_VERDECIMATE_4, DESTINATION_VERDECIMATE_8
image_bilinear_xscale: x scaling factor
image_bilinear_yscale: y scaling factor
image_scaling_width: width of the image after scaling
image_scaling_height: height of the image after scaling
\param[out] none
\retval none
*/
void ipa_destination_init(ipa_destination_parameter_struct* destination_struct)
{
uint32_t destination_pixelformat;
FlagStatus tempflag = RESET;
if(RESET != (IPA_CTL & IPA_CTL_TEN)){
tempflag = SET;
/* reset the TEN in order to configure the following bits */
IPA_CTL &= ~IPA_CTL_TEN;
}
/* destination pixel format, interlace sampling method and rotation configuration */
IPA_DPCTL &= ~(IPA_DPCTL_DPF | IPA_DPCTL_ROT | IPA_DPCTL_HORDEC | IPA_DPCTL_VERDEC);
IPA_DPCTL = (destination_struct->destination_pf |
destination_struct->image_rotate |
destination_struct->image_hor_decimation |
destination_struct->image_ver_decimation);
destination_pixelformat = destination_struct->destination_pf;
/* destination pixel format ARGB8888 */
switch(destination_pixelformat){
case IPA_DPF_ARGB8888:
IPA_DPV &= ~(IPA_DPV_DPDBV_0 | (IPA_DPV_DPDGV_0) | (IPA_DPV_DPDRV_0) | (IPA_DPV_DPDAV_0));
IPA_DPV = (destination_struct->destination_preblue | (destination_struct->destination_pregreen << 8U)
| (destination_struct->destination_prered << 16U)
| (destination_struct->destination_prealpha << 24U));
break;
/* destination pixel format RGB888 */
case IPA_DPF_RGB888:
IPA_DPV &= ~(IPA_DPV_DPDBV_1 | (IPA_DPV_DPDGV_1) | (IPA_DPV_DPDRV_1));
IPA_DPV = (destination_struct->destination_preblue | (destination_struct->destination_pregreen << 8U)
| (destination_struct->destination_prered << 16U));
break;
/* destination pixel format RGB565 */
case IPA_DPF_RGB565:
IPA_DPV &= ~(IPA_DPV_DPDBV_2 | (IPA_DPV_DPDGV_2) | (IPA_DPV_DPDRV_2));
IPA_DPV = (destination_struct->destination_preblue | (destination_struct->destination_pregreen << 5U)
| (destination_struct->destination_prered << 11U));
break;
/* destination pixel format ARGB1555 */
case IPA_DPF_ARGB1555:
IPA_DPV &= ~(IPA_DPV_DPDBV_3 | (IPA_DPV_DPDGV_3) | (IPA_DPV_DPDRV_3)|(IPA_DPV_DPDAV_3));
IPA_DPV = (destination_struct->destination_preblue | (destination_struct->destination_pregreen << 5U)
| (destination_struct->destination_prered << 10U)
| (destination_struct->destination_prealpha << 15U));
break;
/* destination pixel format ARGB4444 */
case IPA_DPF_ARGB4444:
IPA_DPV &= ~(IPA_DPV_DPDBV_4 | (IPA_DPV_DPDGV_4) | (IPA_DPV_DPDRV_4)|(IPA_DPV_DPDAV_4));
IPA_DPV = (destination_struct->destination_preblue | (destination_struct->destination_pregreen << 4U)
| (destination_struct->destination_prered << 8U)
| (destination_struct->destination_prealpha << 12U));
break;
default:
break;
}
/* destination memory base address configuration */
IPA_DMADDR &= ~(IPA_DMADDR_DMADDR);
IPA_DMADDR = destination_struct->destination_memaddr;
/* destination line offset configuration */
IPA_DLOFF &= ~(IPA_DLOFF_DLOFF);
IPA_DLOFF = destination_struct->destination_lineoff;
/* image size configuration */
IPA_IMS &= ~(IPA_IMS_HEIGHT | IPA_IMS_WIDTH);
IPA_IMS |= ((destination_struct->image_width << 16U) | (destination_struct->image_height));
/* xscale and yscale configuration */
IPA_BSCTL &= ~(IPA_BSCTL_XSCALE | IPA_BSCTL_YSCALE);
IPA_BSCTL = ((destination_struct->image_bilinear_xscale & IPA_BSCTL_XSCALE) |
((uint32_t)(destination_struct->image_bilinear_yscale << 16U) & IPA_BSCTL_YSCALE));
/* image size after scaling configuration */
IPA_DIMS &= ~(IPA_DIMS_DWIDTH | IPA_DIMS_DHEIGHT);
IPA_DIMS = (destination_struct->image_scaling_height & IPA_DIMS_DHEIGHT) |
((uint32_t)((destination_struct->image_scaling_width << 16U) & IPA_DIMS_DWIDTH));
if(SET == tempflag){
/* restore the state of TEN */
IPA_CTL |= IPA_CTL_TEN;
}
}
/*!
\brief initialize IPA foreground LUT parameters
\param[in] fg_lut_num: foreground LUT number of pixel
\param[in] fg_lut_pf: foreground LUT pixel format(IPA_LUT_PF_ARGB8888, IPA_LUT_PF_RGB888)
\param[in] fg_lut_addr: foreground LUT memory base address
\param[out] none
\retval none
*/
void ipa_foreground_lut_init(uint8_t fg_lut_num, uint8_t fg_lut_pf, uint32_t fg_lut_addr)
{
FlagStatus tempflag = RESET;
if(RESET != (IPA_FPCTL & IPA_FPCTL_FLLEN)){
tempflag = SET;
/* reset the FLLEN in order to configure the following bits */
IPA_FPCTL &= ~IPA_FPCTL_FLLEN;
}
/* foreground LUT number of pixel configuration */
IPA_FPCTL |= ((uint32_t)fg_lut_num << 8U);
/* foreground LUT pixel format configuration */
if(IPA_LUT_PF_RGB888 == fg_lut_pf){
IPA_FPCTL |= IPA_FPCTL_FLPF;
}else if(IPA_LUT_PF_ARGB8888 == fg_lut_pf){
IPA_FPCTL &= ~(IPA_FPCTL_FLPF);
}else{
}
/* foreground LUT memory base address configuration */
IPA_FLMADDR &= ~(IPA_FLMADDR_FLMADDR);
IPA_FLMADDR = fg_lut_addr;
if(SET == tempflag){
/* restore the state of FLLEN */
IPA_FPCTL |= IPA_FPCTL_FLLEN;
}
}
/*!
\brief initialize IPA background LUT parameters
\param[in] bg_lut_num: background LUT number of pixel
\param[in] bg_lut_pf: background LUT pixel format(IPA_LUT_PF_ARGB8888, IPA_LUT_PF_RGB888)
\param[in] bg_lut_addr: background LUT memory base address
\param[out] none
\retval none
*/
void ipa_background_lut_init(uint8_t bg_lut_num, uint8_t bg_lut_pf, uint32_t bg_lut_addr)
{
FlagStatus tempflag = RESET;
if(RESET != (IPA_BPCTL & IPA_BPCTL_BLLEN)){
tempflag = SET;
/* reset the BLLEN in order to configure the following bits */
IPA_BPCTL &= ~IPA_BPCTL_BLLEN;
}
/* background LUT number of pixel configuration */
IPA_BPCTL |= ((uint32_t)bg_lut_num << 8U);
/* background LUT pixel format configuration */
if(IPA_LUT_PF_RGB888 == bg_lut_pf){
IPA_BPCTL |= IPA_BPCTL_BLPF;
}else if(IPA_LUT_PF_ARGB8888 == bg_lut_pf){
IPA_BPCTL &= ~(IPA_BPCTL_BLPF);
}else{
}
/* background LUT memory base address configuration */
IPA_BLMADDR &= ~(IPA_BLMADDR_BLMADDR);
IPA_BLMADDR = bg_lut_addr;
if(SET == tempflag){
/* restore the state of BLLEN */
IPA_BPCTL |= IPA_BPCTL_BLLEN;
}
}
/*!
\brief configure IPA line mark
\param[in] line_num: line number
\param[out] none
\retval none
*/
void ipa_line_mark_config(uint16_t line_num)
{
IPA_LM &= ~(IPA_LM_LM);
IPA_LM = line_num;
}
/*!
\brief inter-timer enable or disable
\param[in] timer_cfg: IPA_INTER_TIMER_ENABLE,IPA_INTER_TIMER_DISABLE
\param[out] none
\retval none
*/
void ipa_inter_timer_config(uint8_t timer_cfg)
{
if(IPA_INTER_TIMER_ENABLE == timer_cfg){
/* inter-timer enable */
IPA_ITCTL |= IPA_ITCTL_ITEN;
}else if(IPA_INTER_TIMER_DISABLE == timer_cfg){
/* inter-timer disable */
IPA_ITCTL &= ~(IPA_ITCTL_ITEN);
}else{
/* do nothing */
}
}
/*!
\brief configure the number of clock cycles interval
\param[in] clk_num: the number of clock cycles
\param[out] none
\retval none
*/
void ipa_interval_clock_num_config(uint8_t clk_num)
{
/* NCCI[7:0] bits have no meaning if ITEN is '0' */
IPA_ITCTL &= ~(IPA_ITCTL_NCCI);
IPA_ITCTL |= ((uint32_t)clk_num << 8U);
}
/*!
\brief configure the color space conversion parameter
\param[out] conversion_struct: the data needed to configure color conversion parameters
\param[in] ipa_colorspace_enum: the color space
IPA_COLORSPACE_YUV: using default YUV parameter to initialization struct
IPA_COLORSPACE_YCBCR: using default YCbCr parameter to initialization struct
\retval none
*/
void ipa_color_conversion_struct_para_init(ipa_conversion_parameter_struct* conversion_struct, ipa_colorspace_enum colorspace)
{
if(IPA_COLORSPACE_YUV == colorspace){
/* initialize the struct parameters with default YUV conversion values */
conversion_struct->color_space = IPA_COLORSPACE_YUV;
conversion_struct->y_offset = IPA_DEFAULT_YUV_CONV_YOFFSET;
conversion_struct->uv_offset = IPA_DEFAULT_YUV_CONV_UVOFFSET;
conversion_struct->coef_c0 = IPA_DEFAULT_YUV_CONV_C0OFFSET;
conversion_struct->coef_c1 = IPA_DEFAULT_YUV_CONV_C1OFFSET;
conversion_struct->coef_c2 = IPA_DEFAULT_YUV_CONV_C2OFFSET;
conversion_struct->coef_c3 = IPA_DEFAULT_YUV_CONV_C3OFFSET;
conversion_struct->coef_c4 = IPA_DEFAULT_YUV_CONV_C4OFFSET;
}else if(IPA_COLORSPACE_YCBCR == colorspace){
/* initialize the struct parameters with default YCbCr conversion values */
conversion_struct->color_space = IPA_COLORSPACE_YCBCR;
conversion_struct->y_offset = IPA_DEFAULT_YCBCR_CONV_YOFFSET;
conversion_struct->uv_offset = IPA_DEFAULT_YCBCR_CONV_UVOFFSET;
conversion_struct->coef_c0 = IPA_DEFAULT_YCBCR_CONV_C0OFFSET;
conversion_struct->coef_c1 = IPA_DEFAULT_YCBCR_CONV_C1OFFSET;
conversion_struct->coef_c2 = IPA_DEFAULT_YCBCR_CONV_C2OFFSET;
conversion_struct->coef_c3 = IPA_DEFAULT_YCBCR_CONV_C3OFFSET;
conversion_struct->coef_c4 = IPA_DEFAULT_YCBCR_CONV_C4OFFSET;
}else{
/* do nothing */
}
}
/*!
\brief configure the color space conversion parameter
\param[in] conversion_struct: the data needed to configure color conversion parameters
color_space: IPA_COLORSPACE_YUV, IPA_COLORSPACE_YCBCR
y_offset: offset implicit in the Y data
uv_offset: offset implicit in the UV data
coef_c0: Y multiplier coefficient
coef_c1: V/Cr red multiplier coefficient
coef_c2: V/Cr green multiplier coefficient
coef_c3: U/Cb green multiplier coefficient
coef_c4: U/Cb blue multiplier coefficient
\param[out] none
\retval none
*/
void ipa_color_conversion_config(ipa_conversion_parameter_struct* conversion_struct)
{
FlagStatus tempflag = RESET;
if(RESET != (IPA_CTL & IPA_CTL_TEN)){
tempflag = SET;
/* reset the TEN in order to configure the following bits */
IPA_CTL &= ~IPA_CTL_TEN;
}
/* Y offset, UV offset, compliment Y multiplier configuration */
IPA_CSCC_CFG0 &= ~(IPA_CSCC_CFG0_YOFF | IPA_CSCC_CFG0_UVOFF | IPA_CSCC_CFG0_C0);
IPA_CSCC_CFG0 |= (((conversion_struct->y_offset) & IPA_CSCC_CFG0_YOFF) |
((uint32_t)(conversion_struct->uv_offset << 9U) & IPA_CSCC_CFG0_UVOFF) |
((uint32_t)(conversion_struct->coef_c0 << 18U) & IPA_CSCC_CFG0_C0));
/* red V/Cr multiplier, blue U/Cb multiplier configuration */
IPA_CSCC_CFG1 &= ~(IPA_CSCC_CFG1_C1 | IPA_CSCC_CFG1_C4);
IPA_CSCC_CFG1 |= ((conversion_struct->coef_c4 & IPA_CSCC_CFG1_C4) |
((uint32_t)(conversion_struct->coef_c1 << 16U) & IPA_CSCC_CFG1_C1));
/* green V/Cr multiplier coefficient, green U/Cb multiplier configuration */
IPA_CSCC_CFG2 &= ~(IPA_CSCC_CFG2_C2 | IPA_CSCC_CFG2_C3);
IPA_CSCC_CFG2 |= ((conversion_struct->coef_c3 & IPA_CSCC_CFG2_C3) |
((uint32_t)(conversion_struct->coef_c2 << 16U) & IPA_CSCC_CFG2_C2));
if(IPA_COLORSPACE_YUV == conversion_struct->color_space){
/* convert YUV to RGB */
IPA_CSCC_CFG0 &= ~(IPA_CSCC_CFG0_CONVMOD);
}else{
/* convert YCbCr to RGB */
IPA_CSCC_CFG0 |= IPA_CSCC_CFG0_CONVMOD;
}
if(SET == tempflag){
/* restore the state of TEN */
IPA_CTL |= IPA_CTL_TEN;
}
}
/*!
\brief configure IPA foreground scaling, including horizontal/vertical pre-decimation factors and X/Y scaling factors
\param[in] horizontal_decimation: horizontal scaling value
only one parameter can be selected which is shown as below:
\arg DESTINATION_HORDECIMATE_DISABLE: disable horizontal decimate
\arg DESTINATION_HORDECIMATE_2: horizontal decimated by 2
\arg DESTINATION_HORDECIMATE_4: horizontal decimated by 4
\arg DESTINATION_HORDECIMATE_8: horizontal decimated by 8
\param[in] vertical_decimation: vertical scaling value
only one parameter can be selected which is shown as below:
\arg DESTINATION_VERDECIMATE_DISABLE: disable vertical decimate
\arg DESTINATION_VERDECIMATE_2: vertical decimated by 2
\arg DESTINATION_VERDECIMATE_4: vertical decimated by 4
\arg DESTINATION_VERDECIMATE_8: vertical decimated by 8
\param[in] image_scaling_width: image scaling factor of width
\param[in] image_scaling_height: image scaling factor of height
\param[out] none
\retval none
*/
void ipa_foreground_scaling_config(uint32_t horizontal_decimation, uint32_t vertical_decimation, uint32_t image_scaling_width, uint32_t image_scaling_height)
{
/* configure decimation filter */
IPA_DPCTL &= ~(uint32_t)(IPA_DPCTL_VERDEC | IPA_DPCTL_HORDEC);
IPA_DPCTL |= (horizontal_decimation | vertical_decimation);
/* XScaling and YScaling configuration */
IPA_BSCTL &= ~(IPA_BSCTL_XSCALE | IPA_BSCTL_YSCALE);
IPA_BSCTL = ((image_scaling_width & IPA_BSCTL_XSCALE) |
((uint32_t)(image_scaling_height << 16U) & IPA_BSCTL_YSCALE));
}
/*!
\brief configure IPA destination scaling, including width/height of image to be processed
\param[in] dest_scaling_width: width of destination image after scaling
\param[in] dest_scaling_height: height of destination image after scaling
\param[out] none
\retval none
*/
void ipa_destination_scaling_config(uint32_t dest_scaling_width, uint32_t dest_scaling_height)
{
IPA_DIMS &= ~(IPA_DIMS_DWIDTH | IPA_DIMS_DHEIGHT);
IPA_DIMS = (dest_scaling_height & IPA_DIMS_DHEIGHT) |
((uint32_t)((dest_scaling_width << 16U) & IPA_DIMS_DWIDTH));
}
/*!
\brief get IPA flag status in IPA_INTF register
\param[in] flag: IPA flags
one or more parameters can be selected which are shown as below:
\arg IPA_FLAG_TAE: transfer access error interrupt flag
\arg IPA_FLAG_FTF: full transfer finish interrupt flag
\arg IPA_FLAG_TLM: transfer line mark interrupt flag
\arg IPA_FLAG_LAC: LUT access conflict interrupt flag
\arg IPA_FLAG_LLF: LUT loading finish interrupt flag
\arg IPA_FLAG_WCF: wrong configuration interrupt flag
\param[out] none
\retval none
*/
FlagStatus ipa_flag_get(uint32_t flag)
{
if(RESET != (IPA_INTF & flag)){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear IPA flag in IPA_INTF register
\param[in] flag: IPA flags
one or more parameters can be selected which are shown as below:
\arg IPA_FLAG_TAE: transfer access error interrupt flag
\arg IPA_FLAG_FTF: full transfer finish interrupt flag
\arg IPA_FLAG_TLM: transfer line mark interrupt flag
\arg IPA_FLAG_LAC: LUT access conflict interrupt flag
\arg IPA_FLAG_LLF: LUT loading finish interrupt flag
\arg IPA_FLAG_WCF: wrong configuration interrupt flag
\param[out] none
\retval none
*/
void ipa_flag_clear(uint32_t flag)
{
IPA_INTC |= (flag);
}
/*!
\brief enable IPA interrupt
\param[in] int_flag: IPA interrupt flags
one or more parameters can be selected which are shown as below:
\arg IPA_INT_TAE: transfer access error interrupt
\arg IPA_INT_FTF: full transfer finish interrupt
\arg IPA_INT_TLM: transfer line mark interrupt
\arg IPA_INT_LAC: LUT access conflict interrupt
\arg IPA_INT_LLF: LUT loading finish interrupt
\arg IPA_INT_WCF: wrong configuration interrupt
\param[out] none
\retval none
*/
void ipa_interrupt_enable(uint32_t int_flag)
{
IPA_CTL |= (int_flag);
}
/*!
\brief disable IPA interrupt
\param[in] int_flag: IPA interrupt flags
one or more parameters can be selected which are shown as below:
\arg IPA_INT_TAE: transfer access error interrupt
\arg IPA_INT_FTF: full transfer finish interrupt
\arg IPA_INT_TLM: transfer line mark interrupt
\arg IPA_INT_LAC: LUT access conflict interrupt
\arg IPA_INT_LLF: LUT loading finish interrupt
\arg IPA_INT_WCF: wrong configuration interrupt
\param[out] none
\retval none
*/
void ipa_interrupt_disable(uint32_t int_flag)
{
IPA_CTL &= ~(int_flag);
}
/*!
\brief get IPA interrupt flag
\param[in] int_flag: IPA interrupt flag flags
one or more parameters can be selected which are shown as below:
\arg IPA_INT_FLAG_TAE: transfer access error interrupt flag
\arg IPA_INT_FLAG_FTF: full transfer finish interrupt flag
\arg IPA_INT_FLAG_TLM: transfer line mark interrupt flag
\arg IPA_INT_FLAG_LAC: LUT access conflict interrupt flag
\arg IPA_INT_FLAG_LLF: LUT loading finish interrupt flag
\arg IPA_INT_FLAG_WCF: wrong configuration interrupt flag
\param[out] none
\retval none
*/
FlagStatus ipa_interrupt_flag_get(uint32_t int_flag)
{
if(RESET != (IPA_INTF & int_flag)){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear IPA interrupt flag
\param[in] int_flag: IPA interrupt flag flags
one or more parameters can be selected which are shown as below:
\arg IPA_INT_FLAG_TAE: transfer access error interrupt flag
\arg IPA_INT_FLAG_FTF: full transfer finish interrupt flag
\arg IPA_INT_FLAG_TLM: transfer line mark interrupt flag
\arg IPA_INT_FLAG_LAC: LUT access conflict interrupt flag
\arg IPA_INT_FLAG_LLF: LUT loading finish interrupt flag
\arg IPA_INT_FLAG_WCF: wrong configuration interrupt flag
\param[out] none
\retval none
*/
void ipa_interrupt_flag_clear(uint32_t int_flag)
{
IPA_INTC |= (int_flag);
}
@@ -0,0 +1,332 @@
/*!
\file gd32h7xx_lpdts.c
\brief LPDTS driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_lpdts.h"
/* LPDTS high threshold value offset macro */
#define LPDTS_IT_INTHT_OFFSET ((uint32_t)16U)
/* sampling time offset macro */
#define LPDTS_CFG_SPT_OFFSET ((uint32_t)16U)
/* engineering value offset macro */
#define LPDTS_SDATA_VAL_OFFSET ((uint32_t)16U)
/* the T0 temperature macro */
#define LPDTS_T0_TMP_VAL ((uint32_t)25U)
/*!
\brief reset the LPDTS registers
\param[in] none
\param[out] none
\retval none
*/
void lpdts_deinit(void)
{
rcu_periph_reset_enable(RCU_LPDTSRST);
rcu_periph_reset_disable(RCU_LPDTSRST);
}
/*!
\brief initialize the parameters of LPDTS struct with the default values
\param[in] none
\param[out] init_struct: the initialization data needed to initialize LPDTS
\retval none
*/
void lpdts_struct_para_init(lpdts_parameter_struct *init_struct)
{
/* set the struct with the default values */
init_struct->ref_clock = REF_PCLK;
init_struct->trigger_input = NO_HARDWARE_TRIGGER;
init_struct->sampling_time = SPT_CLOCK_15;
}
/*!
\brief initialize the LPDTS
\param[in] init_struct: the initialization data needed to initialize LPDTS_CFG
ref_clock: REF_PCLK, REF_LXTAL
trigger_input: NO_HARDWARE_TRIGGER, LPDTS_TRG
sampling_time: SPT_CLOCK_x(x=1..15)
\param[out] none
\retval none
*/
void lpdts_init(lpdts_parameter_struct *init_struct)
{
uint32_t reg;
/* configure the LPDTS_CFG */
reg = LPDTS_CFG;
reg &= ~(LPDTS_CFG_REFSEL | LPDTS_CFG_ITSEL | LPDTS_CFG_SPT);
reg |= (init_struct->ref_clock | init_struct->trigger_input | init_struct->sampling_time);
LPDTS_CFG = reg;
}
/*!
\brief enable LPDTS temperature sensor
\param[in] none
\param[out] none
\retval none
*/
void lpdts_enable(void)
{
LPDTS_CFG |= LPDTS_CFG_TSEN;
}
/*!
\brief disable LPDTS temperature sensor
\param[in] none
\param[out] none
\retval none
*/
void lpdts_disable(void)
{
LPDTS_CFG &= ~LPDTS_CFG_TSEN;
}
/*!
\brief enable LPDTS software trigger
\param[in] none
\param[out] none
\retval none
*/
void lpdts_soft_trigger_enable(void)
{
LPDTS_CFG |= LPDTS_CFG_TRGS;
}
/*!
\brief disable LPDTS software trigger
\param[in] none
\param[out] none
\retval none
*/
void lpdts_soft_trigger_disable(void)
{
LPDTS_CFG &= ~LPDTS_CFG_TRGS;
}
/*!
\brief configure LPDTS high threshold value
\param[in] value: high threshold value(0~65535)
\param[out] none
\retval none
*/
void lpdts_high_threshold_set(uint16_t value)
{
uint32_t reg;
/* configure the LPDTS_IT */
reg = LPDTS_IT;
reg &= ~LPDTS_IT_INTHT;
reg |= (uint32_t)value << LPDTS_IT_INTHT_OFFSET;
LPDTS_IT = reg;
}
/*!
\brief configure LPDTS low threshold value
\param[in] value: low threshold value(0~65535)
\param[out] none
\retval none
*/
void lpdts_low_threshold_set(uint16_t value)
{
uint32_t reg;
/* configure the LPDTS_IT */
reg = LPDTS_IT;
reg &= ~LPDTS_IT_INTLT;
reg |= (uint32_t)value;
LPDTS_IT = reg;
}
/*!
\brief configure LPDTS reference clock selection
\param[in] source: reference clock source
only one parameter can be selected which is shown as below:
\arg REF_PCLK: high speed reference clock (PCLK)
\arg REF_LXTAL: low speed reference clock (LXTAL)
\param[out] none
\retval none
*/
void lpdts_ref_clock_source_config(uint32_t source)
{
uint32_t reg;
/* configure the LPDTS_CFG */
reg = LPDTS_CFG;
reg &= ~LPDTS_CFG_REFSEL;
reg |= source;
LPDTS_CFG = reg;
}
/*!
\brief get temperature from LPDTS
\param[in] none
\param[out] none
\retval temperature: temperature in deg C
*/
int32_t lpdts_temperature_get(void)
{
uint32_t freq;
uint32_t count;
uint32_t t0;
uint32_t t0_freq;
uint32_t ramp_coeff;
uint32_t reg_cfg;
int32_t temperature;
/* get the total number of samples */
count = (LPDTS_DATA & LPDTS_DATA_COVAL);
/* get LPDTS_CFG configuration */
reg_cfg = LPDTS_CFG;
/* get the module frequency on Hz */
if((reg_cfg & LPDTS_CFG_REFSEL) == LPDTS_CFG_REFSEL) {
freq = (LXTAL_VALUE * count) / (2U * ((reg_cfg & LPDTS_CFG_SPT) >> LPDTS_CFG_SPT_OFFSET));
} else {
freq = (2U * rcu_clock_freq_get(CK_APB1) / count) * ((reg_cfg & LPDTS_CFG_SPT) >> LPDTS_CFG_SPT_OFFSET);
}
/* read factory settings */
t0 = (LPDTS_SDATA & LPDTS_SDATA_VAL) >> LPDTS_SDATA_VAL_OFFSET;
if(t0 == 0U) {
t0 = LPDTS_T0_TMP_VAL;
}
/* get the T0 frequency on Hz */
t0_freq = (LPDTS_SDATA & LPDTS_SDATA_FREQ) * 100U;
/* get the ramp coefficient for the temperature sensor on deg C/Hz */
ramp_coeff = LPDTS_RDATA & LPDTS_RDATA_RCVAL;
/* figure out the temperature deg C */
temperature = (int32_t)t0 + (((int32_t)freq - (int32_t)t0_freq) / (int32_t)ramp_coeff);
return temperature;
}
/*!
\brief get LPDTS flag
\param[in] flag: LPDTS ready flag
only one parameter can be selected which is shown as below:
\arg LPDTS_FLAG_TSR
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus lpdts_flag_get(uint32_t flag)
{
FlagStatus status = RESET;
if(LPDTS_STAT & flag) {
status = SET;
}
/* return the state of corresponding LPDTS flag */
return status;
}
/*!
\brief enable LPDTS interrupt
\param[in] interrupt: the LPDTS interrupt
one or more parameters can be selected which is shown as below:
\arg LPDTS_INT_EM
\arg LPDTS_INT_LT
\arg LPDTS_INT_HT
\arg LPDTS_INT_EMA
\arg LPDTS_INT_LTA
\arg LPDTS_INT_HTA
\param[out] none
\retval none
*/
void lpdts_interrupt_enable(uint32_t interrupt)
{
LPDTS_INTEN |= interrupt;
}
/*!
\brief disable LPDTS interrupt
\param[in] interrupt: the LPDTS interrupt
one or more parameters can be selected which is shown as below:
\arg LPDTS_INT_EM
\arg LPDTS_INT_LT
\arg LPDTS_INT_HT
\arg LPDTS_INT_EMA
\arg LPDTS_INT_LTA
\arg LPDTS_INT_HTA
\param[out] none
\retval none
*/
void lpdts_interrupt_disable(uint32_t interrupt)
{
LPDTS_INTEN &= ~interrupt;
}
/*!
\brief get LPDTS interrupt flag
\param[in] flag: LPDTS interrupt flag
only one parameter can be selected which is shown as below:
\arg LPDTS_INT_FLAG_EM
\arg LPDTS_INT_FLAG_LT
\arg LPDTS_INT_FLAG_HT
\arg LPDTS_INT_FLAG_EMA
\arg LPDTS_INT_FLAG_LTA
\arg LPDTS_INT_FLAG_HTA
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus lpdts_interrupt_flag_get(uint32_t flag)
{
FlagStatus status = RESET;
uint32_t state;
state = LPDTS_STAT;
if(state & flag) {
state = LPDTS_INTEN;
if(state & flag) {
status = SET;
}
}
/* return the state of corresponding LPDTS flag */
return status;
}
/*!
\brief clear the LPDTS interrupt flag
\param[in] flag: LPDTS flag
one or more parameter can be selected which is shown as below:
\arg LPDTS_INT_FLAG_EM
\arg LPDTS_INT_FLAG_LT
\arg LPDTS_INT_FLAG_HT
\arg LPDTS_INT_FLAG_EMA
\arg LPDTS_INT_FLAG_LTA
\arg LPDTS_INT_FLAG_HTA
\param[out] none
\retval none
*/
void lpdts_interrupt_flag_clear(uint32_t flag)
{
/* clear the flags */
LPDTS_INTC = flag;
}
@@ -0,0 +1,404 @@
/*!
\file gd32h7xx_mdio.c
\brief MDIO driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_mdio.h"
/*!
\brief reset MDIO
\param[in] none
\param[out] none
\retval none
*/
void mdio_deinit(void)
{
/* reset MDIO */
rcu_periph_reset_enable(RCU_MDIORST);
rcu_periph_reset_disable(RCU_MDIORST);
}
/*!
\brief reset MDIO block
\param[in] none
\param[out] none
\retval none
*/
void mdio_software_reset(void)
{
MDIO_CTL |= MDIO_CTL_SWRST;
}
/*!
\brief initialize MDIO for communication
\param[in] phy_size: PHY bit length
only one parameter can be selected which is shown as below:
\arg MDIO_PHY_BITS_3: PHY use 3 bits
\arg MDIO_PHY_BITS_5: PHY use 5 bits
\param[in] phy_softaddr: software provided PHYADR (0 - 31)
\param[in] phy_sel: PHYADR select
only one parameter can be selected which is shown as below:
\arg MDIO_PHYADR_HARDWARE: sets expected PHYADR = PHYPIN[4:0]
\arg MDIO_PHYADR_HW_SW_MIX(regval): sets Software address valid bits
\arg MDIO_PHYADR_SOFTWARE: sets expected PHYADR = PHYSW[4:0]
\arg other user defined value: 1 - 30
\param[in] devadd: device type
only one parameter can be selected which is shown as below:
\arg DEVADD_PMA_PMD: device type PMA/PMD
\arg DEVADD_WIS: device type WIS
\arg DEVADD_PCS: device type PCS
\arg DEVADD_PHY_XS: device type PHY XS
\arg DEVADD_DTE_XS: device type DTE XS
\param[out] none
\retval uint32_t: the PHYADR that the device will respond to 0 - 31
*/
uint32_t mdio_init(uint32_t phy_size, uint32_t phy_softaddr, uint32_t phy_sel, uint16_t devadd)
{
uint32_t phy_addr = 0U, phy_hard = 0U;
/* configure MDIO phy bit length */
MDIO_CTL &= ~MDIO_CTL_PHYB;
MDIO_CTL |= phy_size;
/* configure the PHYADR and DEVADD */
MDIO_CFG &= ~(MDIO_CFG_PHYSW | MDIO_CFG_EPHYSEL | MDIO_CFG_EDEVADD);
MDIO_CFG |= CFG_PHYSW(phy_softaddr) | CFG_EPHYSEL(phy_sel) | CFG_EDEVADD(devadd);
/* calculate the PHYADR that the device will respond to */
phy_hard = mdio_phy_pin_read();
phy_addr = (phy_hard & (~phy_sel)) | (phy_softaddr & phy_sel);
return phy_addr;
}
/*!
\brief configure MDIO phy bit length
\param[in] phy_bit: PHY bit length
only one parameter can be selected which is shown as below:
\arg MDIO_PHY_BITS_3: PHY use 3 bits
\arg MDIO_PHY_BITS_5: PHY use 5 bits
\param[out] none
\retval none
*/
void mdio_phy_length_config(uint32_t phy_bit)
{
MDIO_CTL &= ~MDIO_CTL_PHYB;
MDIO_CTL |= phy_bit;
}
/*!
\brief set the software PHYADR value
\param[in] phy_soft: software provided PHYADR (0 - 31)
\param[out] none
\retval none
*/
void mdio_soft_phyadr_set(uint32_t phy_soft)
{
MDIO_CFG &= ~MDIO_CFG_PHYSW;
MDIO_CFG |= CFG_PHYSW(phy_soft);
}
/*!
\brief select the expected frame field PHYADR
\param[in] phy_sel: PHYADR select
only one parameter can be selected which is shown as below:
\arg MDIO_PHYADR_HARDWARE: sets expected PHYADR = PHYPIN[4:0]
\arg MDIO_PHYADR_SOFTWARE: sets expected PHYADR = PHYSW[4:0]
\arg other user defined value: 1 - 30
\param[out] none
\retval none
*/
void mdio_framefield_phyadr_config(uint32_t phy_sel)
{
MDIO_CFG &= ~MDIO_CFG_EPHYSEL;
MDIO_CFG |= CFG_EPHYSEL(phy_sel);
}
/*!
\brief configure the expected frame field DEVADD
\param[in] type: device type
only one parameter can be selected which is shown as below:
\arg DEVADD_PMA_PMD: device type PMA/PMD
\arg DEVADD_WIS: device type WIS
\arg DEVADD_PCS: device type PCS
\arg DEVADD_PHY_XS: device type PHY XS
\arg DEVADD_DTE_XS: device type DTE XS
\param[out] none
\retval none
*/
void mdio_framefield_devadd_config(uint16_t type)
{
MDIO_CFG &= ~MDIO_CFG_EDEVADD;
MDIO_CFG |= CFG_EDEVADD(type);
}
/*!
\brief read the hardware PRTADR[4:0] value
\param[in] none
\param[out] none
\retval uint32_t: 0x0-0x1F
*/
uint32_t mdio_phy_pin_read(void)
{
return GET_PIN_PHYPIN(MDIO_PIN);
}
/*!
\brief configure the expected frame bit timeout
\param[in] timeout: timeout counter among frame bits (0 - 0xFFFF)
\param[out] none
\retval none
*/
void mdio_timeout_config(uint16_t timeout)
{
MDIO_TO &= ~MDIO_TO_TOCNT;
MDIO_TO |= TO_TOCNT(timeout);
}
/*!
\brief enable MDIO frame bit timeout
\param[in] none
\param[out] none
\retval none
*/
void mdio_timeout_enable(void)
{
MDIO_TO |= MDIO_TO_TOEN;
}
/*!
\brief disable MDIO frame bit timeout
\param[in] none
\param[out] none
\retval none
*/
void mdio_timeout_disable(void)
{
MDIO_TO &= ~MDIO_TO_TOEN;
}
/*!
\brief read the received frame field OP
\param[in] none
\param[out] none
\retval uint16_t: 0x0-0x11
*/
uint16_t mdio_op_receive(void)
{
return (uint16_t)(GET_RFRM_ROP(MDIO_RFRM));
}
/*!
\brief read the received frame field PHYADR
\param[in] none
\param[out] none
\retval uint16_t: 0x0-0x1F
*/
uint16_t mdio_phyadr_receive(void)
{
return (uint16_t)(GET_RFRM_RPHY(MDIO_RFRM));
}
/*!
\brief read the received frame field DEVADD
\param[in] none
\param[out] none
\retval uint16_t: 0x0-0x1F
*/
uint16_t mdio_devadd_receive(void)
{
return (uint16_t)(GET_RFRM_RDEV(MDIO_RFRM));
}
/*!
\brief read the received frame field TA
\param[in] none
\param[out] none
\retval uint16_t: 0x0-0x11
*/
uint16_t mdio_ta_receive(void)
{
return (uint16_t)(GET_RFRM_RTA(MDIO_RFRM));
}
/*!
\brief read the received frame field DATA
\param[in] none
\param[out] none
\retval uint16_t: 0x0-0xFFFF
*/
uint16_t mdio_data_receive(void)
{
return (uint16_t)(GET_RDATA_RDATA(MDIO_RDATA));
}
/*!
\brief read the received frame field ADDRESS
\param[in] none
\param[out] none
\retval uint16_t: 0x0-0xFFFF
*/
uint16_t mdio_address_receive(void)
{
return (uint16_t)(GET_RADDR_RADDR(MDIO_RADDR));
}
/*!
\brief transmit the frame field DATA
\param[in] data: data to put in a read or post read increment address frame for transmission (0x0-0xFFFF)
\param[out] none
\retval none
*/
void mdio_data_transmit(uint16_t data)
{
MDIO_TDATA = (uint32_t)data;
}
/*!
\brief get the flag status of the frame
\param[in] flag: MDIO flag
only one parameter can be selected which is shown as below:
\arg MDIO_FLAG_WRFRM: a write data frame flag status
\arg MDIO_FLAG_ADDRFRM: an address frame flag status
\arg MDIO_FLAG_RDINCFRM: a post read increment address frame flag status
\arg MDIO_FLAG_RDFRM: a read data frame flag status
\arg MDIO_FLAG_DEVM: a DEVADD match frame flag status
\arg MDIO_FLAG_DEVNM: a DEVADD nonmatch frame flag status
\arg MDIO_FLAG_PHYM: a PHYADR match frame flag status
\arg MDIO_FLAG_PHYNM: a PHYADR nonmatch frame flag status
\arg MDIO_FLAG_TANM: a TA nonmatch frame flag status
\arg MDIO_FLAG_TIMEOUT: timeout flag
\arg MDIO_FLAG_TX_UNDERRUN: transmit underrun flag
\arg MDIO_FLAG_RX_OVERRUN: receive overrun flag
\arg MDIO_FLAG_RBNE: read data buffer not empty flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus mdio_flag_get(uint32_t flag)
{
__IO uint32_t reg = 0U;
reg = MDIO_STAT;
if(RESET != (reg & flag)){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear the flag status
\param[in] flag: MDIO flag
one or more parameters can be selected which are shown as below:
\arg MDIO_FLAG_WRFRM: a write data frame flag status
\arg MDIO_FLAG_ADDRFRM: an address frame flag status
\arg MDIO_FLAG_RDINCFRM: a post read increment address frame flag status
\arg MDIO_FLAG_RDFRM: a read data frame flag status
\arg MDIO_FLAG_DEVM: a DEVADD match frame flag status
\arg MDIO_FLAG_DEVNM: a DEVADD nonmatch frame flag status
\arg MDIO_FLAG_PHYM: a PHYADR match frame flag status
\arg MDIO_FLAG_PHYNM: a PHYADR nonmatch frame flag status
\arg MDIO_FLAG_TANM: a TA nonmatch frame flag status
\arg MDIO_FLAG_TIMEOUT: timeout flag
\arg MDIO_FLAG_TX_UNDERRUN: transmit underrun flag
\arg MDIO_FLAG_RX_OVERRUN: receive overrun flag
\arg MDIO_FLAG_RBNE: read data buffer not empty flag
\param[out] none
\retval none
*/
void mdio_flag_clear(uint32_t flag)
{
__IO uint32_t reg = 0U;
reg = MDIO_TDATA;
if((MDIO_FLAG_RX_OVERRUN | MDIO_FLAG_RBNE) & flag){
(void)(MDIO_RDATA);
}else if(MDIO_FLAG_TX_UNDERRUN & flag){
MDIO_TDATA = reg;
}else if((MDIO_FLAG_WRFRM | MDIO_FLAG_ADDRFRM | MDIO_FLAG_RDINCFRM | MDIO_FLAG_RDFRM
| MDIO_FLAG_DEVM | MDIO_FLAG_DEVNM | MDIO_FLAG_PHYM | MDIO_FLAG_PHYNM | MDIO_FLAG_TIMEOUT) & flag){
(void)(MDIO_STAT);
} else {
/* illegal parameters */
}
}
/*!
\brief enable MDIO interrupt
\param[in] interrupt: MDIO interrupt
one or more parameters can be selected which are shown as below:
\arg MDIO_INT_WRFRM: a write data frame interrupt
\arg MDIO_INT_ADDRFRM: an address frame interrupt
\arg MDIO_INT_RDINCFRM: a post read increment address frame interrupt
\arg MDIO_INT_RDFRM: a read data frame interrupt
\arg MDIO_INT_DEVM: a DEVADD match frame interrupt
\arg MDIO_INT_DEVNM: a DEVADD nonmatch frame interrupt
\arg MDIO_INT_PHYM: a PHYADR match frame interrupt
\arg MDIO_INT_PHYNM: a PHYADR nonmatch frame interrupt
\arg MDIO_INT_TANM: a TA nonmatch frame flag interrupt
\arg MDIO_INT_TIMEOUT: a timeout interrupt
\arg MDIO_INT_TX_UNDERRUN: a transmit underrun interrupt
\arg MDIO_INT_RX_OVERRUN: a receive overrun interrupt
\arg MDIO_INT_RBNE: a read data buffer not empty interrupt
\param[out] none
\retval none
*/
void mdio_interrupt_enable(uint32_t interrupt)
{
MDIO_INTEN |= interrupt;
}
/*!
\brief disable MDIO interrupt
\param[in] interrupt: MDIO interrupt
one or more parameters can be selected which are shown as below:
\arg MDIO_INT_WRFRM: a write data frame interrupt
\arg MDIO_INT_ADDRFRM: an address frame interrupt
\arg MDIO_INT_RDINCFRM: a post read increment address frame interrupt
\arg MDIO_INT_RDFRM: a read data frame interrupt
\arg MDIO_INT_DEVM: a DEVADD match frame interrupt
\arg MDIO_INT_DEVNM: a DEVADD nonmatch frame interrupt
\arg MDIO_INT_PHYM: a PHYADR match frame interrupt
\arg MDIO_INT_PHYNM: a PHYADR nonmatch frame interrupt
\arg MDIO_INT_TANM: a TA nonmatch frame flag interrupt
\arg MDIO_INT_TIMEOUT: a timeout interrupt
\arg MDIO_INT_TX_UNDERRUN: a transmit underrun interrupt
\arg MDIO_INT_RX_OVERRUN: a receive overrun interrupt
\arg MDIO_INT_RBNE: a read data buffer not empty interrupt
\param[out] none
\retval none
*/
void mdio_interrupt_disable(uint32_t interrupt)
{
MDIO_INTEN &= ~(interrupt);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,259 @@
/*!
\file gd32h7xx_misc.c
\brief MISC driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_misc.h"
/*!
\brief set the priority group
\param[in] nvic_prigroup: the NVIC priority group
\arg NVIC_PRIGROUP_PRE0_SUB4: 0 bits for pre-emption priority, 4 bits for subpriority
\arg NVIC_PRIGROUP_PRE1_SUB3: 1 bits for pre-emption priority, 3 bits for subpriority
\arg NVIC_PRIGROUP_PRE2_SUB2: 2 bits for pre-emption priority, 2 bits for subpriority
\arg NVIC_PRIGROUP_PRE3_SUB1: 3 bits for pre-emption priority, 1 bits for subpriority
\arg NVIC_PRIGROUP_PRE4_SUB0: 4 bits for pre-emption priority, 0 bits for subpriority
\param[out] none
\retval none
*/
void nvic_priority_group_set(uint32_t nvic_prigroup)
{
/* set the priority group value */
SCB->AIRCR = NVIC_AIRCR_VECTKEY_MASK | nvic_prigroup;
}
/*!
\brief enable NVIC interrupt request
\param[in] nvic_irq: the NVIC interrupt request, detailed in IRQn_Type
\param[in] nvic_irq_pre_priority: the pre-emption priority needed to set
\param[in] nvic_irq_sub_priority: the subpriority needed to set
\param[out] none
\retval none
*/
void nvic_irq_enable(IRQn_Type nvic_irq,
uint8_t nvic_irq_pre_priority,
uint8_t nvic_irq_sub_priority)
{
uint32_t temp_priority = 0x00U, temp_pre = 0x00U, temp_sub = 0x00U;
/* use the priority group value to get the temp_pre and the temp_sub */
switch((SCB->AIRCR) & (uint32_t)0x700U) {
case NVIC_PRIGROUP_PRE0_SUB4:
temp_pre = 0U;
temp_sub = 0x4U;
break;
case NVIC_PRIGROUP_PRE1_SUB3:
temp_pre = 1U;
temp_sub = 0x3U;
break;
case NVIC_PRIGROUP_PRE2_SUB2:
temp_pre = 2U;
temp_sub = 0x2U;
break;
case NVIC_PRIGROUP_PRE3_SUB1:
temp_pre = 3U;
temp_sub = 0x1U;
break;
case NVIC_PRIGROUP_PRE4_SUB0:
temp_pre = 4U;
temp_sub = 0x0U;
break;
default:
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
temp_pre = 2U;
temp_sub = 0x2U;
break;
}
/* get the temp_priority to fill the NVIC->IP register */
temp_priority = (uint32_t)nvic_irq_pre_priority << (0x4U - temp_pre);
temp_priority |= nvic_irq_sub_priority & (0x0FU >> (0x4U - temp_sub));
temp_priority = temp_priority << 0x04U;
NVIC->IP[(uint8_t)nvic_irq] = (uint8_t)temp_priority;
/* enable the selected IRQ */
NVIC->ISER[(uint8_t)nvic_irq >> 0x05U] = (uint32_t)0x01U << ((uint8_t)nvic_irq & (uint8_t)0x1FU);
}
/*!
\brief disable NVIC interrupt request
\param[in] nvic_irq: the NVIC interrupt request, detailed in IRQn_Type
\param[out] none
\retval none
*/
void nvic_irq_disable(IRQn_Type nvic_irq)
{
/* disable the selected IRQ.*/
NVIC->ICER[(uint8_t)nvic_irq >> 0x05U] = (uint32_t)0x01U << ((uint8_t)nvic_irq & (uint8_t)0x1FU);
__DSB();
__ISB();
}
/*!
\brief set the NVIC vector table base address
\param[in] nvic_vect_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_vect_tab, uint32_t offset)
{
SCB->VTOR = nvic_vect_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 low power 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 low power 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_CKSYS: systick clock source is from CK_SYS
\arg SYSTICK_CLKSOURCE_CKSYS_DIV8: systick clock source is from CK_SYS/8
\param[out] none
\retval none
*/
void systick_clksource_set(uint32_t systick_clksource)
{
if(SYSTICK_CLKSOURCE_CKSYS == systick_clksource) {
/* set the systick clock source from CK_SYS */
SysTick->CTRL |= SYSTICK_CLKSOURCE_CKSYS;
} else {
/* set the systick clock source from CK_SYS/8 */
SysTick->CTRL &= SYSTICK_CLKSOURCE_CKSYS_DIV8;
}
}
#if (__MPU_PRESENT == 1)
/*!
\brief initialize mpu_region_init_struct with the default values
\param[in] mpu_init_struct: pointer to a mpu_region_init_struct structure
\param[out] none
\retval none
*/
void mpu_region_struct_para_init(mpu_region_init_struct *mpu_init_struct)
{
mpu_init_struct->region_number = MPU_REGION_NUMBER0;
mpu_init_struct->region_base_address = 0x00000000U;
mpu_init_struct->instruction_exec = MPU_INSTRUCTION_EXEC_PERMIT;
mpu_init_struct->access_permission = MPU_AP_NO_ACCESS;
mpu_init_struct->tex_type = MPU_TEX_TYPE0;
mpu_init_struct->access_shareable = MPU_ACCESS_SHAREABLE;
mpu_init_struct->access_cacheable = MPU_ACCESS_CACHEABLE;
mpu_init_struct->access_bufferable = MPU_ACCESS_BUFFERABLE;
mpu_init_struct->subregion_disable = MPU_SUBREGION_ENABLE;
mpu_init_struct->region_size = MPU_REGION_SIZE_32B;
}
/*!
\brief configure the MPU region
It is highly recommended to use MPU to prevent Speculative Prefetching of external memory,
which may cause CPU read locks and even system errors.
\param[in] mpu_init_struct: MPU initialization structure
region_number: region number
MPU_REGION_NUMBERn (n=0,..,15)
region_base_address: region base address
region_size: MPU_REGION_SIZE_32B, MPU_REGION_SIZE_64B, MPU_REGION_SIZE_128B, MPU_REGION_SIZE_256B, MPU_REGION_SIZE_512B,
MPU_REGION_SIZE_1KB, MPU_REGION_SIZE_2KB, MPU_REGION_SIZE_4KB, MPU_REGION_SIZE_8KB, MPU_REGION_SIZE_16KB,
MPU_REGION_SIZE_32KB, MPU_REGION_SIZE_64KB, MPU_REGION_SIZE_128KB, MPU_REGION_SIZE_256KB, MPU_REGION_SIZE_512KB,
MPU_REGION_SIZE_1MB, MPU_REGION_SIZE_2MB, MPU_REGION_SIZE_4MB, MPU_REGION_SIZE_8MB, MPU_REGION_SIZE_16MB,
MPU_REGION_SIZE_32MB, MPU_REGION_SIZE_64MB, MPU_REGION_SIZE_128MB, MPU_REGION_SIZE_256MB, MPU_REGION_SIZE_512MB,
MPU_REGION_SIZE_1GB, MPU_REGION_SIZE_2GB, MPU_REGION_SIZE_4GB
subregion_disable: MPU_SUBREGION_ENABLE, MPU_SUBREGION_DISABLE or 0x00~0xFF
tex_type: MPU_TEX_TYPE0, MPU_TEX_TYPE1, MPU_TEX_TYPE2 or 0x00~0x07
access_permission: MPU_AP_NO_ACCESS, MPU_AP_PRIV_RW, MPU_AP_PRIV_RW_UNPRIV_RO, MPU_AP_FULL_ACCESS, MPU_AP_PRIV_RO,
MPU_AP_PRIV_UNPRIV_RO
access_shareable: MPU_ACCESS_SHAREABLE, MPU_ACCESS_NON_SHAREABLE
access_cacheable: MPU_ACCESS_CACHEABLE, MPU_ACCESS_NON_CACHEABLE
access_bufferable: MPU_ACCESS_BUFFERABLE, MPU_ACCESS_NON_BUFFERABLE
instruction_exec: MPU_INSTRUCTION_EXEC_PERMIT, MPU_INSTRUCTION_EXEC_NOT_PERMIT
\param[out] none
\retval none
*/
void mpu_region_config(mpu_region_init_struct *mpu_init_struct)
{
MPU->RNR = mpu_init_struct->region_number;
MPU->RBAR = mpu_init_struct->region_base_address;
MPU->RASR = ((uint32_t)mpu_init_struct->instruction_exec << MPU_RASR_XN_Pos) |
((uint32_t)mpu_init_struct->access_permission << MPU_RASR_AP_Pos) |
((uint32_t)mpu_init_struct->tex_type << MPU_RASR_TEX_Pos)|
((uint32_t)mpu_init_struct->access_shareable << MPU_RASR_S_Pos) |
((uint32_t)mpu_init_struct->access_cacheable << MPU_RASR_C_Pos) |
((uint32_t)mpu_init_struct->access_bufferable << MPU_RASR_B_Pos) |
((uint32_t)mpu_init_struct->subregion_disable << MPU_RASR_SRD_Pos)|
((uint32_t)mpu_init_struct->region_size << MPU_RASR_SIZE_Pos);
}
/*!
\brief enable the MPU region
\param[in] none
\param[out] none
\retval none
*/
void mpu_region_enable(void)
{
MPU->RASR |= MPU_RASR_ENABLE_Msk;
}
#endif /* __MPU_PRESENT */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,206 @@
/*!
\file gd32h7xx_ospim.c
\brief OSPIM driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_ospim.h"
#include "gd32h7xx_ospi.h"
/*!
\brief reset the OSPIM peripheral
\param[in] none
\param[out] none
\retval none
*/
void ospim_deinit(void)
{
/* reset OSPIM */
rcu_periph_reset_enable(RCU_OSPIMRST);
rcu_periph_reset_disable(RCU_OSPIMRST);
}
/*!
\brief configurate SCK for port
\param[in] port: number of port
only one parameter can be selected which is shown as below:
\arg OSPIM_PORT0: port 0
\arg OSPIM_PORT1: port 1
\param[in] sckconfg: enable or disable SCK
only one parameter can be selected which is shown as below:
\arg OSPIM_PORT_SCK_DISABLE: disable SCK
\arg OSPIM_PORT_SCK_ENABLE: enable SCK
\param[out] none
\retval none
*/
void ospim_port_sck_config(uint8_t port, uint32_t sckconfg)
{
OSPIM_PCFG(port) &= (uint32_t)(~OSPIM_PCFG_SCKEN);
OSPIM_PCFG(port) |= (uint32_t)sckconfg;
}
/*!
\brief select source of SCK for port
\param[in] port: number of port
only one parameter can be selected which is shown as below:
\arg OSPIM_PORT0: port 0
\arg OSPIM_PORT1: port 1
\param[in] sck_source: source of SCK
only one parameter can be selected which is shown as below:
\arg OSPIM_SCK_SOURCE_OSPI0_SCK: the source of SCK is OSPI0_SCK
\arg OSPIM_SCK_SOURCE_OSPI1_SCK: the source of SCK is OSPI1_SCK
\param[out] none
\retval none
*/
void ospim_port_sck_source_select(uint8_t port, uint32_t sck_source)
{
OSPIM_PCFG(port) &= (uint32_t)(~OSPIM_PCFG_SRCPCK);
OSPIM_PCFG(port) |= (uint32_t)sck_source;
}
/*!
\brief configurate CSN for port
\param[in] port: number of port
only one parameter can be selected which is shown as below:
\arg OSPIM_PORT0: port 0
\arg OSPIM_PORT1: port 1
\param[in] csnconfig: enable or disable CSN
only one parameter can be selected which is shown as below:
\arg OSPIM_PORT_CSN_DISABLE: disable CSN
\arg OSPIM_PORT_CSN_ENABLE: enable CSN
\param[out] none
\retval none
*/
void ospim_port_csn_config(uint8_t port, uint32_t csnconfig)
{
OSPIM_PCFG(port) &= (uint32_t)(~OSPIM_PCFG_NCSEN);
OSPIM_PCFG(port) |= (uint32_t)csnconfig;
}
/*!
\brief select source of CSN for port
\param[in] port: number of port
only one parameter can be selected which is shown as below:
\arg OSPIM_PORT0: port 0
\arg OSPIM_PORT1: port 1
\param[in] csn_source: source of CSN
only one parameter can be selected which is shown as below:
\arg OSPIM_CSN_SOURCE_OSPI0_CSN: the source of CSN is OSPI0_CSN
\arg OSPIM_CSN_SOURCE_OSPI1_CSN: the source of CSN is OSPI1_CSN
\param[out] none
\retval none
*/
void ospim_port_csn_source_select(uint8_t port, uint32_t csn_source)
{
OSPIM_PCFG(port) &= (uint32_t)(~OSPIM_PCFG_SRCPCS);
OSPIM_PCFG(port) |= (uint32_t)csn_source;
}
/*!
\brief configurate IO[3:0] for port
\param[in] port: number of port
only one parameter can be selected which is shown as below:
\arg OSPIM_PORT0: port 0
\arg OSPIM_PORT1: port 1
\param[in] ioconfig: enable or disable IO[3:0]
only one parameter can be selected which is shown as below:
\arg OSPIM_IO_LOW_DISABLE: disable IO[3:0]
\arg OSPIM_IO_LOW_ENABLE: enable IO[3:0]
\param[out] none
\retval none
*/
void ospim_port_io3_0_config(uint8_t port, uint32_t ioconfig)
{
OSPIM_PCFG(port) &= (uint32_t)(~OSPIM_PCFG_POLEN);
OSPIM_PCFG(port) |= (uint32_t)ioconfig;
}
/*!
\brief select source of IO[3:0] for port
\param[in] port: number of port
only one parameter can be selected which is shown as below:
\arg OSPIM_PORT0: port 0
\arg OSPIM_PORT1: port 1
\param[in] csn_source: source of IO[3:0]
only one parameter can be selected which is shown as below:
\arg OSPIM_SRCPLIO_OSPI0_IO_LOW: select OSPI0_IO[3:0]
\arg OSPIM_SRCPLIO_OSPI0_IO_HIGH: select OSPI0_IO[7:4]
\arg OSPIM_SRCPLIO_OSPI1_IO_LOW: select OSPI1_IO[3:0]
\arg OSPIM_SRCPLIO_OSPI1_IO_HIGH: select OSPI1_IO[7:4]
\param[out] none
\retval none
*/
void ospim_port_io3_0_source_select(uint8_t port, uint32_t io_source)
{
OSPIM_PCFG(port) &= (uint32_t)(~OSPIM_PCFG_SRCPLIO);
OSPIM_PCFG(port) |= (uint32_t)io_source;
}
/*!
\brief configurate IO[7:4] for port
\param[in] port: number of port
only one parameter can be selected which is shown as below:
\arg OSPIM_PORT0: port 0
\arg OSPIM_PORT1: port 1
\param[in] ioconfig: enable or disable IO[7:4]
only one parameter can be selected which is shown as below:
\arg OSPIM_IO_HIGH_DISABLE: disable IO[7:4]
\arg OSPIM_IO_HIGH_ENABLE: enable IO[7:4]
\param[out] none
\retval none
*/
void ospim_port_io7_4_config(uint8_t port, uint32_t ioconfig)
{
OSPIM_PCFG(port) &= (uint32_t)(~OSPIM_PCFG_POHEN);
OSPIM_PCFG(port) |= (uint32_t)ioconfig;
}
/*!
\brief select source of IO[7:4] for port
\param[in] port: number of port
only one parameter can be selected which is shown as below:
\arg OSPIM_PORT0: port 0
\arg OSPIM_PORT1: port 1
\param[in] csn_source: source of IO[7:4]
only one parameter can be selected which is shown as below:
\arg OSPIM_SRCPHIO_OSPI0_IO_LOW: select OSPI0_IO[3:0]
\arg OSPIM_SRCPHIO_OSPI0_IO_HIGH: select OSPI0_IO[7:4]
\arg OSPIM_SRCPHIO_OSPI1_IO_LOW: select OSPI1_IO[3:0]
\arg OSPIM_SRCPHIO_OSPI1_IO_HIGH: select OSPI1_IO[7:4]
\param[out] none
\retval none
*/
void ospim_port_io7_4_source_select(uint8_t port, uint32_t io_source)
{
OSPIM_PCFG(port) &= (uint32_t)(~OSPIM_PCFG_SRCPHIO);
OSPIM_PCFG(port) |= (uint32_t)io_source;
}
@@ -0,0 +1,568 @@
/*!
\file gd32h7xx_pmu.c
\brief PMU driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_pmu.h"
/* PMU register bit offset */
#define PAR_TSW_IRCCNT_OFFSET ((uint32_t)0x00000010U) /*!< bit offset of TSW_HSICNT in PMU_PAR */
/*!
\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: input analog voltage on PB7 (compared with 0.8V)
\param[out] none
\retval none
*/
void pmu_lvd_select(uint32_t lvdt_n)
{
uint32_t temp;
temp = PMU_CTL0;
/* clear LVDT bits */
temp &= ~PMU_CTL0_LVDT;
/* set LVDT bits according to lvdt_n */
temp |= lvdt_n;
PMU_CTL0 = temp;
}
/*!
\brief enable PMU lvd
\param[in] none
\param[out] none
\retval none
*/
void pmu_lvd_enable(void)
{
PMU_CTL0 |= PMU_CTL0_LVDEN;
}
/*!
\brief disable PMU lvd
\param[in] none
\param[out] none
\retval none
*/
void pmu_lvd_disable(void)
{
PMU_CTL0 &= ~PMU_CTL0_LVDEN;
}
/*!
\brief select analog voltage detector threshold
\param[in] vavdt_n:
only one parameter can be selected which is shown as below:
\arg PMU_VAVDVC_0: voltage threshold of analog voltage detector is 1.7V
\arg PMU_VAVDVC_1: voltage threshold of analog voltage detector is 2.1V
\arg PMU_VAVDVC_2: voltage threshold of analog voltage detector is 2.5V
\arg PMU_VAVDVC_3: voltage threshold of analog voltage detector is 2.8V
\param[out] none
\retval none
*/
void pmu_vavd_select(uint32_t vavdt_n)
{
uint32_t temp;
temp = PMU_CTL0;
/* clear VAVDVC bits */
temp &= ~PMU_CTL0_VAVDVC;
/* set VAVDVC bits according to vavdt_n */
temp |= vavdt_n;
PMU_CTL0 = temp;
}
/*!
\brief enable PMU analog voltage detector
\param[in] none
\param[out] none
\retval none
*/
void pmu_vavd_enable(void)
{
PMU_CTL0 |= PMU_CTL0_VAVDEN;
}
/*!
\brief disable PMU analog voltage detector
\param[in] none
\param[out] none
\retval none
*/
void pmu_vavd_disable(void)
{
PMU_CTL0 &= ~PMU_CTL0_VAVDEN;
}
/*!
\brief enable PMU V0.9V core voltage detector
\param[in] none
\param[out] none
\retval none
*/
void pmu_vovd_enable(void)
{
PMU_CTL0 |= PMU_CTL0_VOVDEN;
}
/*!
\brief disable PMU V0.9V core voltage detector
\param[in] none
\param[out] none
\retval none
*/
void pmu_vovd_disable(void)
{
PMU_CTL0 &= ~PMU_CTL0_VOVDEN;
}
/*!
\brief control the V0.9V core voltage level
\param[in] ldo_n:
only one parameter can be selected which is shown as below:
\arg PMU_LDOVS_0: LDO output voltage 0.8V mode
\arg PMU_LDOVS_1: LDO output voltage 0.85V mode
\arg PMU_LDOVS_2: LDO output voltage 0.9V mode
\arg PMU_LDOVS_3: LDO output voltage 0.95V mode
\arg PMU_LDOVS_4: LDO output voltage 0.975V mode
\arg PMU_LDOVS_5: LDO output voltage 1V mode
\param[out] none
\retval none
*/
void pmu_ldo_output_select(uint32_t ldo_n)
{
uint32_t temp;
temp = PMU_CTL3;
temp &= ~PMU_CTL3_LDOVS;
temp |= ldo_n;
PMU_CTL3 = temp;
}
/*!
\brief Deep-sleep mode V0.9V core voltage select
\param[in] sldo:
only one parameter can be selected which is shown as below:
\arg PMU_SLDOVS_0: SLDOVS scale 0.6V
\arg PMU_SLDOVS_1: SLDOVS scale 0.7V
\arg PMU_SLDOVS_2: SLDOVS scale 0.8V
\arg PMU_SLDOVS_3: SLDOVS scale 0.9V
\param[out] none
\retval none
*/
void pmu_sldo_output_select(uint32_t sldo_n)
{
uint32_t temp;
temp = PMU_CTL0;
temp &= ~PMU_CTL0_SLDOVS;
temp |= sldo_n;
PMU_CTL0 = temp;
}
/*!
\brief PMU VBAT battery charging resistor selection
\param[in] resistor:
only one parameter can be selected which is shown as below:
\arg PMU_VCRSEL_5K: 5kOhms resistor is selected for charing VBAT battery
\arg PMU_VCRSEL_1P5K: 1.5kOhms resistor is selected for charing VBAT battery
\param[out] none
\retval none
*/
void pmu_vbat_charging_select(uint32_t resistor)
{
PMU_CTL2 &= ~PMU_CTL2_VCRSEL;
PMU_CTL2 |= resistor;
}
/*!
\brief enable VBAT battery charging
\param[in] none
\param[out] none
\retval none
*/
void pmu_vbat_charging_enable(void)
{
PMU_CTL2 |= PMU_CTL2_VCEN;
}
/*!
\brief disable VBAT battery charging
\param[in] none
\param[out] none
\retval none
*/
void pmu_vbat_charging_disable(void)
{
PMU_CTL2 &= ~PMU_CTL2_VCEN;
}
/*!
\brief enable VBAT and temperature monitoring
\param[in] none
\param[out] none
\retval none
*/
void pmu_vbat_temp_moniter_enable(void)
{
PMU_CTL1 |= PMU_CTL1_VBTMEN;
}
/*!
\brief disable VBAT and temperature monitoring
\param[in] none
\param[out] none
\retval none
*/
void pmu_vbat_temp_moniter_disable(void)
{
PMU_CTL1 &= ~PMU_CTL1_VBTMEN;
}
/*!
\brief enable USB regulator
\param[in] none
\param[out] none
\retval none
*/
void pmu_usb_regulator_enable(void)
{
PMU_CTL2 |= PMU_CTL2_USBSEN;
}
/*!
\brief disable USB regulator
\param[in] none
\param[out] none
\retval none
*/
void pmu_usb_regulator_disable(void)
{
PMU_CTL2 &= ~PMU_CTL2_USBSEN;
}
/*!
\brief enable VDD33USB voltage level detector
\param[in] none
\param[out] none
\retval none
*/
void pmu_usb_voltage_detector_enable(void)
{
PMU_CTL2 |= PMU_CTL2_VUSB33DEN;
}
/*!
\brief disable VDD33USB voltage level detector
\param[in] none
\param[out] none
\retval none
*/
void pmu_usb_voltage_detector_disable(void)
{
PMU_CTL2 &= ~PMU_CTL2_VUSB33DEN;
}
/*!
\brief power supply configurations
\param[in] smpsmode:
only one parameter can be selected which is shown as below:
\arg PMU_LDO_SUPPLY: V0.9V domains are suppplied from the LDO
\arg PMU_DIRECT_SMPS_SUPPLY: V0.9V domains are suppplied from the SMPS only
\arg PMU_BYPASS: the SMPS disabled and the LDO Bypass. The V0.9V domains are supplied from an external source
\param[out] none
\retval none
*/
void pmu_smps_ldo_supply_config(uint32_t smpsmode)
{
uint32_t temp;
temp = PMU_CTL2;
temp &= ~(PMU_CTL2_DVSEN | PMU_CTL2_LDOEN | PMU_CTL2_BYPASS);
temp |= smpsmode;
PMU_CTL2 = temp;
while(0U == (PMU_CTL3 & PMU_CTL3_VOVRF)) {
}
}
/*!
\brief enter 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-M7 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 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(uint8_t deepsleepmodecmd)
{
/* clear standby mode */
PMU_CTL0 &= ~((uint32_t)(PMU_CTL0_STBMOD));
/* set sleepdeep bit of Cortex-M7 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-M7 system control register */
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
}
/*!
\brief enter standby mode
\param[in] none
\param[out] none
\retval none
*/
void pmu_to_standbymode(void)
{
/* set stbmod bit */
PMU_CTL0 |= PMU_CTL0_STBMOD;
/* reset wakeup flag */
PMU_CTL0 |= PMU_CTL0_WURST;
/* set sleepdeep bit of Cortex-M7 system control register */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
REG32( 0xE000E010U ) &= 0x00010004U;
REG32( 0xE000E180U ) = 0xFFFFFFF3U;
REG32( 0xE000E184U ) = 0xFFFFFDFFU;
REG32( 0xE000E188U ) = 0xFFFFFFFFU;
REG32( 0xE000E18CU ) = 0xFFFFFFFFU;
REG32( 0xE000E190U ) = 0xFFFFFFFFU;
REG32( 0xE000E194U ) = 0xFFFFFFFFU;
/* enter standby mode */
__WFI();
}
/*!
\brief enable PMU wakeup pin
\param[in] wakeup_pin:
only one parameter can be selected which is shown as below:
\arg PMU_WAKEUP_PIN0: WKUP Pin 0
\arg PMU_WAKEUP_PIN1: WKUP Pin 1
\arg PMU_WAKEUP_PIN3: WKUP Pin 3
\arg PMU_WAKEUP_PIN5: WKUP Pin 5
\param[out] none
\retval none
*/
void pmu_wakeup_pin_enable(uint32_t wakeup_pin)
{
PMU_CS |= wakeup_pin;
}
/*!
\brief disable PMU wakeup pin
\param[in] wakeup_pin:
only one parameter can be selected which is shown as below:
\arg PMU_WAKEUP_PIN0: WKUP Pin 0
\arg PMU_WAKEUP_PIN1: WKUP Pin 1
\arg PMU_WAKEUP_PIN3: WKUP Pin 3
\arg PMU_WAKEUP_PIN5: WKUP Pin 5
\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_CTL0 |= PMU_CTL0_BKPWEN;
}
/*!
\brief disable backup domain write
\param[in] none
\param[out] none
\retval none
*/
void pmu_backup_write_disable(void)
{
PMU_CTL0 &= ~PMU_CTL0_BKPWEN;
}
/*!
\brief enable backup voltage stabilizer
\param[in] none
\param[out] none
\retval none
*/
void pmu_backup_voltage_stabilizer_enable(void)
{
PMU_CTL1 |= PMU_CTL1_BKPVSEN;
while(RESET == (PMU_CTL1 & PMU_CTL1_BKPVSRF)) {
}
}
/*!
\brief disable backup voltage stabilizer
\param[in] none
\param[out] none
\retval none
*/
void pmu_backup_voltage_stabilizer_disable(void)
{
PMU_CTL1 &= ~PMU_CTL1_BKPVSEN;
}
/*!
\brief configure IRC counter before enter Deep-sleep mode
\param[in] wait_time: 0x0~0x1F, IRC counter before enter Deep-sleep mode
\param[out] none
\retval none
*/
void pmu_enter_deepsleep_wait_time_config(uint32_t wait_time)
{
uint32_t temp;
temp = PMU_PAR;
temp &= ~PMU_PAR_TSW_IRCCNT;
temp |= (uint32_t)(wait_time << PAR_TSW_IRCCNT_OFFSET);
PMU_PAR = temp;
}
/*!
\brief configure IRC counter before exit Deep-sleep mode
\param[in] wait_time: 0x0~0xFFF, IRC counter before exit Deep-sleep mode
\param[out] none
\retval none
*/
void pmu_exit_deepsleep_wait_time_config(uint32_t wait_time)
{
uint32_t temp;
temp = PMU_PAR;
temp &= ~PMU_PAR_CNT;
temp |= (uint32_t)(wait_time);
PMU_PAR = temp;
}
/*!
\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_LVDF: low voltage detector status flag
\arg PMU_FLAG_VAVDF: VDDA analog voltage detector voltage output on VDDA flag
\arg PMU_FLAG_VOVDF: peripheral voltage on VDDA detector flag
\arg PMU_FLAG_VBATLF: VBAT level monitoring versus low threshold
\arg PMU_FLAG_VBATHF: VBAT level monitoring versus high threshold
\arg PMU_FLAG_TEMPLF: temperature level monitoring versus low threshold
\arg PMU_FLAG_TEMPHF: temperature level monitoring versus high threshold
\arg PMU_FLAG_DVSRF: step-down voltage stabilizer ready flag bit
\arg PMU_FLAG_USB33RF: USB supply ready flag bit
\arg PMU_FLAG_PWRRF: power Ready flag bit.
\param[out] none
\retval FlagStatus SET or RESET
*/
FlagStatus pmu_flag_get(uint32_t flag)
{
if(PMU_REG_VAL(flag) & BIT(PMU_BIT_POS(flag))) {
return SET;
} else {
return RESET;
}
}
/*!
\brief clear flag bit
\param[in] flag_reset:
\arg PMU_FLAG_WAKEUP: wakeup flag
\arg PMU_FLAG_STANDBY: standby flag
\param[out] none
\retval none
*/
void pmu_flag_clear(uint32_t flag_reset)
{
if(PMU_FLAG_WAKEUP == flag_reset) {
PMU_CTL0 |= PMU_CTL0_WURST;
} else {
if(PMU_FLAG_STANDBY == flag_reset) {
PMU_CTL0 |= PMU_CTL0_STBRST;
}
}
}
@@ -0,0 +1,395 @@
/*!
\file gd32h7xx_rameccmu.c
\brief RAMECCMU driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_rameccmu.h"
#define RAMECCMU_REG_RESET_VALUE 0x00000000U
/*!
\brief deinit RAMECCMU unit
\param[in] rameccmu_periph: RAMECCMUx(x=0,1)
\param[out] none
\retval none
*/
void rameccmu_deinit(uint32_t rameccmu_periph)
{
RAMECCMU_INT(rameccmu_periph) = RAMECCMU_REG_RESET_VALUE;
if(RAMECCMU0 == rameccmu_periph){
/* reset RAMECCMU0_MONITOR0 registers */
RAMECCMU_MXCTL(RAMECCMU0_MONITOR0) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXSTAT(RAMECCMU0_MONITOR0) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFADDR(RAMECCMU0_MONITOR0) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFDL(RAMECCMU0_MONITOR0) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFDH(RAMECCMU0_MONITOR0) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFECODE(RAMECCMU0_MONITOR0) = RAMECCMU_REG_RESET_VALUE;
/* reset RAMECCMU0_MONITOR1 registers */
RAMECCMU_MXCTL(RAMECCMU0_MONITOR1) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXSTAT(RAMECCMU0_MONITOR1) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFADDR(RAMECCMU0_MONITOR1) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFDL(RAMECCMU0_MONITOR1) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFDH(RAMECCMU0_MONITOR1) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFECODE(RAMECCMU0_MONITOR1) = RAMECCMU_REG_RESET_VALUE;
/* reset RAMECCMU0_MONITOR2 registers */
RAMECCMU_MXCTL(RAMECCMU0_MONITOR2) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXSTAT(RAMECCMU0_MONITOR2) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFADDR(RAMECCMU0_MONITOR2) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFDL(RAMECCMU0_MONITOR2) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFDH(RAMECCMU0_MONITOR2) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFECODE(RAMECCMU0_MONITOR2) = RAMECCMU_REG_RESET_VALUE;
/* reset RAMECCMU0_MONITOR3 registers */
RAMECCMU_MXCTL(RAMECCMU0_MONITOR3) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXSTAT(RAMECCMU0_MONITOR3) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFADDR(RAMECCMU0_MONITOR3) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFDL(RAMECCMU0_MONITOR3) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFDH(RAMECCMU0_MONITOR3) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFECODE(RAMECCMU0_MONITOR3) = RAMECCMU_REG_RESET_VALUE;
/* reset RAMECCMU0_MONITOR4 registers */
RAMECCMU_MXCTL(RAMECCMU0_MONITOR4) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXSTAT(RAMECCMU0_MONITOR4) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFADDR(RAMECCMU0_MONITOR4) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFDL(RAMECCMU0_MONITOR4) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFDH(RAMECCMU0_MONITOR4) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFECODE(RAMECCMU0_MONITOR4) = RAMECCMU_REG_RESET_VALUE;
}else{
/* reset RAMECCMU1_MONITOR0 registers */
RAMECCMU_MXCTL(RAMECCMU1_MONITOR0) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXSTAT(RAMECCMU1_MONITOR0) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFADDR(RAMECCMU1_MONITOR0) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFDL(RAMECCMU1_MONITOR0) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFDH(RAMECCMU1_MONITOR0) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFECODE(RAMECCMU1_MONITOR0) = RAMECCMU_REG_RESET_VALUE;
/* reset RAMECCMU1_MONITOR1 registers */
RAMECCMU_MXCTL(RAMECCMU1_MONITOR1) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXSTAT(RAMECCMU1_MONITOR1) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFADDR(RAMECCMU1_MONITOR1) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFDL(RAMECCMU1_MONITOR1) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFDH(RAMECCMU1_MONITOR1) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFECODE(RAMECCMU1_MONITOR1) = RAMECCMU_REG_RESET_VALUE;
/* reset RAMECCMU1_MONITOR2 registers */
RAMECCMU_MXCTL(RAMECCMU1_MONITOR2) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXSTAT(RAMECCMU1_MONITOR2) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFADDR(RAMECCMU1_MONITOR2) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFDL(RAMECCMU1_MONITOR2) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFDH(RAMECCMU1_MONITOR2) = RAMECCMU_REG_RESET_VALUE;
RAMECCMU_MXFECODE(RAMECCMU1_MONITOR2) = RAMECCMU_REG_RESET_VALUE;
}
}
/*!
\brief get RAMECCMU monitor ECC failing address
\param[in] rameccmu_monitor: RAMECCMU monitor
only one parameter can be selected which is shown as below:
\arg RAMECCMU0_MONITOR0: RAMECCMU0 monitor 0
\arg RAMECCMU0_MONITOR1: RAMECCMU0 monitor 1
\arg RAMECCMU0_MONITOR2: RAMECCMU0 monitor 2
\arg RAMECCMU0_MONITOR3: RAMECCMU0 monitor 3
\arg RAMECCMU0_MONITOR4: RAMECCMU0 monitor 4
\arg RAMECCMU1_MONITOR0: RAMECCMU1 monitor 0
\arg RAMECCMU1_MONITOR1: RAMECCMU1 monitor 1
\arg RAMECCMU1_MONITOR2: RAMECCMU1 monitor 2
\param[out] none
\retval ECC error failing address
*/
uint32_t rameccmu_monitor_failing_address_get(rameccmu_monitor_enum rameccmu_monitor)
{
return RAMECCMU_MXFADDR(rameccmu_monitor);
}
/*!
\brief get RAMECCMU monitor ECC failing data low 32 bits
\param[in] rameccmu_monitor: RAMECCMU monitor
only one parameter can be selected which is shown as below:
\arg RAMECCMU0_MONITOR0: RAMECCMU0 monitor 0
\arg RAMECCMU0_MONITOR1: RAMECCMU0 monitor 1
\arg RAMECCMU0_MONITOR2: RAMECCMU0 monitor 2
\arg RAMECCMU0_MONITOR3: RAMECCMU0 monitor 3
\arg RAMECCMU0_MONITOR4: RAMECCMU0 monitor 4
\arg RAMECCMU1_MONITOR0: RAMECCMU1 monitor 0
\arg RAMECCMU1_MONITOR1: RAMECCMU1 monitor 1
\arg RAMECCMU1_MONITOR2: RAMECCMU1 monitor 2
\param[out] none
\retval ECC failing data low 32 bits
*/
uint32_t rameccmu_monitor_failing_data_low_bits_get(rameccmu_monitor_enum rameccmu_monitor)
{
return RAMECCMU_MXFDL(rameccmu_monitor);
}
/*!
\brief get RAMECCMU monitor ECC failing data high 32 bits
\param[in] rameccmu_monitor: RAMECCMU monitor
only one parameter can be selected which is shown as below:
\arg RAMECCMU0_MONITOR0: RAMECCMU0 monitor 0
\arg RAMECCMU0_MONITOR1: RAMECCMU0 monitor 1
\arg RAMECCMU0_MONITOR2: RAMECCMU0 monitor 2
\arg RAMECCMU0_MONITOR3: RAMECCMU0 monitor 3
\arg RAMECCMU0_MONITOR4: RAMECCMU0 monitor 4
\arg RAMECCMU1_MONITOR0: RAMECCMU1 monitor 0
\arg RAMECCMU1_MONITOR1: RAMECCMU1 monitor 1
\arg RAMECCMU1_MONITOR2: RAMECCMU1 monitor 2
\param[out] none
\retval ECC failing data high 32 bits
*/
uint32_t rameccmu_monitor_failing_data_high_bits_get(rameccmu_monitor_enum rameccmu_monitor)
{
return RAMECCMU_MXFDH(rameccmu_monitor);
}
/*!
\brief get RAMECCMU monitor failing ECC error code
\param[in] rameccmu_monitor: RAMECCMU monitor
only one parameter can be selected which is shown as below:
\arg RAMECCMU0_MONITOR0: RAMECCMU0 monitor 0
\arg RAMECCMU0_MONITOR1: RAMECCMU0 monitor 1
\arg RAMECCMU0_MONITOR2: RAMECCMU0 monitor 2
\arg RAMECCMU0_MONITOR3: RAMECCMU0 monitor 3
\arg RAMECCMU0_MONITOR4: RAMECCMU0 monitor 4
\arg RAMECCMU1_MONITOR0: RAMECCMU1 monitor 0
\arg RAMECCMU1_MONITOR1: RAMECCMU1 monitor 1
\arg RAMECCMU1_MONITOR2: RAMECCMU1 monitor 2
\param[out] none
\retval ECC failing error code
*/
uint32_t rameccmu_monitor_failing_ecc_error_code_get(rameccmu_monitor_enum rameccmu_monitor)
{
return RAMECCMU_MXFECODE(rameccmu_monitor);
}
/*!
\brief enable RAMECCMU global ECC interruput
\param[in] rameccmu_periph: RAMECCMU
only one parameter can be selected which is shown as below:
\arg RAMECCMU0: RAMECCMU for region 0
\arg RAMECCMU1: RAMECCMU for region 1
\param[in] interrupt: global ECC interruput
one or more parameters can be selected which are shown as below:
\arg RAMECCMU_INT_ECC_GLOBAL_ERROR: ECC global error interrupt
\arg RAMECCMU_INT_ECC_SINGLE_ERROR: ECC single error interrupt
\arg RAMECCMU_INT_ECC_DOUBLE_ERROR: ECC double error interrupt
\arg RAMECCMU_INT_ECC_DOUBLE_ERROR_BYTE_WRITE: ECC double error on byte write interrupt
\param[out] none
\retval none
*/
void rameccmu_global_interrupt_enable(uint32_t rameccmu_periph, uint32_t interrupt)
{
RAMECCMU_INT(rameccmu_periph) |= interrupt;
}
/*!
\brief disable RAMECCMU global ECC interruput
\param[in] rameccmu_periph: RAMECCMU
only one parameter can be selected which is shown as below:
\arg RAMECCMU0: RAMECCMU for region 0
\arg RAMECCMU1: RAMECCMU for region 1
\param[in] interrupt: global ECC interruput
one or more parameters can be selected which are shown as below:
\arg RAMECCMU_INT_ECC_GLOBAL_ERROR: ECC global error interrupt
\arg RAMECCMU_INT_ECC_SINGLE_ERROR: ECC single error interrupt
\arg RAMECCMU_INT_ECC_DOUBLE_ERROR: ECC double error interrupt
\arg RAMECCMU_INT_ECC_DOUBLE_ERROR_BYTE_WRITE: ECC double error on byte write interrupt
\param[out] none
\retval none
*/
void rameccmu_global_interrupt_disable(uint32_t rameccmu_periph, uint32_t interrupt)
{
RAMECCMU_INT(rameccmu_periph) &= (uint32_t)(~interrupt);
}
/*!
\brief enable RAMECCMU monitor ECC error interruput
\param[in] rameccmu_monitor: RAMECCMU monitor
only one parameter can be selected which is shown as below:
\arg RAMECCMU0_MONITOR0: RAMECCMU0 monitor 0
\arg RAMECCMU0_MONITOR1: RAMECCMU0 monitor 1
\arg RAMECCMU0_MONITOR2: RAMECCMU0 monitor 2
\arg RAMECCMU0_MONITOR3: RAMECCMU0 monitor 3
\arg RAMECCMU0_MONITOR4: RAMECCMU0 monitor 4
\arg RAMECCMU1_MONITOR0: RAMECCMU1 monitor 0
\arg RAMECCMU1_MONITOR1: RAMECCMU1 monitor 1
\arg RAMECCMU1_MONITOR2: RAMECCMU1 monitor 2
\param[in] monitor_interrupt: RAMECCMU monitor interruput
one or more parameters can be selected which are shown as below:
\arg RAMECCMU_INT_ECC_SINGLE_ERROR: ECC single error interrupt
\arg RAMECCMU_INT_ECC_DOUBLE_ERROR: ECC double error interrupt
\arg RAMECCMU_INT_ECC_DOUBLE_ERROR_BYTE_WRITE: ECC double error on byte write interrupt
\arg RAMECCMU_INT_ECC_ERROR_LATCHING: ECC error latching
\param[out] none
\retval none
*/
void rameccmu_monitor_interrupt_enable(rameccmu_monitor_enum rameccmu_monitor, uint32_t monitor_interrupt)
{
RAMECCMU_MXCTL(rameccmu_monitor) |= (uint32_t)monitor_interrupt << 1U;
}
/*!
\brief disable RAMECCMU monitor ECC error interruput
\param[in] rameccmu_monitor: RAMECCMU monitor
only one parameter can be selected which is shown as below:
\arg RAMECCMU0_MONITOR0: RAMECCMU0 monitor 0
\arg RAMECCMU0_MONITOR1: RAMECCMU0 monitor 1
\arg RAMECCMU0_MONITOR2: RAMECCMU0 monitor 2
\arg RAMECCMU0_MONITOR3: RAMECCMU0 monitor 3
\arg RAMECCMU0_MONITOR4: RAMECCMU0 monitor 4
\arg RAMECCMU1_MONITOR0: RAMECCMU1 monitor 0
\arg RAMECCMU1_MONITOR1: RAMECCMU1 monitor 1
\arg RAMECCMU1_MONITOR2: RAMECCMU1 monitor 2
\param[in] monitor_interrupt: RAMECCMU monitor interruput
one or more parameters can be selected which are shown as below:
\arg RAMECCMU_INT_ECC_SINGLE_ERROR: ECC single error interrupt
\arg RAMECCMU_INT_ECC_DOUBLE_ERROR: ECC double error interrupt
\arg RAMECCMU_INT_ECC_DOUBLE_ERROR_BYTE_WRITE: ECC double error on byte write interrupt
\arg RAMECCMU_INT_ECC_ERROR_LATCHING: ECC error latching
\param[out] none
\retval none
*/
void rameccmu_monitor_interrupt_disable(rameccmu_monitor_enum rameccmu_monitor, uint32_t monitor_interrupt)
{
RAMECCMU_MXCTL(rameccmu_monitor) &= (uint32_t)~((uint32_t)monitor_interrupt << 1U);
}
/*!
\brief get RAMECCMU monitor ECC error flag
\param[in] rameccmu_monitor: RAMECCMU monitor
only one parameter can be selected which is shown as below:
\arg RAMECCMU0_MONITOR0: RAMECCMU0 monitor 0
\arg RAMECCMU0_MONITOR1: RAMECCMU0 monitor 1
\arg RAMECCMU0_MONITOR2: RAMECCMU0 monitor 2
\arg RAMECCMU0_MONITOR3: RAMECCMU0 monitor 3
\arg RAMECCMU0_MONITOR4: RAMECCMU0 monitor 4
\arg RAMECCMU1_MONITOR0: RAMECCMU1 monitor 0
\arg RAMECCMU1_MONITOR1: RAMECCMU1 monitor 1
\arg RAMECCMU1_MONITOR2: RAMECCMU1 monitor 2
\param[in] flag: RAMECCMU monitor flag
one or more parameters can be selected which are shown as below:
\arg RAMECCMU_FLAG_ECC_SINGLE_ERROR: ECC single error detected and corrected flag
\arg RAMECCMU_FLAG_ECC_DOUBLE_ERROR: ECC double error detected flag
\arg RAMECCMU_FLAG_ECC_DOUBLE_ERROR_BYTE_WRITE: ECC double error on byte write detected flag
\param[out] none
\retval RESET or SET
*/
FlagStatus rameccmu_monitor_flag_get(rameccmu_monitor_enum rameccmu_monitor, uint32_t flag)
{
if(RESET != ((RAMECCMU_MXSTAT(rameccmu_monitor)) & flag)){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear RAMECCMU monitor ECC error flag
\param[in] rameccmu_monitor: RAMECCMU monitor
only one parameter can be selected which is shown as below:
\arg RAMECCMU0_MONITOR0: RAMECCMU0 monitor 0
\arg RAMECCMU0_MONITOR1: RAMECCMU0 monitor 1
\arg RAMECCMU0_MONITOR2: RAMECCMU0 monitor 2
\arg RAMECCMU0_MONITOR3: RAMECCMU0 monitor 3
\arg RAMECCMU0_MONITOR4: RAMECCMU0 monitor 4
\arg RAMECCMU1_MONITOR0: RAMECCMU1 monitor 0
\arg RAMECCMU1_MONITOR1: RAMECCMU1 monitor 1
\arg RAMECCMU1_MONITOR2: RAMECCMU1 monitor 2
\param[in] flag: RAMECCMU monitor flag
one or more parameters can be selected which are shown as below:
\arg RAMECCMU_FLAG_ECC_SINGLE_ERROR: ECC single error detected and corrected flag
\arg RAMECCMU_FLAG_ECC_DOUBLE_ERROR: ECC double error detected flag
\arg RAMECCMU_FLAG_ECC_DOUBLE_ERROR_BYTE_WRITE: ECC double error on byte write detected flag
\param[out] none
\retval none
*/
void rameccmu_monitor_flag_clear(rameccmu_monitor_enum rameccmu_monitor, uint32_t flag)
{
RAMECCMU_MXSTAT(rameccmu_monitor) &= (uint32_t)(~flag);
}
/*!
\brief get RAMECCMU monitor ECC interrupt error flag
\param[in] rameccmu_monitor: RAMECCMU monitor
only one parameter can be selected which is shown as below:
\arg RAMECCMU0_MONITOR0: RAMECCMU0 monitor 0
\arg RAMECCMU0_MONITOR1: RAMECCMU0 monitor 1
\arg RAMECCMU0_MONITOR2: RAMECCMU0 monitor 2
\arg RAMECCMU0_MONITOR3: RAMECCMU0 monitor 3
\arg RAMECCMU0_MONITOR4: RAMECCMU0 monitor 4
\arg RAMECCMU1_MONITOR0: RAMECCMU1 monitor 0
\arg RAMECCMU1_MONITOR1: RAMECCMU1 monitor 1
\arg RAMECCMU1_MONITOR2: RAMECCMU1 monitor 2
\param[in] int_flag: RAMECCMU monitor flag
one or more parameters can be selected which are shown as below:
\arg RAMECCMU_INT_FLAG_ECC_SINGLE_ERROR: ECC single error detected and corrected flag
\arg RAMECCMU_INT_FLAG_ECC_DOUBLE_ERROR: ECC double error detected flag
\arg RAMECCMU_INT_FLAG_ECC_DOUBLE_ERROR_BYTE_WRITE: ECC double error on byte write detected flag
\param[out] none
\retval none
*/
FlagStatus rameccmu_monitor_interrupt_flag_get(rameccmu_monitor_enum rameccmu_monitor, uint32_t int_flag)
{
uint32_t ret1 = RESET;
uint32_t ret2 = RESET;
/* get the status of interrupt enable bit */
ret1 = RAMECCMU_MXCTL(rameccmu_monitor) & (uint32_t)(int_flag << 2U);
/* get the status of interrupt flag */
ret2 = RAMECCMU_MXSTAT(rameccmu_monitor) & int_flag;
if(ret1 && ret2) {
return SET;
} else {
return RESET;
}
}
/*!
\brief clear RAMECCMU monitor interrupt ECC error flag
\param[in] rameccmu_monitor: RAMECCMU monitor
only one parameter can be selected which is shown as below:
\arg RAMECCMU0_MONITOR0: RAMECCMU0 monitor 0
\arg RAMECCMU0_MONITOR1: RAMECCMU0 monitor 1
\arg RAMECCMU0_MONITOR2: RAMECCMU0 monitor 2
\arg RAMECCMU0_MONITOR3: RAMECCMU0 monitor 3
\arg RAMECCMU0_MONITOR4: RAMECCMU0 monitor 4
\arg RAMECCMU1_MONITOR0: RAMECCMU1 monitor 0
\arg RAMECCMU1_MONITOR1: RAMECCMU1 monitor 1
\arg RAMECCMU1_MONITOR2: RAMECCMU1 monitor 2
\param[in] int_flag: RAMECCMU monitor flag
one or more parameters can be selected which are shown as below:
\arg RAMECCMU_INT_FLAG_ECC_SINGLE_ERROR: ECC single error detected and corrected flag
\arg RAMECCMU_INT_FLAG_ECC_DOUBLE_ERROR: ECC double error detected flag
\arg RAMECCMU_INT_FLAG_ECC_DOUBLE_ERROR_BYTE_WRITE: ECC double error on byte write detected flag
\param[out] none
\retval none
*/
void rameccmu_monitor_interrupt_flag_clear(rameccmu_monitor_enum rameccmu_monitor, uint32_t int_flag)
{
RAMECCMU_MXSTAT(rameccmu_monitor) &= (uint32_t)(~int_flag);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,582 @@
/*!
\file gd32h7xx_rspdif.c
\brief RSPDIF driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_rspdif.h"
#define RSPDIF_INIT_MASK (uint32_t)0xFFC88004U /*!< RSPDIF parameter initialization mask */
#define RSPDIF_CKCNT5_OFFSET (uint32_t)16U /*!< RSPDIF the number of consecutive time clock cycles offset */
#define RSPDIF_DATA_F0_PREF_OFFSET (uint32_t)28U /*!< RSPDIF data format 0 preamble type offset */
#define RSPDIF_DATA_F0_C_OFFSET (uint32_t)27U /*!< RSPDIF data format 0 channel status offset */
#define RSPDIF_DATA_F0_U_OFFSET (uint32_t)26U /*!< RSPDIF data format 0 user bit offset */
#define RSPDIF_DATA_F0_V_OFFSET (uint32_t)25U /*!< RSPDIF data format 0 validity bit offset */
#define RSPDIF_DATA_F0_P_OFFSET (uint32_t)24U /*!< RSPDIF data format 0 parity error bit offset */
#define RSPDIF_DATA_F1_PREF_OFFSET (uint32_t)4U /*!< RSPDIF data format 1 preamble type offset */
#define RSPDIF_DATA_F1_C_OFFSET (uint32_t)3U /*!< RSPDIF data format 1 channel status offset */
#define RSPDIF_DATA_F1_U_OFFSET (uint32_t)2U /*!< RSPDIF data format 1 user bit offset */
#define RSPDIF_DATA_F1_V_OFFSET (uint32_t)1U /*!< RSPDIF data format 1 validity bit offset */
#define RSPDIF_DATA_F1_DATA_OFFSET (uint32_t)8U /*!< RSPDIF data format 1 data offset */
/*!
\brief reset the RSPDIF
\param[in] none
\param[out] none
\retval none
*/
void rspdif_deinit(void)
{
rcu_periph_reset_enable(RCU_RSPDIFRST);
rcu_periph_reset_disable(RCU_RSPDIFRST);
}
/*!
\brief initialize the parameters of RSPDIF structure with the default values
\param[in] none
\param[out] rspdif_parameter_struct: the initialized structure rspdif_parameter_struct pointer
\retval none
*/
void rspdif_struct_para_init(rspdif_parameter_struct *rspdif_struct)
{
/* configure the RSPDIF structure with the default values */
rspdif_struct->input_sel = RSPDIF_INPUT_IN0;
rspdif_struct->max_retrie = RSPDIF_MAXRETRIES_15;
rspdif_struct->wait_activity = RSPDIF_WAIT_FOR_ACTIVITY_ON;
rspdif_struct->channel_sel = RSPDIF_CHANNEL_A;
rspdif_struct->sample_format = RSPDIF_DATAFORMAT_MSB;
rspdif_struct->sound_mode = RSPDIF_STEREOMODE_ENABLE;
rspdif_struct->pre_type = RSPDIF_PREAMBLE_TYPE_MASK_OFF;
rspdif_struct->channel_status_bit = RSPDIF_CHANNEL_STATUS_MASK_OFF;
rspdif_struct->validity_bit = RSPDIF_VALIDITY_MASK_OFF;
rspdif_struct->parity_error_bit = RSPDIF_PERROR_MASK_OFF;
rspdif_struct->symbol_clk = RSPDIF_SYMBOL_CLK_OFF;
rspdif_struct->bak_symbol_clk = RSPDIF_BACKUP_SYMBOL_CLK_OFF;
}
/*!
\brief initialize the RSPDIF parameters
\param[in] rspdif_struct : RSPDIF parameter initialization stucture and the member values are shown as below:
input_sel : RSPDIF_INPUT_INx (x = 0 ~ 3)
max_retrie : RSPDIF_MAXRETRIES_NONE, RSPDIF_MAXRETRIES_3, RSPDIF_MAXRETRIES_15, RSPDIF_MAXRETRIES_63
wait_activity : RSPDIF_WAIT_FOR_ACTIVITY_OFF, RSPDIF_WAIT_FOR_ACTIVITY_ON
channel_sel : RSPDIF_CHANNEL_A, RSPDIF_CHANNEL_B
sample_format : RSPDIF_DATAFORMAT_LSB, RSPDIF_DATAFORMAT_MSB, RSPDIF_DATAFORMAT_32BITS
sound_mode : RSPDIF_STEREOMODE_DISABLE, RSPDIF_STEREOMODE_ENABLE
pre_type : RSPDIF_PREAMBLE_TYPE_MASK_OFF, RSPDIF_PREAMBLE_TYPE_MASK_ON
channel_status_bit : RSPDIF_CHANNEL_STATUS_MASK_OFF, RSPDIF_CHANNEL_STATUS_MASK_ON
validity_bit : RSPDIF_VALIDITY_MASK_OFF, RSPDIF_VALIDITY_MASK_ON
parity_error_bit : RSPDIF_PERROR_MASK_OFF, RSPDIF_PERROR_MASK_ON
symbol_clk : RSPDIF_BACKUP_SYMBOL_CLK_OFF, RSPDIF_BACKUP_SYMBOL_CLK_ON
bak_symbol_clk : RSPDIF_SYMBOL_CLK_OFF, RSPDIF_SYMBOL_CLK_ON
\param[out] none
\retval none
*/
void rspdif_init(rspdif_parameter_struct *rspdif_struct)
{
uint32_t reg = 0U;
reg = RSPDIF_CTL;
reg &= RSPDIF_INIT_MASK;
/* select the RSPDIF input */
reg |= rspdif_struct->input_sel;
/* configure the RSPDIF maximum allowed re-tries during synchronization phase */
reg |= rspdif_struct->max_retrie;
/* configure the RSPDIF wait for activity on the selected input */
reg |= rspdif_struct->wait_activity;
/* select the channel status from channel A or B */
reg |= rspdif_struct->channel_sel;
/* configure the RSPDIF data samples format */
reg |= rspdif_struct->sample_format;
/* select stereo or mono mode */
reg |= rspdif_struct->sound_mode;
/* select whether the preamble type value into the RSPDIF_DATA */
reg |= rspdif_struct->pre_type;
/* select whether the channel status and user bits are copied or not into the received frame */
reg |= rspdif_struct->channel_status_bit;
/* select whether the validity bit is copied or not into the received frame */
reg |= rspdif_struct->validity_bit;
/* select whether the parity error bit is copied or not into the received frame */
reg |= rspdif_struct->parity_error_bit;
/* configure the RSPDIF symbol clock generation */
reg |= rspdif_struct->symbol_clk;
/* configure the RSPDIF backup symbol clock generation */
reg |= rspdif_struct->bak_symbol_clk;
/* write to SPDIFRX_CTL register */
RSPDIF_CTL = (uint32_t)reg;
}
/*!
\brief specifies the RSPDIF peripheral state
\param[in] rspdif_state :
only one parameter can be selected which is shown as below:
\arg RSPDIF_STATE_SYNC: enable RSPDIF synchronization only
\arg RSPDIF_STATE_RCV : enable RSPDIF receiver
\param[out] none
\retval none
*/
void rspdif_enable(uint32_t mode)
{
uint32_t reg = 0U;
reg = RSPDIF_CTL;
/* clear RSPDIF state */
reg &= ~(uint32_t)RSPDIF_CTL_RXCFG;
reg |= (uint32_t)mode;
/* enable RSPDIF */
RSPDIF_CTL = (uint32_t)reg;
}
/*!
\brief disable RSPDIF
\param[in] none
\param[out] none
\retval none
*/
void rspdif_disable(void)
{
/* clear RSPDIF state */
RSPDIF_CTL &= ~(uint32_t)RSPDIF_CTL_RXCFG;
}
/*!
\brief enable RSPDIF symbol clock
\param[in] none
\param[out] none
\retval none
*/
void rspdif_symbol_clock_enable(void)
{
RSPDIF_CTL |= (uint32_t)RSPDIF_CTL_SCKEN;
}
/*!
\brief disable RSPDIF symbol clock
\param[in] none
\param[out] none
\retval none
*/
void rspdif_symbol_clock_disable(void)
{
RSPDIF_CTL &= ~(uint32_t)RSPDIF_CTL_SCKEN;
}
/*!
\brief enable RSPDIF backup symbol clock
\param[in] none
\param[out] none
\retval none
*/
void rspdif_backup_symbol_clock_enable(void)
{
RSPDIF_CTL |= (uint32_t)RSPDIF_CTL_BKSCKEN;
}
/*!
\brief disable RSPDIF backup symbol clock
\param[in] none
\param[out] none
\retval none
*/
void rspdif_backup_symbol_clock_disable(void)
{
RSPDIF_CTL &= ~(uint32_t)RSPDIF_CTL_BKSCKEN;
}
/*!
\brief enable the RSPDIF receiver DMA
\param[in] none
\param[out] none
\retval none
*/
void rspdif_dma_enable(void)
{
RSPDIF_CTL |= RSPDIF_CTL_DMAREN;
}
/*!
\brief disable the RSPDIF receiver DMA
\param[in] none
\param[out] none
\retval none
*/
void rspdif_dma_disable(void)
{
RSPDIF_CTL &= ~RSPDIF_CTL_DMAREN;
}
/*!
\brief enable the RSPDIF control buffer DMA
\param[in] none
\param[out] none
\retval none
*/
void rspdif_control_buffer_dma_enable(void)
{
RSPDIF_CTL |= RSPDIF_CTL_DMACBEN;
}
/*!
\brief disable the RSPDIF control buffer DMA
\param[in] none
\param[out] none
\retval none
*/
void rspdif_control_buffer_dma_disable(void)
{
RSPDIF_CTL &= ~RSPDIF_CTL_DMACBEN;
}
/*!
\brief RSPDIF read data
\param[in] none
\param[out] data_struct: RSPDIF data stucture and the member values are shown as below:
format : RSPDIF_DATAFORMAT_LSB, RSPDIF_DATAFORMAT_MSB,RSPDIF_DATAFORMAT_32BITS
preamble : RSPDIF_PREAMBLE_NONE,RSPDIF_PREAMBLE_B,RSPDIF_PREAMBLE_M,RSPDIF_PREAMBLE_W
channel_status : 0 or 1
user_bit : 0 or 1
validity : 0 or 1
parity_err : 0 or 1
data0 : 0 ~ 65535
data1 : 0 ~ 65535
\retval none
*/
void rspdif_data_read(rspdif_data_struct *data_struct)
{
/* get data format */
data_struct->format = RSPDIF_CTL & RSPDIF_CTL_RXDF;
switch(data_struct->format) {
/* data format 0 */
case RSPDIF_DATAFORMAT_LSB:
/* the preamble type */
data_struct->preamble = (uint32_t)((RSPDIF_DATA & RSPDIF_DATA_F0_PREF) >> RSPDIF_DATA_F0_PREF_OFFSET);
/* channel status bit */
data_struct->channel_status = (uint32_t)((RSPDIF_DATA & RSPDIF_DATA_F0_C) >> RSPDIF_DATA_F0_C_OFFSET);
/* user bit */
data_struct->user_bit = (uint32_t)((RSPDIF_DATA & RSPDIF_DATA_F0_U) >> RSPDIF_DATA_F0_U_OFFSET);
/* validity bit */
data_struct->validity = (uint32_t)((RSPDIF_DATA & RSPDIF_DATA_F0_V) >> RSPDIF_DATA_F0_V_OFFSET);
/* parity error bit */
data_struct->parity_err = (uint32_t)((RSPDIF_DATA & RSPDIF_DATA_F0_P) >> RSPDIF_DATA_F0_P_OFFSET);
/* data value 0 */
data_struct->data0 = (uint32_t)(RSPDIF_DATA & RSPDIF_DATA_F0_DATA0);
/* data value 1 */
data_struct->data1 = 0U;
break;
/* data format 1 */
case RSPDIF_DATAFORMAT_MSB:
/* the preamble type */
data_struct->preamble = (uint32_t)((RSPDIF_DATA & RSPDIF_DATA_F1_PREF) >> RSPDIF_DATA_F1_PREF_OFFSET);
/* channel status bit */
data_struct->channel_status = (uint32_t)((RSPDIF_DATA & RSPDIF_DATA_F1_C) >> RSPDIF_DATA_F1_C_OFFSET);
/* user bit */
data_struct->user_bit = (uint32_t)((RSPDIF_DATA & RSPDIF_DATA_F1_U) >> RSPDIF_DATA_F1_U_OFFSET);
/* validity bit */
data_struct->validity = (uint32_t)((RSPDIF_DATA & RSPDIF_DATA_F1_V) >> RSPDIF_DATA_F1_V_OFFSET);
/* parity error bit */
data_struct->parity_err = (uint32_t)(RSPDIF_DATA & RSPDIF_DATA_F1_P);
/* data value 0 */
data_struct->data0 = (uint32_t)((RSPDIF_DATA & RSPDIF_DATA_F1_DATA0) >> RSPDIF_DATA_F1_DATA_OFFSET);
/* data value 1 */
data_struct->data1 = 0U;
break;
/* data format 2 */
case RSPDIF_DATAFORMAT_32BITS:
/* the preamble type */
data_struct->preamble = 0U;
/* channel status bit */
data_struct->channel_status = 0U;
/* user bit */
data_struct->user_bit = 0U;
/* validity bit */
data_struct->validity = 0U;
/* parity error bit */
data_struct->parity_err = 0U;
/* data value 0 */
data_struct->data0 = (uint32_t)(RSPDIF_DATA & RSPDIF_DATA_F2_DATA1);
/* data value 1 */
data_struct->data1 = (uint32_t)(RSPDIF_DATA & RSPDIF_DATA_F2_DATA2);
break;
default:
break;
}
}
/*!
\brief get duration of 5 symbols counted using rspdif_ck
\param[in] none
\param[out] none
\retval duration of 5 symbols counted using rspdif_ck
*/
uint32_t rspdif_duration_of_symbols_get(void)
{
return ((uint32_t)((RSPDIF_STAT & RSPDIF_STAT_CKCNT5) >> RSPDIF_CKCNT5_OFFSET));
}
/*!
\brief get user data information
\param[in] none
\param[out] none
\retval user data information
*/
uint32_t rspdif_user_data_get(void)
{
return ((uint32_t)(RSPDIF_CHSTAT & RSPDIF_CHSTAT_USER));
}
/*!
\brief get channel status information
\param[in] none
\param[out] none
\retval channel status information
*/
uint32_t rspdif_channel_status_get(void)
{
return ((uint32_t)((RSPDIF_CHSTAT & RSPDIF_CHSTAT_CHS) >> 16U));
}
/*!
\brief get start of block
\param[in] none
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus rspdif_start_block_status_get(void)
{
if(RESET != (RSPDIF_CHSTAT & RSPDIF_CHSTAT_SOB)) {
return SET;
} else {
return RESET;
}
}
/*!
\brief get threshold low estimation
\param[in] none
\param[out] none
\retval low threshold value
*/
uint32_t rspdif_low_threshold_get(void)
{
return ((uint32_t)((RSPDIF_DTH & RSPDIF_DTH_THLO) >> 16U));
}
/*!
\brief get threshold high estimation
\param[in] none
\param[out] none
\retval high threshold value
*/
uint32_t rspdif_high_threshold_get(void)
{
return ((uint32_t)(RSPDIF_DTH & RSPDIF_DTH_THHI));
}
/*!
\brief get RSPDIF flag status
\param[in] flag: RSPDIF flag status
only one parameter can be selected which is shown as below:
\arg RSPDIF_FLAG_RBNE : RSPDIF RX buffer is not empty
\arg RSPDIF_FLAG_CBNE : RSPDIF RX control buffer is not empty
\arg RSPDIF_FLAG_PERR : RSPDIF parity error
\arg RSPDIF_FLAG_RXORERR : RSPDIF RX overrun error
\arg RSPDIF_FLAG_SYNDB : RSPDIF synchronization block detected
\arg RSPDIF_FLAG_SYNDO : RSPDIF synchronization done
\arg RSPDIF_FLAG_FRERR : RSPDIF frame error
\arg RSPDIF_FLAG_SYNERR : RSPDIF synchronization error
\arg RSPDIF_FLAG_TMOUTERR : RSPDIF time out error
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus rspdif_flag_get(uint16_t flag)
{
if(RESET != (RSPDIF_STAT & flag)) {
return SET;
} else {
return RESET;
}
}
/*!
\brief clear RSPDIF flag
\param[in] flag: RSPDIF flag status
one or more parameters can be selected which is shown as below:
\arg RSPDIF_FLAG_PERR : RSPDIF parity error
\arg RSPDIF_FLAG_RXORERR : RSPDIF RX overrun error
\arg RSPDIF_FLAG_SYNDB : RSPDIF synchronization block detected
\arg RSPDIF_FLAG_SYNDO : RSPDIF synchronization done
\param[out] none
\retval none
*/
void rspdif_flag_clear(uint16_t flag)
{
RSPDIF_STATC |= flag;
}
/*!
\brief enable RSPDIF interrupt
\param[in] interrupt: RSPDIF interrupt
one or more parameters can be selected which is shown as below:
\arg RSPDIF_INT_RBNE : RSPDIF RX buffer is not empty interrupt
\arg RSPDIF_INT_CBNE : RSPDIF RX control buffer is not empty interrupt
\arg RSPDIF_INT_PERR : RSPDIF parity error interrupt
\arg RSPDIF_INT_RXORERR: RSPDIF RX overrun error interrupt
\arg RSPDIF_INT_SYNDB : RSPDIF synchronization block detected interrupt
\arg RSPDIF_INT_SYNDO : RSPDIF synchronization done interrupt
\arg RSPDIF_INT_RXDCERR: RSPDIF data decoding error interrupt
\param[out] none
\retval none
*/
void rspdif_interrupt_enable(uint8_t interrupt)
{
RSPDIF_INTEN |= (uint32_t)interrupt;
}
/*!
\brief disable RSPDIF interrupt
\param[in] interrupt: RSPDIF interrupt
one or more parameters can be selected which is shown as below:
\arg RSPDIF_INT_RBNE : RSPDIF RX buffer is not empty interrupt
\arg RSPDIF_INT_CBNE : RSPDIF RX control buffer is not empty interrupt
\arg RSPDIF_INT_PERR : RSPDIF parity error interrupt
\arg RSPDIF_INT_RXORERR: RSPDIF RX overrun error interrupt
\arg RSPDIF_INT_SYNDB : RSPDIF synchronization block detected interrupt
\arg RSPDIF_INT_SYNDO : RSPDIF synchronization done interrupt
\arg RSPDIF_INT_RXDCERR: RSPDIF data decoding error interrupt
\param[out] none
\retval none
*/
void rspdif_interrupt_disable(uint8_t interrupt)
{
RSPDIF_INTEN &= ~(uint32_t)interrupt;
}
/*!
\brief get RSPDIF interrupt flag status
\param[in] int_flag: RSPDIF interrupt flag status
only one parameter can be selected which is shown as below:
\arg RSPDIF_INT_FLAG_RBNE : RSPDIF RX buffer is not empty interrupt flag
\arg RSPDIF_INT_FLAG_CBNE : RSPDIF RX control buffer is not empty interrupt flag
\arg RSPDIF_INT_FLAG_PERR : RSPDIF parity error interrupt flag
\arg RSPDIF_INT_FLAG_RXORERR : RSPDIF RX overrun error interrupt flag
\arg RSPDIF_INT_FLAG_SYNDB : RSPDIF synchronization block detected interrupt flag
\arg RSPDIF_INT_FLAG_SYNDO : RSPDIF synchronization done interrupt flag
\arg RSPDIF_INT_FLAG_FRERR : RSPDIF frame error interrupt flag
\arg RSPDIF_INT_FLAG_SYNERR : RSPDIF synchronization error interrupt flag
\arg RSPDIF_INT_FLAG_TMOUTERR : RSPDIF time out error interrupt flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus rspdif_interrupt_flag_get(uint16_t int_flag)
{
uint32_t reg1 = RSPDIF_STAT;
uint32_t reg2 = RSPDIF_INTEN;
switch(int_flag) {
/* RSPDIF RX buffer is not empty interrupt */
case RSPDIF_INT_FLAG_RBNE:
reg1 = reg1 & RSPDIF_STAT_RBNE;
reg2 = reg2 & RSPDIF_INTEN_RBNEIE;
break;
/* RSPDIF RX control buffer is not empty interrupt */
case RSPDIF_INT_FLAG_CBNE:
reg1 = reg1 & RSPDIF_STAT_CBNE;
reg2 = reg2 & RSPDIF_INTEN_CBNEIE;
break;
/* RSPDIF parity error interrupt */
case RSPDIF_INT_FLAG_PERR:
reg1 = reg1 & RSPDIF_STAT_PERR;
reg2 = reg2 & RSPDIF_INTEN_PERRIE;
break;
/* RSPDIF RX overrun error interrupt */
case RSPDIF_INT_FLAG_RXORERR:
reg1 = reg1 & RSPDIF_STAT_RXORERR;
reg2 = reg2 & RSPDIF_INTEN_RXORERRIE;
break;
/* RSPDIF synchronization block detected interrupt */
case RSPDIF_INT_FLAG_SYNDB:
reg1 = reg1 & RSPDIF_STAT_SYNDB;
reg2 = reg2 & RSPDIF_INTEN_SYNDBIE;
break;
/* RSPDIF synchronization done interrupt */
case RSPDIF_INT_FLAG_SYNDO:
reg1 = reg1 & RSPDIF_STAT_SYNDO;
reg2 = reg2 & RSPDIF_INTEN_SYNDOIE;
break;
/* RSPDIF frame error interrupt */
case RSPDIF_INT_FLAG_FRERR:
reg1 = reg1 & RSPDIF_STAT_FRERR;
reg2 = reg2 & RSPDIF_INTEN_RXDCERRIE;
break;
/* RSPDIF synchronization error interrupt */
case RSPDIF_INT_FLAG_SYNERR:
reg1 = reg1 & RSPDIF_STAT_SYNERR;
reg2 = reg2 & RSPDIF_INTEN_RXDCERRIE;
break;
/* RSPDIF time out error interrupt */
case RSPDIF_INT_FLAG_TMOUTERR:
reg1 = reg1 & RSPDIF_STAT_TMOUTERR;
reg2 = reg2 & RSPDIF_INTEN_RXDCERRIE;
break;
default :
break;
}
/*get RSPDIF interrupt flag status */
if((0U != reg1) && (0U != reg2)) {
return SET;
} else {
return RESET;
}
}
/*!
\brief clear RSPDIF interrupt flag status
\param[in] int_flag: RSPDIF interrupt flag status
one or more parameters can be selected which is shown as below:
\arg RSPDIF_INT_FLAG_PERR : RSPDIF parity error interrupt flag
\arg RSPDIF_INT_FLAG_RXORERR : RSPDIF RX overrun error interrupt flag
\arg RSPDIF_INT_FLAG_SYNDB : RSPDIF synchronization block detected interrupt flag
\arg RSPDIF_INT_FLAG_SYNDO : RSPDIF synchronization done interrupt flag
\param[out] none
\retval none
*/
void rspdif_interrupt_flag_clear(uint16_t int_flag)
{
RSPDIF_STATC |= int_flag ;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,384 @@
/*!
\file gd32h7xx_rtdec.c
\brief RTDEC driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_rtdec.h"
/* RTDEC firmware version offset macro */
#define ARE_FMVER_OFFSET (uint32_t)0x00000010U)
/*!
\brief reset RTDEC
\param[in] rtdec_periph: RTDECx(x = 0, 1)
\param[out] none
\retval none
*/
void rtdec_deinit(uint32_t rtdec_periph)
{
if(RTDEC0 == rtdec_periph){
/* reset RTDEC0 */
rcu_periph_reset_enable(RCU_RTDEC0RST);
rcu_periph_reset_disable(RCU_RTDEC0RST);
}
if(RTDEC1 == rtdec_periph) {
/* reset RTDEC1 */
rcu_periph_reset_enable(RCU_RTDEC1RST);
rcu_periph_reset_disable(RCU_RTDEC1RST);
}
}
/*!
\brief initialize the parameters of RTDEC struct with default values
\param[in] none
\param[out] rtdec_parameter_struct: the initialized struct rtdec_parameter_struct pointer
\retval none
*/
void rtdec_struct_para_init(rtdec_parameter_struct* rtdec_struct)
{
/* configure the structure with default value */
rtdec_struct->access_mode = (uint8_t)RTDEC_MODE_DATA_ACCESS;
rtdec_struct->key_crc = 0x00U;
rtdec_struct->fw_version = 0x0000U;
rtdec_struct->key = 0x00000000U;
rtdec_struct->nonce = 0x00000000U;
rtdec_struct->start_addr = 0x00000000U;
rtdec_struct->end_addr = 0x00000000U;
}
/*!
\brief initialize RTDEC
\param[in] rtdec_periph: RTDECx(x = 0, 1)
\param[in] rtdec_area: RTDEC_AREAx(x = 0, 1, 2, 3)
\param[in] rtdec_struct: RTDEC parameter initialization stuct members of the structure
and the member values are shown as below:
access_mode: RTDEC_MODE_CODE_ACCESS, RTDEC_MODE_DATA_ACCESS, RTDEC_MODE_BOTH_ACCESS
key_crc: CRC value of area key
fw_version: area firmware version
key: area key
nonce: area nonce
start_addr: area start address
end_addr: area end address
\param[out] none
\retval ErrStatus: ERROR or SUCCESS
*/
ErrStatus rtdec_init(uint32_t rtdec_periph, uint32_t rtdec_area, rtdec_parameter_struct *rtdec_struct)
{
uint8_t key_crc_reg = 0U;
uint32_t key_nonce_addr = 0U;
/* write the correct MODE[1:0] value and firmware version in ARExCFG register */
RTDEC_ARE_CFG(rtdec_periph, rtdec_area) &= ~(uint32_t)(RTDEC_MODE | RTDEC_ARE_FMVER);
RTDEC_ARE_CFG(rtdec_periph, rtdec_area) |= ((uint32_t)(rtdec_struct->access_mode)) | (uint32_t)(((uint32_t)(rtdec_struct->fw_version) << ARE_FMVER_OFFSET);
/* program ARExKEY registers */
key_nonce_addr = (uint32_t)rtdec_struct->key;
RTDEC_ARE_KEY0(rtdec_periph, rtdec_area) = *(uint32_t *)key_nonce_addr;
key_nonce_addr += 4U;
RTDEC_ARE_KEY1(rtdec_periph, rtdec_area) = *(uint32_t *)key_nonce_addr;
key_nonce_addr += 4U;
RTDEC_ARE_KEY2(rtdec_periph, rtdec_area) = *(uint32_t *)key_nonce_addr;
key_nonce_addr += 4U;
RTDEC_ARE_KEY3(rtdec_periph, rtdec_area) = *(uint32_t *)key_nonce_addr;
/* check the key CRC */
key_crc_reg = (uint8_t)GET_BITS(RTDEC_ARE_CFG(rtdec_periph, rtdec_area), 8U, 15U);
if(key_crc_reg != rtdec_struct->key_crc){
return ERROR;
}
/* program ARExNONCE registers */
key_nonce_addr = (uint32_t)rtdec_struct->nonce;
RTDEC_ARE_NONCE0(rtdec_periph, rtdec_area) = *(uint32_t *)key_nonce_addr;
key_nonce_addr += 4U;
RTDEC_ARE_NONCE1(rtdec_periph, rtdec_area) = *(uint32_t *)key_nonce_addr;
/* write the start address and end address of area */
RTDEC_ARE_SADDR(rtdec_periph, rtdec_area) = rtdec_struct->start_addr;
RTDEC_ARE_EADDR(rtdec_periph, rtdec_area) = rtdec_struct->end_addr;
return SUCCESS;
}
/*!
\brief configure RTDEC area data attribute
\param[in] rtdec_periph: RTDECx(x = 0, 1)
\param[in] rtdec_area: RTDEC_AREAx(x = 0, 1, 2, 3)
\param[in] access_mode: allowed access mode of data
only one parameter can be selected which is shown as below:
\arg RTDEC_MODE_CODE_ACCESS: code/instruction access only
\arg RTDEC_MODE_DATA_ACCESS: data access only
\arg RTDEC_MODE_BOTH_ACCESS: code and data access
\param[in] firmware_version: 16-bit number, version of data
\param[out] none
\retval none
*/
void rtdec_config(uint32_t rtdec_periph, uint32_t rtdec_area, uint8_t access_mode, uint16_t firmware_version)
{
/* write the correct MODE[1:0] value and firmware version in ARExCFG register */
RTDEC_ARE_CFG(rtdec_periph, rtdec_area) &= ~(uint32_t)(RTDEC_MODE | RTDEC_ARE_FMVER);
RTDEC_ARE_CFG(rtdec_periph, rtdec_area) |= ((uint32_t)access_mode) | ((uint32_t)((uint32_t)firmware_version << ARE_FMVER_OFFSET);
}
/*!
\brief configure RTDEC key or register lock
\param[in] rtdec_periph: RTDECx(x = 0, 1)
\param[in] rtdec_area: RTDEC_AREAx(x = 0, 1, 2, 3)
\param[in]: lock_type: key lock or register lock
\arg: RTDEC_ARE_CFG_LK: register lock
\arg: RTDEC_ARE_K_LK: key lock
\param[out] none
\retval none
*/
void rtdec_lock(uint32_t rtdec_periph, uint32_t rtdec_area, uint32_t lock_type)
{
RTDEC_ARE_CFG(rtdec_periph, rtdec_area) |= lock_type;
}
/*!
\brief initialize RTDEC area address
\param[in] rtdec_periph: RTDECx(x = 0, 1)
\param[in] rtdec_area: RTDEC_AREAx(x = 0, 1, 2, 3)
\param[in]: saddr: area start address, the 4 MSB bits and the 12 LSB bits are ignored
\param[in]: eaddr: area end address, the 4 MSB bits and the 12 LSB bits are ignored
\param[out] none
\retval none
*/
void rtdec_addr_init(uint32_t rtdec_periph, uint32_t rtdec_area, uint32_t saddr, uint32_t eaddr)
{
/* write the start address and end address of area */
RTDEC_ARE_SADDR(rtdec_periph, rtdec_area) = saddr;
RTDEC_ARE_EADDR(rtdec_periph, rtdec_area) = eaddr;
}
/*!
\brief initialize RTDEC nonce, nonce follows little endian format
\param[in] rtdec_periph: RTDECx(x = 0, 1)
\param[in] rtdec_area: RTDEC_AREAx(x = 0, 1, 2, 3)
\param[in]: nonce: an array containing 64-bit nonce data, little endian format
\param[out] none
\retval none
*/
void rtdec_nonce_init(uint32_t rtdec_periph, uint32_t rtdec_area, uint32_t* nonce)
{
uint32_t nonce_addr = (uint32_t)nonce;
/* program ARExNONCE registers */
RTDEC_ARE_NONCE0(rtdec_periph, rtdec_area) = *(uint32_t *)(nonce_addr);
nonce_addr += 4U;
RTDEC_ARE_NONCE1(rtdec_periph, rtdec_area) = *(uint32_t *)(nonce_addr);
}
/*!
\brief initialize RTDEC key, key follows little endian format
\param[in] rtdec_periph: RTDECx(x = 0, 1)
\param[in] rtdec_area: RTDEC_AREAx(x = 0, 1, 2, 3)
\param[in]: key: an array containing 128-bit key data, little endian format
\param[out] none
\retval none
*/
void rtdec_key_init(uint32_t rtdec_periph, uint32_t rtdec_area, uint32_t* key)
{
uint32_t key_addr = (uint32_t)key;
/* program ARExKEY registers */
RTDEC_ARE_KEY0(rtdec_periph, rtdec_area) = *(uint32_t *)(key_addr);
key_addr += 4U;
RTDEC_ARE_KEY1(rtdec_periph, rtdec_area) = *(uint32_t *)(key_addr);
key_addr += 4U;
RTDEC_ARE_KEY2(rtdec_periph, rtdec_area) = *(uint32_t *)(key_addr);
key_addr += 4U;
RTDEC_ARE_KEY3(rtdec_periph, rtdec_area) = *(uint32_t *)(key_addr);
}
/*!
\brief get CRC value of RTDEC key data
\param[in] rtdec_periph: RTDECx(x = 0, 1)
\param[in] rtdec_area: RTDEC_AREAx(x = 0, 1, 2, 3)
\param[out] none
\retval CRC value
*/
uint8_t rtdec_key_crc_get(uint32_t rtdec_periph, uint32_t rtdec_area)
{
return (uint8_t)GET_BITS(RTDEC_ARE_CFG(rtdec_periph, rtdec_area), 8U, 15U);
}
/*!
\brief enable RTDEC area
\param[in] rtdec_periph: RTDECx(x = 0, 1)
\param[in] rtdec_area: RTDEC_AREAx(x = 0, 1, 2, 3)
\param[out] none
\retval none
*/
void rtdec_enable(uint32_t rtdec_periph, uint32_t rtdec_area)
{
RTDEC_ARE_CFG(rtdec_periph, rtdec_area) |= RTDEC_ARE_EN;
}
/*!
\brief disable RTDEC area
\param[in] rtdec_periph: RTDECx(x = 0, 1)
\param[in] rtdec_area: RTDEC_AREAx(x = 0, 1, 2, 3)
\param[out] none
\retval none
*/
void rtdec_disable(uint32_t rtdec_periph, uint32_t rtdec_area)
{
RTDEC_ARE_CFG(rtdec_periph, rtdec_area) &= ~RTDEC_ARE_EN;
}
/*!
\brief get RTDEC error flag
\param[in] rtdec_periph: RTDECx(x = 0, 1)
\param[in]: flag: error flag
only one parameter can be selected which is shown as below:
\arg RTDEC_FLAG_SEC_ERROR: security error flag
\arg RTDEC_FLAG_MODE_ERROR: access mode error flag
\arg RTDEC_FLAG_KEY_ERROR: key error flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus rtdec_flag_get(uint32_t rtdec_periph, uint32_t flag)
{
if(RESET != (RTDEC_INTF(rtdec_periph) & flag)){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear RTDEC error flag
\param[in] rtdec_periph: RTDECx(x = 0, 1)
\param[in]: flag: error flag
only one parameter can be selected which is shown as below:
\arg RTDEC_FLAG_SEC_ERROR: security error flag
\arg RTDEC_FLAG_MODE_ERROR: access mode error flag
\arg RTDEC_FLAG_KEY_ERROR: key error flag
\param[out] none
\retval none
*/
void rtdec_flag_clear(uint32_t rtdec_periph, uint32_t flag)
{
RTDEC_INTC(rtdec_periph) |= flag;
}
/*!
\brief enable RTDEC interrupt
\param[in] rtdec_periph: RTDECx(x = 0, 1)
\param[in]: interrupt: interrupt type
one or more parameters can be selected which is shown as below:
\arg RTDEC_INT_SEC: security error interrupt
\arg RTDEC_INT_MODE: access mode error interrupt
\arg RTDEC_INT_KEY: key error interrupt
\param[out] none
\retval none
*/
void rtdec_interrupt_enable(uint32_t rtdec_periph, uint32_t interrupt)
{
RTDEC_INTEN(rtdec_periph) |= interrupt;
}
/*!
\brief disable RTDEC interrupt
\param[in] rtdec_periph: RTDECx(x = 0, 1)
\param[in]: interrupt: interrupt type
one or more parameters can be selected which is shown as below:
\arg RTDEC_INT_SEC: security error interrupt
\arg RTDEC_INT_MODE: access mode error interrupt
\arg RTDEC_INT_KEY: key error interrupt
\param[out] none
\retval none
*/
void rtdec_interrupt_disable(uint32_t rtdec_periph, uint32_t interrupt)
{
RTDEC_INTEN(rtdec_periph) &= ~interrupt;
}
/*!
\brief get RTDEC interrupt flag
\param[in] rtdec_periph: RTDECx(x = 0, 1)
\param[in]: int_flag: interrupt flag
only one parameter can be selected which is shown as below:
\arg RTDEC_INT_FLAG_SEC_ERROR: security error interrupt flag
\arg RTDEC_INT_FLAG_MODE_ERROR: access mode error interrupt flag
\arg RTDEC_INT_FLAG_KEY_ERROR: key error interrupt flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus rtdec_interrupt_flag_get(uint32_t rtdec_periph, uint32_t int_flag)
{
uint32_t interrupt_enable = 0U, interrupt_flag = 0U;
switch(int_flag){
/* RTDEC security error interrupt */
case RTDEC_INT_FLAG_SEC_ERROR:
interrupt_flag = RTDEC_INTF(rtdec_periph) & int_flag;
interrupt_enable = RTDEC_INTEN(rtdec_periph) & RTDEC_INT_SEC;
break;
/* RTDEC execute-only or execute-never error interrupt */
case RTDEC_INT_FLAG_MODE_ERROR:
interrupt_flag = RTDEC_INTF(rtdec_periph) & int_flag;
interrupt_enable = RTDEC_INTEN(rtdec_periph) & RTDEC_INT_MODE;
break;
/* RTDEC key error interrupt */
case RTDEC_INT_FLAG_KEY_ERROR:
interrupt_flag = RTDEC_INTF(rtdec_periph) & int_flag;
interrupt_enable = RTDEC_INTEN(rtdec_periph) & RTDEC_INT_KEY;
break;
default:
break;
}
/* get RTDEC interrupt flag status */
if(interrupt_flag && interrupt_enable){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear RTDEC interrupt flag
\param[in] rtdec_periph: RTDECx(x = 0, 1)
\param[in]: int_flag: interrupt flag
only one parameter can be selected which is shown as below:
\arg RTDEC_INT_FLAG_SEC_ERROR: security error interrupt flag
\arg RTDEC_INT_FLAG_MODE_ERROR: access mode error interrupt flag
\arg RTDEC_INT_FLAG_KEY_ERROR: key error interrupt flag
\param[out] none
\retval none
*/
void rtdec_interrupt_flag_clear(uint32_t rtdec_periph, uint32_t int_flag)
{
RTDEC_INTC(rtdec_periph) |= int_flag;
}
@@ -0,0 +1,792 @@
/*!
\file gd32h7xx_sai.c
\brief SAI driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_sai.h"
/* SAI pdm mode microphone delay mask */
#define PDM_MICROPHONE_DELAY_MASK ((uint32_t)0x00000007U)
/*!< bit offset of MTFCNT in SAI_CFG1 */
#define CFG1_MTFCNT_OFFSET ((uint32_t)0x00000007U)
/*!
\brief reset SAI
\param[in] sai_periph: SAIx(x = 0,1,2)
\param[out] none
\retval none
*/
void sai_deinit(uint32_t sai_periph)
{
switch(sai_periph) {
case SAI0:
/* reset SAI0 */
rcu_periph_reset_enable(RCU_SAI0RST);
rcu_periph_reset_disable(RCU_SAI0RST);
break;
case SAI1:
/* reset SAI1 */
rcu_periph_reset_enable(RCU_SAI1RST);
rcu_periph_reset_disable(RCU_SAI1RST);
break;
case SAI2:
/* reset SAI2 */
rcu_periph_reset_enable(RCU_SAI2RST);
rcu_periph_reset_disable(RCU_SAI2RST);
break;
default:
break;
}
}
/*!
\brief initialize the parameter of SAI structure with a default value
\param[in] none
\param[out] sai_init_stuct: the initialization data needed to initialize SAI
\retval none
*/
void sai_struct_para_init(sai_parameter_struct *sai_init_stuct)
{
/* initialize the initpara struct member with the default value */
sai_init_stuct->operating_mode = SAI_MASTER_TRANSMITTER;
sai_init_stuct->protocol = SAI_PROTOCOL_POLYMORPHIC;
sai_init_stuct->data_width = SAI_DATAWIDTH_32BIT;
sai_init_stuct->shift_dir = SAI_SHIFT_MSB;
sai_init_stuct->sample_edge = SAI_SAMPEDGE_FALLING;
sai_init_stuct->sync_mode = SAI_SYNCMODE_ASYNC;
sai_init_stuct->output_drive = SAI_OUTPUT_WITH_SAIEN;
sai_init_stuct->clk_div_bypass = SAI_CLKDIV_BYPASS_OFF;
sai_init_stuct->mclk_div = SAI_MCLKDIV_1;
sai_init_stuct->mclk_oversampling = SAI_MCLK_OVERSAMP_256;
sai_init_stuct->mclk_enable = SAI_MCLK_DISABLE;
sai_init_stuct->fifo_threshold = SAI_FIFOTH_EMPTY;
}
/*!
\brief initialize the parameter of SAI frame structure with a default value
\param[in] none
\param[out] sai_frame_init_struct: the initialization data needed to initialize SAI frame
\retval none
*/
void sai_frame_struct_para_init(sai_frame_parameter_struct *sai_frame_init_struct)
{
/* initialize the initpara struct member with the default value */
sai_frame_init_struct->frame_width = 256U;
sai_frame_init_struct->frame_sync_width = 128U;
sai_frame_init_struct->frame_sync_function = SAI_FS_FUNC_START;
sai_frame_init_struct->frame_sync_polarity = SAI_FS_POLARITY_LOW;
sai_frame_init_struct->frame_sync_offset = SAI_FS_OFFSET_BEGINNING;
}
/*!
\brief initialize the parameter of SAI slot structure with a default value
\param[in] none
\param[out] sai_slot_init_struct: the initialization data needed to initialize SAI slot
\retval none
*/
void sai_slot_struct_para_init(sai_slot_parameter_struct *sai_slot_init_struct)
{
/* initialize the initpara struct member with the default value */
sai_slot_init_struct->slot_number = 16U;
sai_slot_init_struct->slot_width = SAI_SLOT_WIDTH_DATA;
sai_slot_init_struct->data_offset = 0U;
sai_slot_init_struct->slot_active = SAI_SLOT_ACTIVE_NONE;
}
/*!
\brief initialize SAI
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] block: specify which bolck is initialized
only one parameter can be selected which is shown as below:
\arg SAI_BLOCKx(x = 0,1)
\param[in] sai_struct: SAI parameter initialization stuct members of the structure
and the member values are shown as below:
operating_mode: SAI_MASTER_TRANSMITTER, SAI_MASTER_RECEIVER, SAI_SLAVE_TRANSMITTER, SAI_SLAVE_RECEIVER;
protocol: SAI_PROTOCOL_POLYMORPHIC, SAI_PROTOCOL_SPDIF, SAI_PROTOCOL_AC97
data_width: SAI_DATA_WIDTH_xBIT (x = 8, 10, 16, 20, 24, 32)
shift_dir: SAI_SHIFT_MSB, SAI_SHIFT_LSB
sample_edge: SAI_SAMPEDGE_FALLING, SAI_SAMPEDGE_RISING
sync_mode: SAI_SYNCMODE_ASYNC, SAI_SYNCMODE_OTHERBLOCK, SAI_SYNCMODE_EXTERNALSAI
output_drive: SAI_OUTPUT_WITH_SAIEN, SAI_OUTPUT_NOW
clk_div_bypass: SAI_CLKDIV_BYPASS_OFF, SAI_CLKDIV_BYPASS_ON
mck_div: SAI_MCLKDIV_x (x = 1,2,..,63)
mck_oversampling: SAI_MASTERCLK_OVERSAMP_256, SAI_MASTERCLK_OVERSAMP_512
mck_enable: SAI_MASTERCLK_DISABLE, SAI_MASTERCLK_ENABLE
fifo_threshold: SAI_FIFOTH_EMPTY, SAI_FIFOTH_QUARTER, SAI_FIFOTH_HALF, SAI_FIFOTH_THREE_QUARTER, SAI_FIFOTH_FULL
\param[out] none
\retval none
*/
void sai_init(uint32_t sai_periph, uint32_t block, sai_parameter_struct *sai_struct)
{
uint32_t reg = 0U;
/* configure the SAI CFGR0 value */
reg = SAI_CFG0(sai_periph, block);
reg &= ~(SAI_CFG0_OPTMOD | SAI_CFG0_PROT | \
SAI_CFG0_DATAWD | SAI_CFG0_SHIFTDIR | \
SAI_CFG0_SAMPEDGE | SAI_CFG0_SYNCMOD | \
SAI_CFG0_ODRIV | SAI_CFG0_BYPASS | \
SAI_CFG0_MDIV | SAI_CFG0_MOSPR | \
SAI_CFG0_MCLKEN | SAI_CFG0_SAIEN);
reg |= (uint32_t)(sai_struct->operating_mode | sai_struct->protocol | \
sai_struct->data_width | sai_struct->shift_dir | \
sai_struct->sample_edge | sai_struct->sync_mode | \
sai_struct->output_drive | sai_struct->clk_div_bypass | \
sai_struct->mclk_div | sai_struct->mclk_oversampling | \
sai_struct->mclk_enable);
SAI_CFG0(sai_periph, block) = reg;
/* configure the SAI CFGR1 FIFO threshold */
reg = SAI_CFG1(sai_periph, block);
reg &= ~SAI_CFG1_FFTH;
reg |= (uint32_t)(sai_struct->fifo_threshold);
SAI_CFG1(sai_periph, block) = reg;
}
/*!
\brief initialize SAI frame
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] block: specify which bolck is initialized
only one parameter can be selected which is shown as below:
\arg SAI_BLOCKx(x=0,1)
\param[in] sai_frame_struct: SAI frame parameter initialization stuct members of the structure
and the member values are shown as below:
frame_width: 1~256, frame width
frame_sync_width: 1~128, frame synchronization active width
frame_sync_function: SAI_FS_FUNC_START, SAI_FS_FUNC_START_CHANNEL
frame_sync_polarity: SAI_FS_POLARITY_LOW, SAI_FS_POLARITY_HIGH
frame_sync_offset: SAI_FS_OFFSET_BEGINNING, SAI_FS_OFFSET_ONEBITBEFORE
\param[out] none
\retval none
*/
void sai_frame_init(uint32_t sai_periph, uint32_t block, sai_frame_parameter_struct *sai_frame_struct)
{
uint32_t reg = 0U;
reg = SAI_FCFG(sai_periph, block);
reg &= ~(SAI_FCFG_FWD | SAI_FCFG_FSAWD | SAI_FCFG_FSFUNC | \
SAI_FCFG_FSPL | SAI_FCFG_FSOST);
reg |= (uint32_t)(sai_frame_struct->frame_sync_offset | \
sai_frame_struct->frame_sync_polarity | \
sai_frame_struct->frame_sync_function | \
((sai_frame_struct->frame_sync_width - 1U) << 8U) | \
(sai_frame_struct->frame_width - 1U));
/* config the SAI freame */
SAI_FCFG(sai_periph, block) = reg;
}
/*!
\brief initialize SAI slot
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] block: specify which bolck is initialized
only one parameter can be selected which is shown as below:
\arg SAI_BLOCKx(x=0,1)
\param[in] sai_slot_struct: SAI slot parameter initialization stuct members of the structure
and the member values are shown as below:
slot_number: 1~16, slot number
slot_width: SAI_SLOTWIDTH_DATA, SAI_SLOTWIDTH_16BIT, SAI_SLOTWIDTH_32BIT
data_offset: 0~31, data offset
slot_active: one or more parameters can be selected, SAI_SLOT_ACTIVE_NONE, SAI_SLOT_ACTIVE_x(x=0..15), SAI_SLOT_ACTIVE_ALL
\param[out] none
\retval none
*/
void sai_slot_init(uint32_t sai_periph, uint32_t block, sai_slot_parameter_struct *sai_slot_struct)
{
uint32_t reg = 0U;
reg = SAI_SCFG(sai_periph, block);
reg &= ~(SAI_SCFG_DATAOST | SAI_SCFG_SLOTWD | SAI_SCFG_SLOTNUM | SAI_SCFG_SLOTAV);
reg = (uint32_t)(((sai_slot_struct->slot_number - 1U) << 8U) | \
sai_slot_struct->slot_width | \
sai_slot_struct->data_offset | \
sai_slot_struct->slot_active);
/* configure the SAI slot */
SAI_SCFG(sai_periph, block) = reg;
}
/*!
\brief SAI enable
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] block: specify which bolck is initialized
only one parameter can be selected which is shown as below:
\arg SAI_BLOCKx(x=0,1)
\param[out] none
\retval none
*/
void sai_enable(uint32_t sai_periph, uint32_t block)
{
SAI_CFG0(sai_periph, block) |= SAI_CFG0_SAIEN;
}
/*!
\brief SAI disable
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] block: specify which bolck is initialized
only one parameter can be selected which is shown as below:
\arg SAI_BLOCKx(x=0,1)
\param[out] none
\retval none
*/
void sai_disable(uint32_t sai_periph, uint32_t block)
{
SAI_CFG0(sai_periph, block) &= ~SAI_CFG0_SAIEN;
}
/*!
\brief SAI serial data near inactive slot output management
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] block: specify which bolck is initialized
only one parameter can be selected which is shown as below:
\arg SAI_BLOCKx(x=0,1)
\param[in] sdout: serial data output management
only one parameter can be selected which is shown as below:
\arg SAI_SDLINE_DRIVE: SD line output is driven entirely during the audio frame
\arg SAI_SDLINE_RELEASE: SD line output is released near inactive slots
\param[out] none
\retval none
*/
void sai_sdoutput_config(uint32_t sai_periph, uint32_t block, uint32_t sdout)
{
SAI_CFG1(sai_periph, block) &= ~SAI_CFG1_SDOM;
SAI_CFG1(sai_periph, block) |= sdout;
}
/*!
\brief configure SAI mono mode
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] block: specify which bolck is initialized
only one parameter can be selected which is shown as below:
\arg SAI_BLOCKx (x=0,1)
\param[in] mono: stereo and mono mode selection
only one parameter can be selected which is shown as below:
\arg SAI_STEREO_MODE: stereo mode
\arg SAI_MONO_MODE: mono mode
\param[out] none
\retval none
*/
void sai_monomode_config(uint32_t sai_periph, uint32_t block, uint32_t mono)
{
SAI_CFG0(sai_periph, block) &= ~SAI_CFG0_MONO;
SAI_CFG0(sai_periph, block) |= mono ;
}
/*!
\brief configure SAI companding mode
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] block: specify which bolck is initialized
only one parameter can be selected which is shown as below:
\arg SAI_BLOCKx (x=0,1)
\param[in] compander: compander mode
only one parameter can be selected which is shown as below:
\arg SAI_COMPANDER_OFF: no compansion applies
\arg SAI_COMPANDER_ULAW: u-law algorithm
\arg SAI_COMPANDER_ALAW: A-law algorithm
\param[in] complement:complement mode
only one parameter can be selected which is shown as below:
\arg SAI_COMPLEMENT_1S: data represented in 1's complement form
\arg SAI_COMPLEMENT_2S: data represented in 2's complement form
\param[out] none
\retval none
*/
void sai_companding_config(uint32_t sai_periph, uint32_t block, uint32_t compander,
uint32_t complement)
{
uint32_t reg = 0U;
reg = SAI_CFG1(sai_periph, block);
reg &= ~(SAI_CFG1_CPLMOD | SAI_CFG1_CPAMOD);
reg |= (compander | complement);
SAI_CFG1(sai_periph, block) = reg;
}
/*!
\brief SAI mute detected enable or mute send enable
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] block: specify which bolck is initialized
only one parameter can be selected which is shown as below:
\arg SAI_BLOCKx (x=0,1)
\param[out] none
\retval none
*/
void sai_mute_enable(uint32_t sai_periph, uint32_t block)
{
SAI_CFG1(sai_periph, block) |= SAI_CFG1_MT;
}
/*!
\brief SAI mute detected disable or mute send disable
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] block: specify which bolck is initialized
only one parameter can be selected which is shown as below:
\arg SAI_BLOCKx (x=0,1)
\param[out] none
\retval none
*/
void sai_mute_disable(uint32_t sai_periph, uint32_t block)
{
SAI_CFG1(sai_periph, block) &= ~SAI_CFG1_MT;
}
/*!
\brief configure SAI mute value
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] block: specify which bolck is initialized
only one parameter can be selected which is shown as below:
\arg SAI_BLOCKx (x=0,1)
\param[in] value: mute value
only one parameter can be selected which are shown as below:
\arg SAI_MUTESENT_0: 0 is sent via the serial data line when mute is on
\arg SAI_MUTESENT_LASTFREAM: If SLOTNUM is less or equals to two, last frame is sent via the serial data line
\param[out] none
\retval none
*/
void sai_mute_value_config(uint32_t sai_periph, uint32_t block, uint32_t value)
{
SAI_CFG1(sai_periph, block) &= ~SAI_CFG1_MTVAL;
SAI_CFG1(sai_periph, block) |= value;
}
/*!
\brief configure SAI mute frame count
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] block: specify which bolck is initialized
only one parameter can be selected which is shown as below:
\arg SAI_BLOCKx (x=0,1)
\param[in] count: 0~63, mute frame count
\param[out] none
\retval none
*/
void sai_mute_count_config(uint32_t sai_periph, uint32_t block, uint32_t count)
{
uint32_t reg = 0U;
reg = SAI_CFG1(sai_periph, block);
reg &= ~SAI_CFG1_MTFCNT;
reg |= count << CFG1_MTFCNT_OFFSET;
SAI_CFG1(sai_periph, block) = reg;
}
/*!
\brief SAI transmit data
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] block: specify which bolck is initialized
only one parameter can be selected which is shown as below:
\arg SAI_BLOCKx (x=0,1)
\param[in] data: 32-bit data
\param[out] none
\retval none
*/
void sai_data_transmit(uint32_t sai_periph, uint32_t block, uint32_t data)
{
SAI_DATA(sai_periph, block) = data;
}
/*!
\brief SAI receive data
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] block: specify which bolck is initialized
only one parameter can be selected which is shown as below:
\arg SAI_BLOCKx (x=0,1)
\param[out] none
\retval received data
*/
uint32_t sai_data_receive(uint32_t sai_periph, uint32_t block)
{
return SAI_DATA(sai_periph, block);
}
/*!
\brief get SAI fifo status
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] block: specify which bolck is initialized
only one parameter can be selected which is shown as below:
\arg SAI_BLOCKx (x=0,1)
\param[out] none
\retval state of fifo
\arg FIFO_EMPTY: empty
\arg FIFO_EMPTY_TO_1_4_FULL: empty < fifo_level <= 1/4_full
\arg FIFO_1_4_FULL_TO_1_2_FULL: 1/4_full < fifo_level <= 1/2_full
\arg FIFO_1_2_FULL_TO_3_4_FULL: 1/2_full < fifo_level <= 3/4_full
\arg FIFO_3_4_FULL_TO_FULL: 3/4_full < fifo_level < full
\arg FIFO_FULL: full
*/
sai_fifo_state_enum sai_fifo_status_get(uint32_t sai_periph, uint32_t block)
{
sai_fifo_state_enum sai_fifo_state = FIFO_EMPTY;
if(SAI_FIFO_STAT_EMPTY == (SAI_STAT(sai_periph, block) & SAI_STAT_FFSTAT)) {
sai_fifo_state = FIFO_EMPTY;
} else if(SAI_FIFO_STAT_QUARTER == (SAI_STAT(sai_periph, block) & SAI_STAT_FFSTAT)) {
sai_fifo_state = FIFO_EMPTY_TO_1_4_FULL;
} else if(SAI_FIFO_STAT_HALF == (SAI_STAT(sai_periph, block) & SAI_STAT_FFSTAT)) {
sai_fifo_state = FIFO_1_4_FULL_TO_1_2_FULL;
} else if(SAI_FIFO_STAT_THREE_QUARTER == (SAI_STAT(sai_periph, block) & SAI_STAT_FFSTAT)) {
sai_fifo_state = FIFO_1_2_FULL_TO_3_4_FULL;
} else if(SAI_FIFO_STAT_NEARFULL == (SAI_STAT(sai_periph, block) & SAI_STAT_FFSTAT)) {
sai_fifo_state = FIFO_3_4_FULL_TO_FULL;
} else {
sai_fifo_state = FIFO_FULL;
}
return sai_fifo_state;
}
/*!
\brief SAI fifo flush
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] block: specify which bolck is initialized
only one parameter can be selected which is shown as below:
\arg SAI_BLOCKx (x=0,1)
\param[out] none
\retval none
*/
void sai_fifo_flush(uint32_t sai_periph, uint32_t block)
{
SAI_CFG1(sai_periph, block) |= SAI_CFG1_FLUSH;
}
/*!
\brief enable SAI dma
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] block: specify which bolck is initialized
only one parameter can be selected which is shown as below:
\arg SAI_BLOCKx (x=0,1)
\param[out] none
\retval none
*/
void sai_dma_enable(uint32_t sai_periph, uint32_t block)
{
SAI_CFG0(sai_periph, block) |= SAI_CFG0_DMAEN;
}
/*!
\brief disable SAI dma
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] block: specify which bolck is initialized
only one parameter can be selected which is shown as below:
\arg SAI_BLOCKx (x=0,1)
\param[out] none
\retval none
*/
void sai_dma_disable(uint32_t sai_periph, uint32_t block)
{
SAI_CFG0(sai_periph, block) &= ~SAI_CFG0_DMAEN;
}
/*!
\brief SAI synchronization input select
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] input: specify which external SAI to be select for synchronization
only one parameter can be selected which are shown as below:
\arg SAI_SYNCINPUT_SAI0: SAI1 or SAI2 selects the synchronization coming from SAI0
\arg SAI_SYNCINPUT_SAI1: SAI0 or SAI2 selects the synchronization coming from SAI1
\arg SAI_SYNCINPUT_SAI2: SAI0 or SAI1 selects the synchronization coming from SAI2
\param[out] none
\retval none
*/
void sai_sync_input_config(uint32_t sai_periph, uint32_t input)
{
uint32_t reg = 0U;
reg = SAI_SYNCFG(sai_periph);
reg &= ~SAI_SYNCFG_SYNI;
reg |= input;
SAI_SYNCFG(sai_periph) = reg;
}
/*!
\brief SAI synchronization output select
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] output: specify which block to be used for further synchronization for others SAI
only one parameter can be selected which are shown as below:
\arg SAI_SYNCOUTPUT_OFF: no synchronization output signals
\arg SAI_SYNCOUTPUT_BLOCK0: block 0 used for further synchronization for others SAI
\arg SAI_SYNCOUTPUT_BLOCK1: block 1 used for further synchronization for others SAI
\param[out] none
\retval none
*/
void sai_sync_output_config(uint32_t sai_periph, uint32_t output)
{
uint32_t reg = 0U;
reg = SAI_SYNCFG(sai_periph);
reg &= ~SAI_SYNCFG_SYNO;
reg |= output;
SAI_SYNCFG(sai_periph) = reg;
}
/*!
\brief enable SAI pdm mode
\param[in] sai_periph: SAIx(x=0,1,2)
\param[out] none
\retval none
*/
void sai_pdm_enable(uint32_t sai_periph)
{
SAI_PDMCTL(sai_periph) |= SAI_PDMCTL_PDMEN;
}
/*!
\brief disable SAI pdm mode
\param[in] sai_periph: SAIx(x=0,1,2)
\param[out] none
\retval none
*/
void sai_pdm_disable(uint32_t sai_periph)
{
SAI_PDMCTL(sai_periph) &= ~SAI_PDMCTL_PDMEN;
}
/*!
\brief configure SAI pdm mode microphone number
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] microphonenum: 2, 4, 6 or 8(not applicable to GD32H7xx), select microphones number
\param[out] none
\retval none
*/
void sai_pdm_microphone_number_config(uint32_t sai_periph, uint32_t microphonenum)
{
uint32_t temp = SAI_PDMCTL(sai_periph);
temp &= ~SAI_PDMCTL_MICNUMSEL;
temp |= ((microphonenum / 2U - 1U) << 4U);
SAI_PDMCTL(sai_periph) = temp;
}
/*!
\brief configure SAI pdm mode microphone delay
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] microphone: specify which microphone delay parameter to config
only one parameter can be selected which are shown as below:
\arg SAI_PDM_MICROPHONE0_L: microphone 0 channel left
\arg SAI_PDM_MICROPHONE0_R: microphone 0 channel right
\arg SAI_PDM_MICROPHONE1_L: microphone 1 channel left
\arg SAI_PDM_MICROPHONE1_R: microphone 1 channel right
\arg SAI_PDM_MICROPHONE2_L: microphone 2 channel left
\arg SAI_PDM_MICROPHONE2_R: microphone 2 channel right
\arg SAI_PDM_MICROPHONE3_L: microphone 3 channel left, (not applicable to GD32H7xx)
\arg SAI_PDM_MICROPHONE3_R: microphone 3 channel right, (not applicable to GD32H7xx)
\param[in] delay: 0~7, the microphone data flow delay period
\param[out] none
\retval none
*/
void sai_pdm_delay_config(uint32_t sai_periph, uint32_t microphone, uint32_t delay)
{
uint32_t temp = SAI_PDMCFG(sai_periph);
temp &= ~(PDM_MICROPHONE_DELAY_MASK << (microphone * 4U));
temp |= (delay << (microphone * 4U));
SAI_PDMCFG(sai_periph) = temp;
}
/*!
\brief enable SAI pdm mode clock line 0
\param[in] sai_periph: SAIx(x=0,1,2)
\param[out] none
\retval none
*/
void sai_pdm_clk0_enable(uint32_t sai_periph)
{
SAI_PDMCTL(sai_periph) |= SAI_PDMCTL_CLKL0EN;
}
/*!
\brief disable SAI pdm mode clock line 0
\param[in] sai_periph: SAIx(x=0,1,2)
\param[out] none
\retval none
*/
void sai_pdm_clk0_disable(uint32_t sai_periph)
{
SAI_PDMCTL(sai_periph) &= ~SAI_PDMCTL_CLKL0EN;
}
/*!
\brief enable SAI pdm mode clock line 1
\param[in] sai_periph: SAIx(x=0,1,2)
\param[out] none
\retval none
*/
void sai_pdm_clk1_enable(uint32_t sai_periph)
{
SAI_PDMCTL(sai_periph) |= SAI_PDMCTL_CLKL1EN;
}
/*!
\brief disable SAI pdm mode clock line 1
\param[in] sai_periph: SAIx(x=0,1,2)
\param[out] none
\retval none
*/
void sai_pdm_clk1_disable(uint32_t sai_periph)
{
SAI_PDMCTL(sai_periph) &= ~SAI_PDMCTL_CLKL1EN;
}
/*!
\brief enable the SAI interrupt
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] block: specify which bolck is initialized
only one parameter can be selected which is shown as below:
\arg SAI_BLOCKx(x=0,1)
\param[in] interrupt: specify which interrupt to enable
one or more parameters can be selected which are shown as below:
\arg SAI_INT_OUERR: FIFO overrun or underrun interrupt enable
\arg SAI_INT_MTDET: mute detection interrupt enable
\arg SAI_INT_ERRCK: error clock interrupt enable
\arg SAI_INT_FFREQ: FIFO request interrupt enable
\arg SAI_INT_ACNRDY: audio codec not ready interrupt enable
\arg SAI_INT_FSADET: frame synchronization advanced detection interrupt enable
\arg SAI_INT_FSPDET: frame synchronization postpone detection interrupt enable
\param[out] none
\retval none
*/
void sai_interrupt_enable(uint32_t sai_periph, uint32_t block, uint32_t interrupt)
{
SAI_INTEN(sai_periph, block) |= interrupt;
}
/*!
\brief disable the SAI interrupt
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] block: specify which bolck is initialized
only one parameter can be selected which is shown as below:
\arg SAI_BLOCKx(x=0,1)
\param[in] interrupt: specify which interrupt to disable
one or more parameters can be selected which are shown as below:
\arg SAI_INT_OUERR: FIFO overrun or underrun interrupt
\arg SAI_INT_MTDET: mute detection interrupt
\arg SAI_INT_ERRCK: error clock interrupt
\arg SAI_INT_FFREQ: FIFO request interrupt
\arg SAI_INT_ACNRDY: audio codec not ready interrupt
\arg SAI_INT_FSADET: frame synchronization advanced detection interrupt
\arg SAI_INT_FSPDET: frame synchronization postpone detection interrupt
\param[out] none
\retval none
*/
void sai_interrupt_disable(uint32_t sai_periph, uint32_t block, uint32_t interrupt)
{
SAI_INTEN(sai_periph, block) &= ~interrupt;
}
/*!
\brief get the SAI interrupt flag
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] block: specify which bolck is initialized
only one parameter can be selected which is shown as below:
\arg SAI_BLOCKx(x=0,1)
\param[in] interrupt: specify which interrupt flag to get
only one parameter can be selected which are shown as below:
\arg SAI_FLAG_OUERR: FIFO overrun or underrun interrupt flag
\arg SAI_FLAG_MTDET: mute detection interrupt flag
\arg SAI_FLAG_ERRCK: error clock interrupt flag
\arg SAI_FLAG_FFREQ: FIFO request interrupt flag
\arg SAI_FLAG_ACNRDY: audio codec not ready interrupt flag
\arg SAI_FLAG_FSADET: frame synchronization advanced detection interrupt flag
\arg SAI_FLAG_FSPDET: frame synchronization postpone detection interrupt flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus sai_interrupt_flag_get(uint32_t sai_periph, uint32_t block, uint32_t interrupt)
{
uint32_t inten = 0U;
inten = SAI_INTEN(sai_periph, block) & interrupt;
if((RESET != (SAI_STAT(sai_periph, block) & interrupt)) && (RESET != inten)) {
return SET;
} else {
return RESET;
}
}
/*!
\brief clear the SAI interrupt flag
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] block: specify which bolck is initialized
only one parameter can be selected which is shown as below:
\arg SAI_BLOCKx(x=0,1)
\param[in] interrupt: specify which interrupt flag to clear
one or more parameters can be selected which are shown as below:
\arg SAI_FLAG_OUERR: FIFO overrun or underrun interrupt flag
\arg SAI_FLAG_MTDET: mute detection interrupt flag
\arg SAI_FLAG_ERRCK: error clock interrupt flag
\arg SAI_FLAG_ACNRDY: audio codec not ready interrupt flag
\arg SAI_FLAG_FSADET: frame synchronization advanced detection interrupt flag
\arg SAI_FLAG_FSPDET: frame synchronization postpone detection interrupt flag
\param[out] none
\retval none
*/
void sai_interrupt_flag_clear(uint32_t sai_periph, uint32_t block, uint32_t interrupt)
{
SAI_INTC(sai_periph, block) = interrupt;
}
/*!
\brief get the SAI flag
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] block: specify which bolck is initialized
only one parameter can be selected which is shown as below:
\arg SAI_BLOCKx(x=0,1)
\param[in] flag: specify which flag to get
only one parameter can be selected which are shown as below:
\arg SAI_FLAG_OUERR: FIFO overrun or underrun flag
\arg SAI_FLAG_MTDET: mute detection flag
\arg SAI_FLAG_ERRCK: error clock flag
\arg SAI_FLAG_FFREQ: FIFO request flag
\arg SAI_FLAG_ACNRDY: audio codec not ready flag
\arg SAI_FLAG_FSADET: frame synchronization advanced detection flag
\arg SAI_FLAG_FSPDET: frame synchronization postpone detection flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus sai_flag_get(uint32_t sai_periph, uint32_t block, uint32_t flag)
{
if(RESET != (SAI_STAT(sai_periph, block) & flag)) {
return SET;
} else {
return RESET;
}
}
/*!
\brief clear the SAI flag
\param[in] sai_periph: SAIx(x=0,1,2)
\param[in] block: specify which bolck is initialized
only one parameter can be selected which is shown as below:
\arg SAI_BLOCKx(x=0,1)
\param[in] flag: specify which flag to clear
one or more parameters can be selected which are shown as below:
\arg SAI_FLAG_OUERR: FIFO overrun or underrun flag
\arg SAI_FLAG_MTDET: mute detection flag
\arg SAI_FLAG_ERRCK: error clock flag
\arg SAI_FLAG_ACNRDY: audio codec not ready flag
\arg SAI_FLAG_FSADET: frame synchronization advanced detection flag
\arg SAI_FLAG_FSPDET: frame synchronization postpone detection flag
\param[out] none
\retval none
*/
void sai_flag_clear(uint32_t sai_periph, uint32_t block, uint32_t flag)
{
SAI_INTC(sai_periph, block) = flag;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,646 @@
/*!
\file gd32h7xx_syscfg.c
\brief SYSCFG driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_syscfg.h"
/*!
\brief reset the SYSCFG registers
\param[in] none
\param[out] none
\retval none
*/
void syscfg_deinit(void)
{
rcu_periph_reset_enable(RCU_SYSCFGRST);
rcu_periph_reset_disable(RCU_SYSCFGRST);
}
/*!
\brief enable I2Cx(x=0,1,2,3) fast mode plus or I2C fast mode plus PBx(x=6,7,8,9)
\param[in] i2c_fmp
one or more parameters can be selected which are shown as below:
\arg SYSCFG_I2C0_FMP: I2C0 fast mode plus
\arg SYSCFG_I2C1_FMP: I2C1 fast mode plus
\arg SYSCFG_I2C2_FMP: I2C2 fast mode plus
\arg SYSCFG_I2C3_FMP: I2C3 fast mode plus
\arg SYSCFG_I2C_FMP_PB6: I2C fast mode plus on PB6 pin
\arg SYSCFG_I2C_FMP_PB7: I2C fast mode plus on PB7 pin
\arg SYSCFG_I2C_FMP_PB8: I2C fast mode plus on PB8 pin
\arg SYSCFG_I2C_FMP_PB9: I2C fast mode plus on PB9 pin
\param[out] none
\retval none
*/
void syscfg_i2c_fast_mode_plus_enable(uint32_t i2c_fmp)
{
SYSCFG_PMCFG |= i2c_fmp;
}
/*!
\brief disable I2Cx(x=0,1,2,3) fast mode plus or I2C fast mode plus PBx(x=6,7,8,9)
\param[in] i2c_fmp
one or more parameters can be selected which are shown as below:
\arg SYSCFG_I2C0_FMP: I2C0 fast mode plus
\arg SYSCFG_I2C1_FMP: I2C1 fast mode plus
\arg SYSCFG_I2C2_FMP: I2C2 fast mode plus
\arg SYSCFG_I2C3_FMP: I2C3 fast mode plus
\arg SYSCFG_I2C_FMP_PB6: I2C fast mode plus on PB6 pin
\arg SYSCFG_I2C_FMP_PB7: I2C fast mode plus on PB7 pin
\arg SYSCFG_I2C_FMP_PB8: I2C fast mode plus on PB8 pin
\arg SYSCFG_I2C_FMP_PB9: I2C fast mode plus on PB9 pin
\param[out] none
\retval none
*/
void syscfg_i2c_fast_mode_plus_disable(uint32_t i2c_fmp)
{
SYSCFG_PMCFG &= (uint32_t)(~i2c_fmp);
}
/*!
\brief open analog switch (Pxy and Pxy_C are separated pads)
\param[in] gpio_answ: GPIO analog switch
one or more parameters can be selected which are shown as below:
\arg SYSCFG_PA0_ANALOG_SWITCH: PA0 analog switch
\arg SYSCFG_PA1_ANALOG_SWITCH: PA1 analog switch
\arg SYSCFG_PC2_ANALOG_SWITCH: PC2 analog switch
\arg SYSCFG_PC3_ANALOG_SWITCH: PC3 analog switch
\param[out] none
\retval none
*/
void syscfg_analog_switch_enable(uint32_t gpio_answ)
{
SYSCFG_PMCFG |= gpio_answ;
}
/*!
\brief close analog switch (Pxy and Pxy_C are connected through the analog switch)
\param[in] gpio_answ: GPIO analog switch
one or more parameters can be selected which are shown as below:
\arg SYSCFG_PA0_ANALOG_SWITCH: PA0 analog switch
\arg SYSCFG_PA1_ANALOG_SWITCH: PA1 analog switch
\arg SYSCFG_PC2_ANALOG_SWITCH: PC2 analog switch
\arg SYSCFG_PC3_ANALOG_SWITCH: PC3 analog switch
\param[out] none
\retval none
*/
void syscfg_analog_switch_disable(uint32_t gpio_answ)
{
SYSCFG_PMCFG &= (uint32_t)(~gpio_answ);
}
/*!
\brief configure the PHY interface for the ethernet MAC
\param[in] enet_periph: ENETx(x=0,1)
\param[in] phy_interface: specifies the media interface mode
only one parameter can be selected which is shown as below:
\arg SYSCFG_ENET_PHY_MII: MII mode is selected
\arg SYSCFG_ENET_PHY_RMII: RMII mode is selected
\param[out] none
\retval none
*/
void syscfg_enet_phy_interface_config(uint32_t ethernet, uint32_t phy_interface)
{
uint32_t reg;
/* read the value of SYSCFG_PMCFG register */
reg = SYSCFG_PMCFG;
/* configure the ENET media interface */
if(ENET0 == ethernet) {
reg &= ~SYSCFG_PMCFG_ENET0_PHY_SEL;
reg |= ENET0_MEDIA_INTERFACE(phy_interface);
} else {
reg &= ~SYSCFG_PMCFG_ENET1_PHY_SEL;
reg |= ENET1_MEDIA_INTERFACE(phy_interface);
}
SYSCFG_PMCFG = reg;
}
/*!
\brief configure the GPIO pin as EXTI Line
\param[in] exti_port: specify the GPIO port used in EXTI
only one parameter can be selected which is shown as below:
\arg EXTI_SOURCE_GPIOx(x = A,B,C,D,E,F,G,H,J,K): EXTI GPIO port
\param[in] exti_pin: specify the EXTI line
only one parameter can be selected which is shown as below:
\arg EXTI_SOURCE_PINx(GPIOA x = 0..15,GPIOB x = 0..15,GPIOC x = 0..15,GPIOD x = 0..15,GPIOE x = 0..15,
GPIOF x = 0..15,GPIOG x = 0..15,GPIOH x = 0..15,GPIOI x = 0..15,GPIOJ x = 8,9,10,11, GPIOK x = 0,1,2,4,5,6): 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 enable module lockup function (function can be disabled by system reset)
\param[in] lockup:
one or more parameters can be selected which are shown as below:
\arg SYSCFG_LVD_LOCKUP: LVD signal
\arg SYSCFG_CPU_LOCKUP: CPU lockup signal
\arg SYSCFG_BKPRAM_LOCKUP: Region 2 backup SRAM ECC double error signal
\arg SYSCFG_SRAM1_LOCKUP: Region 1 SRAM1 ECC double error signal
\arg SYSCFG_SRAM0_LOCKUP: Region 1 SRAM0 ECC double error signal
\arg SYSCFG_DTCM_LOCKUP: Region 0 DTCM ECC double error signal
\arg SYSCFG_ITCM_LOCKUP: Region 0 ITCM-RAM ECC double error signal
\arg SYSCFG_AXIRAM_LOCKUP: Region 0 AXI-SRAM ECC double error signal
\param[out] none
\retval none
*/
void syscfg_lockup_enable(uint32_t lockup)
{
SYSCFG_LKCTL |= lockup;
}
/*!
\brief select timer channel input source
\param[in] timer_input: TIMER channel input select, refer to timer_channel_input_enum
\arg TIMER7_CI0_INPUT_TIMER7_CH0: select CMP1 output as TIMER7 CI0
\arg TIMER7_CI0_INPUT_CMP1_OUT: select TIMER7 CH0 as TIMER7 CI0
\arg TIMER7_CI1_INPUT_TIMER7_CH1: select TIMER7 CH1 as TIMER7 CI1
\arg TIMER7_CI2_INPUT_TIMER7_CH2: select TIMER7 CH2 as TIMER7 CI2
\arg TIMER7_CI3_INPUT_TIMER7_CH3: select TIMER7 CH3 as TIMER7 CI3
\arg TIMER0_CI0_INPUT_TIMER0_CH0: select CMP0 output as TIMER0 CI0
\arg TIMER0_CI0_INPUT_CMP0_OUT: select TIMER0 CH0 as TIMER0 CI0
\arg TIMER0_CI1_INPUT_TIMER0_CH1: select TIMER0 CH1 as TIMER0 CI1
\arg TIMER0_CI2_INPUT_TIMER0_CH2: select TIMER0 CH2 as TIMER0 CI2
\arg TIMER0_CI3_INPUT_TIMER0_CH3: select TIMER0 CH3 as TIMER0 CI3
\arg TIMER2_CI0_INPUT_TIMER2_CH0: select TIMER2 CH0 as TIMER2 CI0
\arg TIMER2_CI0_INPUT_CMP0_OUT: select CMP0 as TIMER2 CI0
\arg TIMER2_CI0_INPUT_CMP1_OUT: select CMP1 as TIMER2 CI0
\arg TIMER2_CI0_INPUT_CMP0_OR_CMP1_OUT: select CMP0 or CMP1 as TIMER2 CI0
\arg TIMER2_CI1_INPUT_TIMER2_CH1: select TIMER2 CH1 as TIMER2 CI1
\arg TIMER2_CI2_INPUT_TIMER2_CH2: select TIMER2 CH2 as TIMER2 CI2
\arg TIMER2_CI3_INPUT_TIMER2_CH3: select TIMER2 CH3 as TIMER2 CI3
\arg TIMER1_CI0_INPUT_TIMER1_CH0: select TIMER1 CH0 as TIMER1 CI0
\arg TIMER1_CI1_INPUT_TIMER1_CH1: select TIMER1 CH1 as TIMER1 CI1
\arg TIMER1_CI2_INPUT_TIMER1_CH2: select TIMER1 CH2 as TIMER1 CI2
\arg TIMER1_CI3_INPUT_TIMER1_CH3: select TIMER1 CH3 as TIMER1 CI3
\arg TIMER1_CI3_INPUT_CMP0_OUT: select CMP0 output as TIMER1 CI3
\arg TIMER1_CI3_INPUT_CMP1_OUT: select CMP1 output as TIMER1 CI3
\arg TIMER1_CI3_INPUT_CMP0_OR_CMP1_OUT: select CMP0 or CMP1 output as TIMER1 CI3
\arg TIMER4_CI0_INPUT_TIMER4_CH0: select TIMER4 CH0 as TIMER4 CI0
\arg TIMER4_CI1_INPUT_TIMER4_CH1: select TIMER4 CH1 as TIMER4 CI1
\arg TIMER4_CI2_INPUT_TIMER4_CH2: select TIMER4 CH2 as TIMER4 CI2
\arg TIMER4_CI3_INPUT_TIMER4_CH3: select TIMER4 CH3 as TIMER4 CI3
\arg TIMER3_CI0_INPUT_TIMER3_CH0: select TIMER3 CH0 as TIMER3 CI0
\arg TIMER3_CI1_INPUT_TIMER3_CH1: select TIMER3 CH1 as TIMER3 CI1
\arg TIMER3_CI2_INPUT_TIMER3_CH2: select TIMER3 CH2 as TIMER3 CI2
\arg TIMER3_CI3_INPUT_TIMER3_CH3: select TIMER3 CH3 as TIMER3 CI3
\arg TIMER23_CI0_INPUT_TIMER23_CH0: select TIMER23 CH0 as TIMER23 CI0
\arg TIMER23_CI1_INPUT_TIMER23_CH1: select TIMER23 CH1 as TIMER23 CI1
\arg TIMER23_CI2_INPUT_TIMER23_CH2: select TIMER23 CH2 as TIMER23 CI2
\arg TIMER23_CI3_INPUT_TIMER23_CH3: select TIMER23 CH3 as TIMER23 CI3
\arg TIMER22_CI0_INPUT_TIMER22_CH0: select TIMER22 CH0 as TIMER22 CI0
\arg TIMER22_CI1_INPUT_TIMER22_CH1: select TIMER22 CH1 as TIMER22 CI1
\arg TIMER22_CI2_INPUT_TIMER22_CH2: select TIMER22 CH2 as TIMER22 CI2
\arg TIMER22_CI3_INPUT_TIMER22_CH3: select TIMER22 CH3 as TIMER22 CI3
\arg TIMER22_CI3_INPUT_CMP0_OUT: select CMP0 output as TIMER22 CI3
\arg TIMER22_CI3_INPUT_CMP1_OUT: select CMP1 output as TIMER22 CI3
\arg TIMER22_CI3_INPUT_CMP0_OR_CMP1_OUT: select CMP0 or CMP1 output as TIMER22 CI3
\arg TIMER31_CI0_INPUT_TIMER31_CH0: select TIMER31 CH0 as TIMER31 CI0
\arg TIMER31_CI0_INPUT_CMP0_OUT: select CMP0 output as TIMER31 CI0
\arg TIMER31_CI0_INPUT_CMP1_OUT: select CMP1 output as TIMER31 CI0
\arg TIMER31_CI0_INPUT_CMP0_OR_CMP1_OUT: select CMP0 or CMP1 output as TIMER31 CI0
\arg TIMER31_CI1_INPUT_TIMER31_CH1: select TIMER31 CH1 as TIMER31 CI1
\arg TIMER31_CI2_INPUT_TIMER31_CH2: select TIMER31 CH2 as TIMER31 CI2
\arg TIMER31_CI3_INPUT_TIMER31_CH3: select TIMER31 CH3 as TIMER31 CI3
\arg TIMER30_CI0_INPUT_TIMER30_CH0: select TIMER30 CH0 as TIMER30 CI0
\arg TIMER30_CI0_INPUT_CMP0_OUT: select CMP0 output as TIMER30 CI0
\arg TIMER30_CI0_INPUT_CMP1_OUT: select CMP1 output as TIMER30 CI0
\arg TIMER30_CI0_INPUT_CMP0_OR_CMP1_OUT: select CMP0 or CMP1 output as TIMER30 CI0
\arg TIMER30_CI1_INPUT_TIMER30_CH1: select TIMER30 CH1 as TIMER30 CI1
\arg TIMER30_CI2_INPUT_TIMER30_CH2: select TIMER30 CH2 as TIMER30 CI2
\arg TIMER30_CI3_INPUT_TIMER30_CH3: select TIMER30 CH3 as TIMER30 CI3
\arg TIMER14_CI0_INPUT_TIMER14_CH0: select TIMER14 CH0 as TIMER14 CI0
\arg TIMER14_CI0_INPUT_TIMER1_CH0: select TIMER1 CH0 as TIMER14 CI0
\arg TIMER14_CI0_INPUT_TIMER2_CH0: select TIMER2 CH0 as TIMER14 CI0
\arg TIMER14_CI0_INPUT_TIMER3_CH0: select TIMER3 CH0 as TIMER14 CI0
\arg TIMER14_CI0_INPUT_LXTAL: select LXTAL as TIMER14 CI0
\arg TIMER14_CI0_INPUT_LPIRC4M: select LPIRC4M as TIMER14 CI0
\arg TIMER14_CI0_INPUT_CKOUT1: select CKOUT1 as TIMER14 CI0
\arg TIMER14_CI1_INPUT_TIMER14_CH1: select TIMER14 CH1 as TIMER14 CI1
\arg TIMER14_CI1_INPUT_TIMER1_CH1: select TIMER1 CH1 as TIMER14 CI1
\arg TIMER14_CI1_INPUT_TIMER2_CH1: select TIMER2 CH1 as TIMER14 CI1
\arg TIMER14_CI1_INPUT_TIMER3_CH1: select TIMER3 CH1 as TIMER14 CI1
\arg TIMER40_CI0_INPUT_TIMER40_CH0: select TIMER40 CH0 as TIMER40 CI0
\arg TIMER40_CI0_INPUT_TIMER2_CH0: select TIMER2 CH0 as TIMER40 CI0
\arg TIMER40_CI0_INPUT_TIMER3_CH0: select TIMER3 CH0 as TIMER40 CI0
\arg TIMER40_CI0_INPUT_TIMER4_CH0: select TIMER4 CH0 as TIMER40 CI0
\arg TIMER40_CI0_INPUT_LXTAL: select LXTAL as TIMER40 CI0
\arg TIMER40_CI0_INPUT_LPIRC4M: select LPIRC4M as TIMER40 CI0
\arg TIMER40_CI0_INPUT_CKOUT1: select CKOUT1 as TIMER40 CI0
\arg TIMER40_CI1_INPUT_TIMER40_CH1: select TIMER40 CH1 as TIMER40 CI0
\arg TIMER40_CI1_INPUT_TIMER2_CH1: select TIMER2 CH1 as TIMER40 CI0
\arg TIMER40_CI1_INPUT_TIMER3_CH1: select TIMER3 CH1 as TIMER40 CI0
\arg TIMER40_CI1_INPUT_TIMER4_CH1: select TIMER4 CH1 as TIMER40 CI0
\arg TIMER41_CI0_INPUT_TIMER41_CH0: select TIMER41 CH0 as TIMER41 CI0
\arg TIMER41_CI0_INPUT_TIMER3_CH0: select TIMER3 CH0 as TIMER41 CI0
\arg TIMER41_CI0_INPUT_TIMER4_CH0: select TIMER4 CH0 as TIMER41 CI0
\arg TIMER41_CI0_INPUT_TIMER22_CH0: select TIMER22 CH0 as TIMER41 CI0
\arg TIMER41_CI0_INPUT_LXTAL: select LXTAL as TIMER41 CI0
\arg TIMER41_CI0_INPUT_LPIRC4M: select LPIRC4M as TIMER41 CI0
\arg TIMER41_CI0_INPUT_CKOUT1: select CKOUT1 as TIMER41 CI0
\arg TIMER41_CI1_INPUT_TIMER41_CH1: select TIMER41 CH1 as TIMER41 CI1
\arg TIMER41_CI1_INPUT_TIMER3_CH1: select TIMER3 CH1 as TIMER41 CI1
\arg TIMER41_CI1_INPUT_TIMER4_CH1: select TIMER4 CH1 as TIMER41 CI1
\arg TIMER41_CI1_INPUT_TIMER22_CH1: select TIMER22 CH1 as TIMER41 CI1
\arg TIMER42_CI0_INPUT_TIMER42_CH0: select TIMER42 CH0 as TIMER42 CI0
\arg TIMER42_CI0_INPUT_TIMER4_CH0: select TIMER4 CH0 as TIMER42 CI0
\arg TIMER42_CI0_INPUT_TIMER22_CH0: select TIMER22 CH0 as TIMER42 CI0
\arg TIMER42_CI0_INPUT_TIMER23_CH0: select TIMER23 CH0 as TIMER42 CI0
\arg TIMER42_CI0_INPUT_LXTAL: select LXTAL as TIMER42 CI0
\arg TIMER42_CI0_INPUT_LPIRC4M: select LPIRC4M as TIMER42 CI0
\arg TIMER42_CI0_INPUT_CKOUT1: select CKOUT1 as TIMER42 CI0
\arg TIMER42_CI1_INPUT_TIMER42_CH1: select TIMER42 CH1 as TIMER42 CI1
\arg TIMER42_CI1_INPUT_TIMER4_CH1: select TIMER4 CH1 as TIMER42 CI1
\arg TIMER42_CI1_INPUT_TIMER22_CH1: select TIMER22 CH1 as TIMER42 CI1
\arg TIMER42_CI1_INPUT_TIMER23_CH1: select TIMER23 CH1 as TIMER42 CI1
\arg TIMER15_CI0_INPUT_TIMER15_CH0: select TIMER15 CH0 as TIMER15 CI0
\arg TIMER15_CI0_INPUT_IRC32K: select IRC32K as TIMER15 CI0
\arg TIMER15_CI0_INPUT_LXTAL: select LXTAL as TIMER15 CI0
\arg TIMER15_CI0_INPUT_WKUP_IT: select WKUP IT as TIMER15 CI0
\arg TIMER16_CI0_INPUT_TIMER16_CH0: select TIMER16 CH0 as TIMER16 CI0
\arg TIMER16_CI0_INPUT_RSPDIF: select RSPDIF symbol ck as TIMER16 CI0
\arg TIMER16_CI0_INPUT_HXTAL_RTCDIV: select HXTAL/RTCDIV 1M as TIMER16 CI0
\arg TIMER16_CI0_INPUT_CKOUT0: select CKOUT0 as TIMER16 CI0
\arg TIMER43_CI0_INPUT_TIMER43_CH0: select TIMER43 CH0 as TIMER43 CI0
\arg TIMER43_CI0_INPUT_TIMER22_CH0: select TIMER22 CH0 as TIMER43 CI0
\arg TIMER43_CI0_INPUT_TIMER23_CH0: select TIMER23 CH0 as TIMER43 CI0
\arg TIMER43_CI0_INPUT_TIMER30_CH0: select TIMER30 CH0 as TIMER43 CI0
\arg TIMER43_CI0_INPUT_LXTAL: select LXTAL as TIMER43 CI0
\arg TIMER43_CI0_INPUT_LPIRC4M: select LPIRC4M as TIMER43 CI0
\arg TIMER43_CI0_INPUT_CKOUT1: select CKOUT1 as TIMER43 CI0
\arg TIMER43_CI1_INPUT_TIMER43_CH1: select TIMER43 CH1 as TIMER43 CI1
\arg TIMER43_CI1_INPUT_TIMER22_CH1: select TIMER22 CH1 as TIMER43 CI1
\arg TIMER43_CI1_INPUT_TIMER23_CH1: select TIMER23 CH1 as TIMER43 CI1
\arg TIMER43_CI1_INPUT_TIMER30_CH1: select TIMER30 CH1 as TIMER43 CI1
\arg TIMER44_CI0_INPUT_TIMER44_CH0: select TIMER44 CH0 as TIMER44 CI0
\arg TIMER44_CI0_INPUT_TIMER23_CH0: select TIMER23 CH0 as TIMER44 CI0
\arg TIMER44_CI0_INPUT_TIMER30_CH0: select TIMER30 CH0 as TIMER44 CI0
\arg TIMER44_CI0_INPUT_TIMER31_CH0: select TIMER31 CH0 as TIMER44 CI0
\arg TIMER44_CI0_INPUT_LXTAL: select LXTAL as TIMER44 CI0
\arg TIMER44_CI0_INPUT_LPIRC4M: select LPIRC4M as TIMER44 CI0
\arg TIMER44_CI0_INPUT_CKOUT1: select CKOUT1 as TIMER44 CI0
\arg TIMER44_CI1_INPUT_TIMER44_CH1: select TIMER44 CH1 as TIMER44 CI1
\arg TIMER44_CI1_INPUT_TIMER23_CH1: select TIMER23 CH1 as TIMER44 CI1
\arg TIMER44_CI1_INPUT_TIMER30_CH1: select TIMER30 CH1 as TIMER44 CI1
\arg TIMER44_CI1_INPUT_TIMER31_CH1: select TIMER31 CH1 as TIMER44 CI1
\param[out] none
\retval none
*/
void syscfg_timer_input_source_select(timer_channel_input_enum timer_input)
{
uint32_t clear_timer_mask = ~((uint32_t)TIMER_IS_MASK << (TIMER_BIT_POS(timer_input)));
uint32_t config_timer_mask = (TIMER_SEL_VAL(timer_input) << TIMER_BIT_POS(timer_input));
switch(TIMER_REG_INDEX(timer_input)) {
case TIMERCISEL0:
/* clear TIMER channel input select */
SYSCFG_TIMERCISEL0 &= clear_timer_mask;
/* config TIMER channel input */
SYSCFG_TIMERCISEL0 |= config_timer_mask;
break;
case TIMERCISEL1:
/* clear TIMER channel input select */
SYSCFG_TIMERCISEL1 &= clear_timer_mask;
/* config TIMER channel input */
SYSCFG_TIMERCISEL1 |= config_timer_mask;
break;
case TIMERCISEL2:
/* clear TIMER channel input select */
SYSCFG_TIMERCISEL2 &= clear_timer_mask;
/* config TIMER channel input */
SYSCFG_TIMERCISEL2 |= config_timer_mask;
break;
case TIMERCISEL3:
/* clear TIMER channel input select */
SYSCFG_TIMERCISEL3 &= clear_timer_mask;
/* config TIMER channel input */
SYSCFG_TIMERCISEL3 |= config_timer_mask;
break;
case TIMERCISEL4:
/* clear TIMER channel input select */
SYSCFG_TIMERCISEL4 &= clear_timer_mask;
/* config TIMER channel input */
SYSCFG_TIMERCISEL4 |= config_timer_mask;
break;
case TIMERCISEL5:
/* clear TIMER channel input select */
SYSCFG_TIMERCISEL5 &= clear_timer_mask;
/* config TIMER channel input */
SYSCFG_TIMERCISEL5 |= config_timer_mask;
break;
case TIMERCISEL6:
/* clear TIMER channel input select */
SYSCFG_TIMERCISEL6 &= clear_timer_mask;
/* config TIMER channel input */
SYSCFG_TIMERCISEL6 |= config_timer_mask;
break;
default:
break;
}
}
/*!
\brief configure the I/O compensation cell
\param[in] syscfg_cps: specifies the I/O compensation cell mode
only one parameter can be selected which is shown as below:
\arg SYSCFG_IO_COMPENSATION_ENABLE: I/O compensation cell is enabled
\arg SYSCFG_IO_COMPENSATION_DISABLE: I/O compensation cell is disabled
\param[out] none
\retval none
*/
void syscfg_io_compensation_config(uint32_t syscfg_cps)
{
uint32_t reg;
reg = SYSCFG_CPSCTL;
/* reset the SYSCFG_CPSCTL_CPS_EN bit and set according to syscfg_compensation */
reg &= ~SYSCFG_CPSCTL_CPS_EN;
SYSCFG_CPSCTL = (reg | syscfg_cps);
}
/*!
\brief enable I/O speed optimization, high-speed at low-voltage
\param[in] none
\param[out] none
\retval none
*/
void syscfg_io_low_voltage_speed_optimization_enable(void)
{
SYSCFG_CPSCTL |= SYSCFG_CPSCTL_IOSPDOP;
}
/*!
\brief disable I/O speed optimization, high-speed at low-voltage
\param[in] none
\param[out] none
\retval none
*/
void syscfg_io_low_voltage_speed_optimization_disable(void)
{
SYSCFG_CPSCTL &= ~SYSCFG_CPSCTL_IOSPDOP;
}
/*!
\brief set P/N MOS compensation value
\param[in] mos
only one parameter can be selected which is shown as below:
\arg NMOS_COMPENSATION: NMOS
\arg PMOS_COMPENSATION: PMOS
\param[in] code: P/N MOS compensation value
\param[out] none
\retval none
*/
void syscfg_pnmos_compensation_code_set(uint32_t mos, uint32_t code)
{
uint32_t value;
value = SYSCFG_CPSCCCFG;
if(NMOS_COMPENSATION == mos) {
value &= ~SYSCFG_CPSCCCFG_NCPSCC;
value |= (code & 0x0FU);
} else {
value &= ~SYSCFG_CPSCCCFG_PCPSCC;
value |= ((code & 0x0FU) << 4U);
}
SYSCFG_CPSCCCFG = value;
}
/*!
\brief set secure SRAM size
\param[in] SRAM size
only one parameter can be selected which is shown as below:
\arg SECURE_SRAM_SIZE_0KB: secure SRAM size is 0KB
\arg SECURE_SRAM_SIZE_32KB: secure SRAM size is 32KB
\arg SECURE_SRAM_SIZE_64KB: secure SRAM size is 64KB
\arg SECURE_SRAM_SIZE_128KB: secure SRAM size is 128KB
\param[out] none
\retval none
*/
void syscfg_secure_sram_size_set(uint32_t size)
{
SYSCFG_SRAMCFG0 &= (uint32_t)(~SYSCFG_SRAMCFG0_SECURE_SRAM_SIZE);
SYSCFG_SRAMCFG0 |= size;
}
/*!
\brief get secure SRAM size
\param[in] none
\param[out] none
\retval SRAM size
\arg SECURE_SRAM_SIZE_0KB: secure SRAM size is 0KB
\arg SECURE_SRAM_SIZE_32KB: secure SRAM size is 32KB
\arg SECURE_SRAM_SIZE_64KB: secure SRAM size is 64KB
\arg SECURE_SRAM_SIZE_128KB: secure SRAM size is 128KB
*/
uint32_t syscfg_secure_sram_size_get(void)
{
return (SYSCFG_SRAMCFG0 & SYSCFG_SRAMCFG0_SECURE_SRAM_SIZE);
}
/*!
\brief get BOOT mode
\param[in] none
\param[out] none
\retval boot mode
\arg BOOT_SRAM: BOOT from SRAM (ITCM/DTCM/RAM shared/AXI SRAM)
\arg BOOT_SECURITY: BOOT from Security
\arg BOOT_SYSTEM: BOOT_SYS (BootLoader)
\arg BOOT_USER_FLASH: BOOT_USER (User flash OSPI0/1)
*/
uint32_t syscfg_bootmode_get(void)
{
return ((SYSCFG_USERCFG & SYSCFG_USERCFG_BOOT_MODE) >> 4U);
}
/*!
\brief enable TCM wait state
\param[in] none
\param[out] none
\retval none
*/
void syscfg_tcm_wait_state_enable(void)
{
SYSCFG_SRAMCFG1 |= SYSCFG_SRAMCFG1_TCM_WAITSTATE;
}
/*!
\brief disable TCM wait state
\param[in] none
\param[out] none
\retval none
*/
void syscfg_tcm_wait_state_disable(void)
{
SYSCFG_SRAMCFG1 &= ~SYSCFG_SRAMCFG1_TCM_WAITSTATE;
}
/*!
\brief enable FPU interrupt
\param[in] fpu_int: FPU interrupt
one or more parameters can be selected which are shown as below:
\arg SYSCFG_FPUINT_INEXACT: inexact interrupt
\arg SYSCFG_FPUINT_INPUT_ABNORMAL: input abnormal interrupt
\arg SYSCFG_FPUINT_OVERFLOW: overflow interrupt
\arg SYSCFG_FPUINT_UNDERFLOW: underflow interrupt
\arg SYSCFG_FPUINT_DIV0: divide-by-zero interrupt
\arg SYSCFG_FPUINT_INVALID_OPERATION: invalid operation interrupt
\param[out] none
\retval none
*/
void syscfg_fpu_interrupt_enable(uint32_t fpu_int)
{
SYSCFG_FPUINTEN |= fpu_int;
}
/*!
\brief disable FPU interrupt
\param[in] fpu_int: FPU interrupt
one or more parameters can be selected which are shown as below:
\arg SYSCFG_FPUINT_INEXACT: inexact interrupt
\arg SYSCFG_FPUINT_INPUT_ABNORMAL: input abnormal interrupt
\arg SYSCFG_FPUINT_OVERFLOW: overflow interrupt
\arg SYSCFG_FPUINT_UNDERFLOW: underflow interrupt
\arg SYSCFG_FPUINT_DIV0: divide-by-zero interrupt
\arg SYSCFG_FPUINT_INVALID_OPERATION: invalid operation interrupt
\param[out] none
\retval none
*/
void syscfg_fpu_interrupt_disable(uint32_t fpu_int)
{
SYSCFG_FPUINTEN &= (uint32_t)(~fpu_int);
}
/*!
\brief get compensation cell flags
\param[in] cps_flag: compensation flag
\arg SYSCFG_FLAG_IO_LOW_VOLTAGE: I/O in low voltage state flag, product supply voltage is working below 2.5V
\arg SYSCFG_FLAG_COMPENSATION_READY: I/O compensation cell ready flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus syscfg_compensation_flag_get(uint32_t cps_flag)
{
if(SYSCFG_CPSCTL & cps_flag) {
return SET;
} else {
return RESET;
}
}
/*!
\brief get the ICACHE or DCACHE detection and error information
\param[in] cache:
only one parameter can be selected which is shown as below:
\arg ICACHE_STATUS: select ICACHE
\arg DCACHE_STATUS: select DCACHE
\param[in] status:
only one parameter can be selected which is shown as below:
\arg CPU_CACHE_ERROR_DETECTION: select detection information
\arg CPU_CACHE_ERROR_BANK: select error information
\param[out] none
\retval value
*/
uint32_t syscfg_cpu_cache_status_get(uint32_t cache, uint32_t status)
{
uint32_t value = 0U;
switch(cache) {
/* get ICACHE information */
case ICACHE_STATUS:
if(CPU_CACHE_ERROR_DETECTION == status) {
/* return detection information */
value = (uint32_t)((SYSCFG_CPUICAC & SYSCFG_CPUICAC_CPU_ICDET) >> 28U);
} else {
/* return error bank information */
value = (uint32_t)((SYSCFG_CPUICAC & SYSCFG_CPUICAC_CPU_ICERR) >> 6U);
}
break;
/* get DCACHE information */
case DCACHE_STATUS:
if(CPU_CACHE_ERROR_DETECTION == status) {
/* return detection information */
value = (uint32_t)((SYSCFG_CPUDCAC & SYSCFG_CPUICAC_CPU_ICDET) >> 28U);
} else {
/* return error bank information */
value = (uint32_t)((SYSCFG_CPUDCAC & SYSCFG_CPUICAC_CPU_ICERR) >> 6U);
}
break;
default:
break;
}
return value;
}
/*!
\brief get brownout reset threshold level
\param[in] none
\param[out] none
\retval BOR level
\arg BOR_OFF: no BOR function
\arg BOR_THRESHOLD_VAL1: BOR threshold value 1
\arg BOR_THRESHOLD_VAL2: BOR threshold value 2
\arg BOR_THRESHOLD_VAL3: BOR threshold value 3
*/
uint32_t syscfg_brownout_reset_threshold_level_get(void)
{
return (SYSCFG_USERCFG & SYSCFG_USERCFG_BOR_TH);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,598 @@
/*!
\file gd32h7xx_tli.c
\brief TLI driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_tli.h"
/* TLI default value */
#define TLI_DEFAULT_VALUE 0x00000000U
#define TLI_OPAQUE_VALUE 0x000000FFU
/*!
\brief deinitialize TLI registers
\param[in] none
\param[out] none
\retval none
*/
void tli_deinit(void)
{
rcu_periph_reset_enable(RCU_TLIRST);
rcu_periph_reset_disable(RCU_TLIRST);
}
/*!
\brief initialize the parameters of TLI parameter structure with the default values, it is suggested
that call this function after a tli_parameter_struct structure is defined
\param[in] none
\param[out] tli_struct: the data needed to initialize TLI
synpsz_vpsz: size of the vertical synchronous pulse
synpsz_hpsz: size of the horizontal synchronous pulse
backpsz_vbpsz: size of the vertical back porch plus synchronous pulse
backpsz_hbpsz: size of the horizontal back porch plus synchronous pulse
activesz_vasz: size of the vertical active area width plus back porch and synchronous pulse
activesz_hasz: size of the horizontal active area width plus back porch and synchronous pulse
totalsz_vtsz: vertical total size of the display, including active area, back porch, synchronous
totalsz_htsz: vorizontal total size of the display, including active area, back porch, synchronous
backcolor_red: background value red
backcolor_green: background value green
backcolor_blue: background value blue
signalpolarity_hs: TLI_HSYN_ACTLIVE_LOW,TLI_HSYN_ACTLIVE_HIGH
signalpolarity_vs: TLI_VSYN_ACTLIVE_LOW,TLI_VSYN_ACTLIVE_HIGH
signalpolarity_de: TLI_DE_ACTLIVE_LOW,TLI_DE_ACTLIVE_HIGHT
signalpolarity_pixelck: TLI_PIXEL_CLOCK_TLI,TLI_PIXEL_CLOCK_INVERTEDTLI
\retval none
*/
void tli_struct_para_init(tli_parameter_struct *tli_struct)
{
/* initialize the struct parameters with default values */
tli_struct->synpsz_vpsz = TLI_DEFAULT_VALUE;
tli_struct->synpsz_hpsz = TLI_DEFAULT_VALUE;
tli_struct->backpsz_vbpsz = TLI_DEFAULT_VALUE;
tli_struct->backpsz_hbpsz = TLI_DEFAULT_VALUE;
tli_struct->activesz_vasz = TLI_DEFAULT_VALUE;
tli_struct->activesz_hasz = TLI_DEFAULT_VALUE;
tli_struct->totalsz_vtsz = TLI_DEFAULT_VALUE;
tli_struct->totalsz_htsz = TLI_DEFAULT_VALUE;
tli_struct->backcolor_red = TLI_DEFAULT_VALUE;
tli_struct->backcolor_green = TLI_DEFAULT_VALUE;
tli_struct->backcolor_blue = TLI_DEFAULT_VALUE;
tli_struct->signalpolarity_hs = TLI_HSYN_ACTLIVE_LOW;
tli_struct->signalpolarity_vs = TLI_VSYN_ACTLIVE_LOW;
tli_struct->signalpolarity_de = TLI_DE_ACTLIVE_LOW;
tli_struct->signalpolarity_pixelck = TLI_PIXEL_CLOCK_TLI;
}
/*!
\brief initialize TLI display timing parameters
\param[in] tli_struct: the data needed to initialize TLI
synpsz_vpsz: size of the vertical synchronous pulse
synpsz_hpsz: size of the horizontal synchronous pulse
backpsz_vbpsz: size of the vertical back porch plus synchronous pulse
backpsz_hbpsz: size of the horizontal back porch plus synchronous pulse
activesz_vasz: size of the vertical active area width plus back porch and synchronous pulse
activesz_hasz: size of the horizontal active area width plus back porch and synchronous pulse
totalsz_vtsz: vertical total size of the display, including active area, back porch, synchronous
totalsz_htsz: vorizontal total size of the display, including active area, back porch, synchronous
backcolor_red: background value red
backcolor_green: background value green
backcolor_blue: background value blue
signalpolarity_hs: TLI_HSYN_ACTLIVE_LOW,TLI_HSYN_ACTLIVE_HIGH
signalpolarity_vs: TLI_VSYN_ACTLIVE_LOW,TLI_VSYN_ACTLIVE_HIGH
signalpolarity_de: TLI_DE_ACTLIVE_LOW,TLI_DE_ACTLIVE_HIGH
signalpolarity_pixelck: TLI_PIXEL_CLOCK_TLI,TLI_PIXEL_CLOCK_INVERTEDTLI
\param[out] none
\retval none
*/
void tli_init(tli_parameter_struct *tli_struct)
{
/* synchronous pulse size configuration */
TLI_SPSZ &= ~(TLI_SPSZ_VPSZ | TLI_SPSZ_HPSZ);
TLI_SPSZ = (uint32_t)((uint32_t)tli_struct->synpsz_vpsz | ((uint32_t)tli_struct->synpsz_hpsz << 16U));
/* back-porch size configuration */
TLI_BPSZ &= ~(TLI_BPSZ_VBPSZ | TLI_BPSZ_HBPSZ);
TLI_BPSZ = (uint32_t)((uint32_t)tli_struct->backpsz_vbpsz | ((uint32_t)tli_struct->backpsz_hbpsz << 16U));
/* active size configuration */
TLI_ASZ &= ~(TLI_ASZ_VASZ | TLI_ASZ_HASZ);
TLI_ASZ = (tli_struct->activesz_vasz | (tli_struct->activesz_hasz << 16U));
/* total size configuration */
TLI_TSZ &= ~(TLI_TSZ_VTSZ | TLI_TSZ_HTSZ);
TLI_TSZ = (tli_struct->totalsz_vtsz | (tli_struct->totalsz_htsz << 16U));
/* background color configuration */
TLI_BGC &= ~(TLI_BGC_BVB | (TLI_BGC_BVG) | (TLI_BGC_BVR));
TLI_BGC = (tli_struct->backcolor_blue | (tli_struct->backcolor_green << 8U) | (tli_struct->backcolor_red << 16U));
TLI_CTL &= ~(TLI_CTL_HPPS|TLI_CTL_VPPS | TLI_CTL_DEPS|TLI_CTL_CLKPS);
TLI_CTL |= (tli_struct->signalpolarity_hs | tli_struct->signalpolarity_vs | \
tli_struct->signalpolarity_de | tli_struct->signalpolarity_pixelck);
}
/*!
\brief configure TLI dither function
\param[in] dither_stat
only one parameter can be selected which is shown as below:
\arg TLI_DITHER_ENABLE
\arg TLI_DITHER_DISABLE
\param[out] none
\retval none
*/
void tli_dither_config(uint8_t dither_stat)
{
if(TLI_DITHER_ENABLE == dither_stat){
TLI_CTL |= TLI_CTL_DFEN;
} else {
TLI_CTL &= ~(TLI_CTL_DFEN);
}
}
/*!
\brief enable TLI
\param[in] none
\param[out] none
\retval none
*/
void tli_enable(void)
{
TLI_CTL |= TLI_CTL_TLIEN;
}
/*!
\brief disable TLI
\param[in] none
\param[out] none
\retval none
*/
void tli_disable(void)
{
TLI_CTL &= ~(TLI_CTL_TLIEN);
}
/*!
\brief configure TLI reload mode
\param[in] reload_mod
only one parameter can be selected which is shown as below:
\arg TLI_FRAME_BLANK_RELOAD_EN
\arg TLI_REQUEST_RELOAD_EN
\param[out] none
\retval none
*/
void tli_reload_config(uint8_t reload_mod)
{
if(TLI_FRAME_BLANK_RELOAD_EN == reload_mod){
/* the layer configuration will be reloaded at frame blank */
TLI_RL |= TLI_RL_FBR;
} else {
/* the layer configuration will be reloaded after this bit sets */
TLI_RL |= TLI_RL_RQR;
}
}
/*!
\brief initialize the parameters of TLI layer structure with the default values, it is suggested
that call this function after a tli_layer_parameter_struct structure is defined
\param[in] none
\param[out] layer_struct: TLI Layer parameter struct
layer_window_rightpos: window right position
layer_window_leftpos: window left position
layer_window_bottompos: window bottom position
layer_window_toppos: window top position
layer_ppf: LAYER_PPF_ARGB8888,LAYER_PPF_RGB888,LAYER_PPF_RGB565,
LAYER_PPF_ARG1555,LAYER_PPF_ARGB4444,LAYER_PPF_L8,
LAYER_PPF_AL44,LAYER_PPF_AL88
layer_sa: specified alpha
layer_default_alpha: the default color alpha
layer_default_red: the default color red
layer_default_green: the default color green
layer_default_blue: the default color blue
layer_acf1: LAYER_ACF1_SA,LAYER_ACF1_PASA
layer_acf2: LAYER_ACF2_SA,LAYER_ACF2_PASA
layer_frame_bufaddr: frame buffer base address
layer_frame_buf_stride_offset: frame buffer stride offset
layer_frame_line_length: frame line length
layer_frame_total_line_number: frame total line number
\retval none
*/
void tli_layer_struct_para_init(tli_layer_parameter_struct *layer_struct)
{
/* initialize the struct parameters with default values */
layer_struct->layer_window_rightpos = TLI_DEFAULT_VALUE;
layer_struct->layer_window_leftpos = TLI_DEFAULT_VALUE;
layer_struct->layer_window_bottompos = TLI_DEFAULT_VALUE;
layer_struct->layer_window_toppos = TLI_DEFAULT_VALUE;
layer_struct->layer_ppf = LAYER_PPF_ARGB8888;
layer_struct->layer_sa = TLI_OPAQUE_VALUE;
layer_struct->layer_default_alpha = TLI_DEFAULT_VALUE;
layer_struct->layer_default_red = TLI_DEFAULT_VALUE;
layer_struct->layer_default_green = TLI_DEFAULT_VALUE;
layer_struct->layer_default_blue = TLI_DEFAULT_VALUE;
layer_struct->layer_acf1 = LAYER_ACF1_PASA;
layer_struct->layer_acf2 = LAYER_ACF2_PASA;
layer_struct->layer_frame_bufaddr = TLI_DEFAULT_VALUE;
layer_struct->layer_frame_buf_stride_offset = TLI_DEFAULT_VALUE;
layer_struct->layer_frame_line_length = TLI_DEFAULT_VALUE;
layer_struct->layer_frame_total_line_number = TLI_DEFAULT_VALUE;
}
/*!
\brief initialize TLI layer
\param[in] layerx: LAYERx(x=0,1)
\param[in] layer_struct: TLI Layer parameter struct
layer_window_rightpos: window right position
layer_window_leftpos: window left position
layer_window_bottompos: window bottom position
layer_window_toppos: window top position
layer_ppf: LAYER_PPF_ARGB8888,LAYER_PPF_RGB888,LAYER_PPF_RGB565,
LAYER_PPF_ARG1555,LAYER_PPF_ARGB4444,LAYER_PPF_L8,
LAYER_PPF_AL44,LAYER_PPF_AL88
layer_sa: specified alpha
layer_default_alpha: the default color alpha
layer_default_red: the default color red
layer_default_green: the default color green
layer_default_blue: the default color blue
layer_acf1: LAYER_ACF1_SA,LAYER_ACF1_PASA
layer_acf2: LAYER_ACF2_SA,LAYER_ACF2_PASA
layer_frame_bufaddr: frame buffer base address
layer_frame_buf_stride_offset: frame buffer stride offset
layer_frame_line_length: frame line length
layer_frame_total_line_number: frame total line number
\param[out] none
\retval none
*/
void tli_layer_init(uint32_t layerx,tli_layer_parameter_struct *layer_struct)
{
/* configure layer window horizontal position */
TLI_LXHPOS(layerx) &= ~(TLI_LXHPOS_WLP | (TLI_LXHPOS_WRP));
TLI_LXHPOS(layerx) = (uint32_t)((uint32_t)layer_struct->layer_window_leftpos | ((uint32_t)layer_struct->layer_window_rightpos << 16U));
/* configure layer window vertical position */
TLI_LXVPOS(layerx) &= ~(TLI_LXVPOS_WTP | (TLI_LXVPOS_WBP));
TLI_LXVPOS(layerx) = (uint32_t)((uint32_t)layer_struct->layer_window_toppos | ((uint32_t)layer_struct->layer_window_bottompos << 16U));
/* configure layer packeted pixel format */
TLI_LXPPF(layerx) &= ~(TLI_LXPPF_PPF);
TLI_LXPPF(layerx) = layer_struct->layer_ppf;
/* configure layer specified alpha */
TLI_LXSA(layerx) &= ~(TLI_LXSA_SA);
TLI_LXSA(layerx) = layer_struct->layer_sa;
/* configure layer default color */
TLI_LXDC(layerx) &= ~(TLI_LXDC_DCB | (TLI_LXDC_DCG) | (TLI_LXDC_DCR) | (TLI_LXDC_DCA));
TLI_LXDC(layerx) = (uint32_t)((uint32_t)layer_struct->layer_default_blue |
((uint32_t)layer_struct->layer_default_green << 8U) |
((uint32_t)layer_struct->layer_default_red << 16U) |
((uint32_t)layer_struct->layer_default_alpha << 24U));
/* configure layer alpha calculation factors */
TLI_LXBLEND(layerx) &= ~(TLI_LXBLEND_ACF2 | (TLI_LXBLEND_ACF1));
TLI_LXBLEND(layerx) = ((layer_struct->layer_acf2) | (layer_struct->layer_acf1));
/* configure layer frame buffer base address */
TLI_LXFBADDR(layerx) &= ~(TLI_LXFBADDR_FBADD);
TLI_LXFBADDR(layerx) = (layer_struct->layer_frame_bufaddr);
/* configure layer frame line length */
TLI_LXFLLEN(layerx) &= ~(TLI_LXFLLEN_FLL | (TLI_LXFLLEN_STDOFF));
TLI_LXFLLEN(layerx) = (uint32_t)((uint32_t)layer_struct->layer_frame_line_length | ((uint32_t)layer_struct->layer_frame_buf_stride_offset << 16U));
/* configure layer frame total line number */
TLI_LXFTLN(layerx) &= ~(TLI_LXFTLN_FTLN);
TLI_LXFTLN(layerx) = (uint32_t)(layer_struct->layer_frame_total_line_number);
}
/*!
\brief reconfigure window position
\param[in] layerx: LAYERx(x=0,1)
\param[in] offset_x: new horizontal offset
\param[in] offset_y: new vertical offset
\param[out] none
\retval none
*/
void tli_layer_window_offset_modify(uint32_t layerx,uint16_t offset_x,uint16_t offset_y)
{
/* configure window start position */
uint32_t layer_ppf, line_num, hstart, vstart;
uint32_t line_length = 0U;
TLI_LXHPOS(layerx) &= ~(TLI_LXHPOS_WLP | (TLI_LXHPOS_WRP));
TLI_LXVPOS(layerx) &= ~(TLI_LXVPOS_WTP | (TLI_LXVPOS_WBP));
hstart = (uint32_t)offset_x + (((TLI_BPSZ & TLI_BPSZ_HBPSZ) >> 16U) + 1U);
vstart = (uint32_t)offset_y + ((TLI_BPSZ & TLI_BPSZ_VBPSZ) + 1U);
line_num = (TLI_LXFTLN(layerx) & TLI_LXFTLN_FTLN);
layer_ppf = (TLI_LXPPF(layerx) & TLI_LXPPF_PPF);
/* the bytes of a line equal TLI_LXFLLEN_FLL bits value minus 3 */
switch(layer_ppf){
case LAYER_PPF_ARGB8888:
/* each pixel includes 4bytes, when pixel format is ARGB8888 */
line_length = (((TLI_LXFLLEN(layerx) & TLI_LXFLLEN_FLL) -3U) / 4U);
break;
case LAYER_PPF_RGB888:
/* each pixel includes 3bytes, when pixel format is RGB888 */
line_length = (((TLI_LXFLLEN(layerx) & TLI_LXFLLEN_FLL) - 3U) / 3U);
break;
case LAYER_PPF_RGB565:
case LAYER_PPF_ARGB1555:
case LAYER_PPF_ARGB4444:
case LAYER_PPF_AL88:
/* each pixel includes 2bytes, when pixel format is RGB565,ARG1555,ARGB4444 or AL88 */
line_length = (((TLI_LXFLLEN(layerx) & TLI_LXFLLEN_FLL) - 3U) / 2U);
break;
case LAYER_PPF_L8:
case LAYER_PPF_AL44:
/* each pixel includes 1byte, when pixel format is L8 or AL44 */
line_length = (((TLI_LXFLLEN(layerx) & TLI_LXFLLEN_FLL) - 3U));
break;
default:
break;
}
/* reconfigure window position */
TLI_LXHPOS(layerx) = (hstart | ((hstart+line_length - 1U) << 16U));
TLI_LXVPOS(layerx) = (vstart | ((vstart+line_num - 1U) << 16U));
}
/*!
\brief initialize the parameters of TLI layer LUT structure with the default values, it is suggested
that call this function after a tli_layer_lut_parameter_struct structure is defined
\param[in] none
\param[out] lut_struct: TLI layer LUT parameter struct
layer_table_addr: look up table write address
layer_lut_channel_red: red channel of a LUT entry
layer_lut_channel_green: green channel of a LUT entry
layer_lut_channel_blue: blue channel of a LUT entry
\retval none
*/
void tli_lut_struct_para_init(tli_layer_lut_parameter_struct *lut_struct)
{
/* initialize the struct parameters with default values */
lut_struct->layer_table_addr = TLI_DEFAULT_VALUE;
lut_struct->layer_lut_channel_red = TLI_DEFAULT_VALUE;
lut_struct->layer_lut_channel_green = TLI_DEFAULT_VALUE;
lut_struct->layer_lut_channel_blue = TLI_DEFAULT_VALUE;
}
/*!
\brief initialize TLI layer LUT
\param[in] layerx: LAYERx(x=0,1)
\param[in] lut_struct: TLI layer LUT parameter struct
layer_table_addr: look up table write address
layer_lut_channel_red: red channel of a LUT entry
layer_lut_channel_green: green channel of a LUT entry
layer_lut_channel_blue: blue channel of a LUT entry
\param[out] none
\retval none
*/
void tli_lut_init(uint32_t layerx,tli_layer_lut_parameter_struct *lut_struct)
{
TLI_LXLUT(layerx) = (uint32_t)(((uint32_t)lut_struct->layer_lut_channel_blue) |
((uint32_t)lut_struct->layer_lut_channel_green << 8U) |
((uint32_t)lut_struct->layer_lut_channel_red << 16U) |
((uint32_t)lut_struct->layer_table_addr << 24U));
}
/*!
\brief initialize TLI layer color key
\param[in] layerx: LAYERx(x=0,1)
\param[in] redkey: color key red
\param[in] greenkey: color key green
\param[in] bluekey: color key blue
\param[out] none
\retval none
*/
void tli_color_key_init(uint32_t layerx,uint8_t redkey,uint8_t greenkey,uint8_t bluekey)
{
TLI_LXCKEY(layerx) = (((uint32_t)bluekey) | ((uint32_t)greenkey << 8U) | ((uint32_t)redkey << 16U));
}
/*!
\brief enable TLI layer
\param[in] layerx: LAYERx(x=0,1)
\param[out] none
\retval none
*/
void tli_layer_enable(uint32_t layerx)
{
TLI_LXCTL(layerx) |= TLI_LXCTL_LEN;
}
/*!
\brief disable TLI layer
\param[in] layerx: LAYERx(x=0,1)
\param[out] none
\retval none
*/
void tli_layer_disable(uint32_t layerx)
{
TLI_LXCTL(layerx) &= ~(TLI_LXCTL_LEN);
}
/*!
\brief enable TLI layer color keying
\param[in] layerx: LAYERx(x=0,1)
\param[out] none
\retval none
*/
void tli_color_key_enable(uint32_t layerx)
{
TLI_LXCTL(layerx) |= TLI_LXCTL_CKEYEN;
}
/*!
\brief disable TLI layer color keying
\param[in] layerx: LAYERx(x=0,1)
\param[out] none
\retval none
*/
void tli_color_key_disable(uint32_t layerx)
{
TLI_LXCTL(layerx) &= ~(TLI_LXCTL_CKEYEN);
}
/*!
\brief enable TLI layer LUT
\param[in] layerx: LAYERx(x=0,1)
\param[out] none
\retval none
*/
void tli_lut_enable(uint32_t layerx)
{
TLI_LXCTL(layerx) |= TLI_LXCTL_LUTEN;
}
/*!
\brief disable TLI layer LUT
\param[in] layerx: LAYERx(x=0,1)
\param[out] none
\retval none
*/
void tli_lut_disable(uint32_t layerx)
{
TLI_LXCTL(layerx) &= ~(TLI_LXCTL_LUTEN);
}
/*!
\brief set line mark value
\param[in] line_num: line number
\param[out] none
\retval none
*/
void tli_line_mark_set(uint16_t line_num)
{
TLI_LM &= ~(TLI_LM_LM);
TLI_LM = (uint32_t)line_num;
}
/*!
\brief get current displayed position
\param[in] none
\param[out] none
\retval position of current pixel
*/
uint32_t tli_current_pos_get(void)
{
return TLI_CPPOS;
}
/*!
\brief enable TLI interrupt
\param[in] int_flag: TLI interrupt flags
one or more parameters can be selected which are shown as below:
\arg TLI_INT_LM: line mark interrupt
\arg TLI_INT_FE: FIFO error interrupt
\arg TLI_INT_TE: transaction error interrupt
\arg TLI_INT_LCR: layer configuration reloaded interrupt
\param[out] none
\retval none
*/
void tli_interrupt_enable(uint32_t int_flag)
{
TLI_INTEN |= (int_flag);
}
/*!
\brief disable TLI interrupt
\param[in] int_flag: TLI interrupt flags
one or more parameters can be selected which are shown as below:
\arg TLI_INT_LM: line mark interrupt
\arg TLI_INT_FE: FIFO error interrupt
\arg TLI_INT_TE: transaction error interrupt
\arg TLI_INT_LCR: layer configuration reloaded interrupt
\param[out] none
\retval none
*/
void tli_interrupt_disable(uint32_t int_flag)
{
TLI_INTEN &= ~(int_flag);
}
/*!
\brief get TLI interrupt flag
\param[in] int_flag: TLI interrupt flags
one or more parameters can be selected which are shown as below:
\arg TLI_INT_FLAG_LM: line mark interrupt flag
\arg TLI_INT_FLAG_FE: FIFO error interrupt flag
\arg TLI_INT_FLAG_TE: transaction error interrupt flag
\arg TLI_INT_FLAG_LCR: layer configuration reloaded interrupt flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus tli_interrupt_flag_get(uint32_t int_flag)
{
uint32_t state;
state = TLI_INTF;
if(state & int_flag){
state = TLI_INTEN;
if(state & int_flag){
return SET;
}
}
return RESET;
}
/*!
\brief clear TLI interrupt flag
\param[in] int_flag: TLI interrupt flags
one or more parameters can be selected which are shown as below:
\arg TLI_INT_FLAG_LM: line mark interrupt flag
\arg TLI_INT_FLAG_FE: FIFO error interrupt flag
\arg TLI_INT_FLAG_TE: transaction error interrupt flag
\arg TLI_INT_FLAG_LCR: layer configuration reloaded interrupt flag
\param[out] none
\retval none
*/
void tli_interrupt_flag_clear(uint32_t int_flag)
{
TLI_INTC |= (int_flag);
}
/*!
\brief get TLI flag or state in TLI_INTF register or TLI_STAT register
\param[in] flag: TLI flags or states
only one parameter can be selected which is shown as below:
\arg TLI_FLAG_VDE: current VDE state
\arg TLI_FLAG_HDE: current HDE state
\arg TLI_FLAG_VS: current VS status of the TLI
\arg TLI_FLAG_HS: current HS status of the TLI
\arg TLI_FLAG_LM: line mark interrupt flag
\arg TLI_FLAG_FE: FIFO error interrupt flag
\arg TLI_FLAG_TE: transaction error interrupt flag
\arg TLI_FLAG_LCR: layer configuration reloaded interrupt flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus tli_flag_get(uint32_t flag)
{
uint32_t stat;
/* choose which register to get flag or state */
if(flag >> 31U){
stat = TLI_INTF;
}else{
stat = TLI_STAT;
}
if(flag & stat){
return SET;
}else{
return RESET;
}
}
@@ -0,0 +1,236 @@
/*!
\file gd32h7xx_tmu.c
\brief TMU driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_tmu.h"
#define MASK_LOW_HALFWORD ((uint32_t)0xFFFF0000U)
#define MASK_HIGH_HALFWORD ((uint32_t)0x0000FFFFU)
/*!
\brief reset the TMU registers
\param[in] none
\param[out] none
\retval none
*/
void tmu_deinit(void)
{
rcu_periph_reset_enable(RCU_TMURST);
rcu_periph_reset_disable(RCU_TMURST);
}
/*!
\brief initialize the parameters of TMU struct with the default values
\param[in] init_struct: pointer to init parameter struct
\param[out] none
\retval none
*/
void tmu_struct_para_init(tmu_parameter_struct* init_struct)
{
/* set the struct with the default values */
init_struct->mode = TMU_MODE_COS;
init_struct->iterations_number = TMU_ITERATION_STEPS_20;
init_struct->scale = TMU_SCALING_FACTOR_1;
init_struct->dma_read = TMU_READ_DMA_DISABLE;
init_struct->dma_write = TMU_WRITE_DMA_DISABLE;
init_struct->read_times = TMU_READ_TIMES_1;
init_struct->write_times = TMU_WRITE_TIMES_1;
init_struct->output_width = TMU_OUTPUT_WIDTH_32;
init_struct->input_width = TMU_INPUT_WIDTH_32;
}
/*!
\brief initialize TMU
\param[in] init_struct: pointer to init parameter struct
mode: TMU_MODE_COS,TMU_MODE_SIN,TMU_MODE_ATAN2,TMU_MODE_MODULUS,TMU_MODE_ATAN,
TMU_MODE_COSH,TMU_MODE_SINH,TMU_MODE_ATANH,TMU_MODE_LN,TMU_MODE_SQRT
iterations_number: TMU_ITERATION_STEPS_x(x=4,8,12,..24)
scale: TMU_SCALING_FACTOR_x(x=1,2,4,8,16,32,64,128)
dma_read: TMU_READ_DMA_DISABLE, TMU_READ_DMA_ENABLE
dma_write: TMU_WRITE_DMA_DISABLE, TMU_WRITE_DMA_ENABLE
read_times: TMU_READ_TIMES_1, TMU_READ_TIMES_2
write_times: TMU_WRITE_TIMES_1, TMU_WRITE_TIMES_2
output_width: TMU_OUTPUT_WIDTH_32, TMU_OUTPUT_WIDTH_16
input_width: TMU_INPUT_WIDTH_32, TMU_INPUT_WIDTH_16
\param[out] none
\retval none
*/
void tmu_init(tmu_parameter_struct* init_struct)
{
uint32_t reg = 0U;
reg |= ( init_struct->mode | init_struct->iterations_number | init_struct->scale |\
init_struct->dma_read | init_struct->dma_write | init_struct->read_times |\
init_struct->write_times | init_struct->output_width | init_struct->input_width);
TMU_CS = reg;
}
/*!
\brief enable TMU read interrupt
\param[in] none
\param[out] none
\retval none
*/
void tmu_read_interrupt_enable(void)
{
TMU_CS |= TMU_CS_RIE;
}
/*!
\brief disable TMU read interrupt
\param[in] none
\param[out] none
\retval none
*/
void tmu_read_interrupt_disable(void)
{
TMU_CS &= ~TMU_CS_RIE;
}
/*!
\brief enable TMU DMA read request
\param[in] none
\param[out] none
\retval none
*/
void tmu_dma_read_enable(void)
{
TMU_CS |= TMU_CS_RDEN;
}
/*!
\brief disable TMU DMA read request
\param[in] none
\param[out] none
\retval none
*/
void tmu_dma_read_disable(void)
{
TMU_CS &= ~TMU_CS_RDEN;
}
/*!
\brief enable TMU DMA write request
\param[in] none
\param[out] none
\retval none
*/
void tmu_dma_write_enable(void)
{
TMU_CS |= TMU_CS_WDEN;
}
/*!
\brief disable TMU DMA write request
\param[in] none
\param[out] none
\retval none
*/
void tmu_dma_write_disable(void)
{
TMU_CS &= ~TMU_CS_WDEN;
}
/*!
\brief write one data in q1.31 format
\param[in] data: the first input data only
\param[out] none
\retval none
*/
void tmu_one_q31_write(uint32_t data)
{
TMU_IDATA = data;
}
/*!
\brief write two data in q1.31 format
\param[in] data1: the first input data
\param[in] data2: the second input data
\param[out] none
\retval none
*/
void tmu_two_q31_write(uint32_t data1, uint32_t data2)
{
TMU_IDATA = data1;
TMU_IDATA = data2;
}
/*!
\brief write two data in q1.15 format
\param[in] data1: the first input data
\param[in] data2: the second input data (this data is meaningless in mode4 ~ mode9)
\param[out] none
\retval none
*/
void tmu_two_q15_write(uint16_t data1, uint16_t data2)
{
TMU_IDATA = ((((uint32_t)data1) & MASK_HIGH_HALFWORD)| (((uint32_t)data2 << 16U) & MASK_LOW_HALFWORD));
}
/*!
\brief read one data in q1.31 format
\param[in] none
\param[out] p: pointer to the first output data only
\retval none
*/
void tmu_one_q31_read(uint32_t* p)
{
*p = TMU_ODATA;
}
/*!
\brief read two data in q1.31 format
\param[in] none
\param[out] p1: pointer to the first output data
\param[out] p2: pointer to the second output data
\retval none
*/
void tmu_two_q31_read(uint32_t* p1, uint32_t* p2)
{
*p1 = TMU_ODATA;
*p2 = TMU_ODATA;
}
/*!
\brief read two data in q1.15 format
\param[in] none
\param[out] p1: pointer to the first output data
\param[out] p2: pointer to the second output data (this data is meaningless in mode4, mode7 ~ mode9)
\retval none
*/
void tmu_two_q15_read(uint16_t* p1, uint16_t* p2)
{
uint32_t data;
data = TMU_ODATA;
*p1 = (uint16_t)data;
*p2 = (uint16_t)(data >> 16U);
}
@@ -0,0 +1,513 @@
/*!
\file gd32h7xx_trigsel.c
\brief TRIGSEL driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_trigsel.h"
/* TRIGSEL target register redefine */
#define TRIGSEL_TARGET_REG(target_periph) (REG32(TRIGSEL + ((uint32_t)(target_periph) & BITS(2,31)))) /*!< target peripheral register */
#define TRIGSEL_TARGET_PERIPH_SHIFT(target_periph) (((uint32_t)(target_periph) & BITS(0,1)) << 3U) /*!< bit offset in target peripheral register */
#define TRIGSEL_TARGET_PERIPH_MASK(target_periph) ((uint32_t)(BITS(0,7) << TRIGSEL_TARGET_PERIPH_SHIFT(target_periph))) /*!< bit mask in target peripheral register */
/*!
\brief deinitialize TRIGSEL
\param[in] none
\param[out] none
\retval none
*/
void trigsel_deinit(void)
{
rcu_periph_reset_enable(RCU_TRIGSELRST);
rcu_periph_reset_disable(RCU_TRIGSELRST);
}
/*!
\brief set the trigger input signal for target peripheral
\param[in] target_periph: target peripheral value
only one parameter can be selected which is shown as below:
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT0: output target peripheral TRIGSEL_OUT0 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT1: output target peripheral TRIGSEL_OUT1 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT2: output target peripheral TRIGSEL_OUT2 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT3: output target peripheral TRIGSEL_OUT3 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT4: output target peripheral TRIGSEL_OUT4 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT5: output target peripheral TRIGSEL_OUT5 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT6: output target peripheral TRIGSEL_OUT6 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT7: output target peripheral TRIGSEL_OUT7 pin
\arg TRIGSEL_OUTPUT_ADC0_REGTRG: output target peripheral ADC0_REGTRG
\arg TRIGSEL_OUTPUT_ADC0_INSTRG: output target peripheral ADC0_INSTRG
\arg TRIGSEL_OUTPUT_ADC1_REGTRG: output target peripheral ADC1_REGTRG
\arg TRIGSEL_OUTPUT_ADC1_INSTRG: output target peripheral ADC1_INSTRG
\arg TRIGSEL_OUTPUT_ADC2_REGTRG: output target peripheral ADC2_REGTRG
\arg TRIGSEL_OUTPUT_ADC2_INSTRG: output target peripheral ADC2_INSTRG
\arg TRIGSEL_OUTPUT_DAC0_OUT0_EXTRG: output target peripheral DAC0_OUT0_EXTRG
\arg TRIGSEL_OUTPUT_DAC0_OUT1_EXTRG: output target peripheral DAC0_OUT1_EXTRG
\arg TRIGSEL_OUTPUT_TIMER0_BRKIN0: output target peripheral TIMER0_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER0_BRKIN1: output target peripheral TIMER0_BRKIN1
\arg TRIGSEL_OUTPUT_TIMER0_BRKIN2: output target peripheral TIMER0_BRKIN2
\arg TRIGSEL_OUTPUT_TIMER7_BRKIN0: output target peripheral TIMER7_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER7_BRKIN1: output target peripheral TIMER7_BRKIN1
\arg TRIGSEL_OUTPUT_TIMER7_BRKIN2: output target peripheral TIMER7_BRKIN2
\arg TRIGSEL_OUTPUT_TIMER14_BRKIN0: output target peripheral TIMER14_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER15_BRKIN0: output target peripheral TIMER15_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER16_BRKIN0: output target peripheral TIMER16_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER40_BRKIN0: output target peripheral TIMER40_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER41_BRKIN0: output target peripheral TIMER41_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER42_BRKIN0: output target peripheral TIMER42_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER43_BRKIN0: output target peripheral TIMER43_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER44_BRKIN0: output target peripheral TIMER44_BRKIN0
\arg TRIGSEL_OUTPUT_CAN0_EX_TIME_TICK: output target peripheral CAN0_EX_TIME_TICK
\arg TRIGSEL_OUTPUT_CAN1_EX_TIME_TICK: output target peripheral CAN1_EX_TIME_TICK
\arg TRIGSEL_OUTPUT_CAN2_EX_TIME_TICK: output target peripheral CAN2_EX_TIME_TICK
\arg TRIGSEL_OUTPUT_LPDTS_TRG: output target peripheral LPDTS_TRG
\arg TRIGSEL_OUTPUT_TIMER0_ETI: output target peripheral TIMER0_ETI
\arg TRIGSEL_OUTPUT_TIMER1_ETI: output target peripheral TIMER1_ETI
\arg TRIGSEL_OUTPUT_TIMER2_ETI: output target peripheral TIMER2_ETI
\arg TRIGSEL_OUTPUT_TIMER3_ETI: output target peripheral TIMER3_ETI
\arg TRIGSEL_OUTPUT_TIMER4_ETI: output target peripheral TIMER4_ETI
\arg TRIGSEL_OUTPUT_TIMER7_ETI: output target peripheral TIMER7_ETI
\arg TRIGSEL_OUTPUT_TIMER22_ETI: output target peripheral TIMER22_ETI
\arg TRIGSEL_OUTPUT_TIMER23_ETI: output target peripheral TIMER23_ETI
\arg TRIGSEL_OUTPUT_TIMER30_ETI: output target peripheral TIMER30_ETI
\arg TRIGSEL_OUTPUT_TIMER31_ETI: output target peripheral TIMER31_ETI
\arg TRIGSEL_OUTPUT_EDOUT_TRG: output target peripheral EDOUT_TRG
\arg TRIGSEL_OUTPUT_HPDF_ITRG: output target peripheral HPDF_ITR
\arg TRIGSEL_OUTPUT_TIMER0_ITI14: output target peripheral TIMER0_ITI14
\arg TRIGSEL_OUTPUT_TIMER1_ITI14: output target peripheral TIMER1_ITI14
\arg TRIGSEL_OUTPUT_TIMER2_ITI14: output target peripheral TIMER2_ITI14
\arg TRIGSEL_OUTPUT_TIMER3_ITI14: output target peripheral TIMER3_ITI14
\arg TRIGSEL_OUTPUT_TIMER4_ITI14: output target peripheral TIMER4_ITI14
\arg TRIGSEL_OUTPUT_TIMER7_ITI14: output target peripheral TIMER7_ITI14
\arg TRIGSEL_OUTPUT_TIMER14_ITI14: output target peripheral TIMER14_ITI14
\arg TRIGSEL_OUTPUT_TIMER22_ITI14: output target peripheral TIMER22_ITI14
\arg TRIGSEL_OUTPUT_TIMER23_ITI14: output target peripheral TIMER23_ITI14
\arg TRIGSEL_OUTPUT_TIMER30_ITI14: output target peripheral TIMER30_ITI14
\arg TRIGSEL_OUTPUT_TIMER31_ITI14: output target peripheral TIMER31_ITI14
\arg TRIGSEL_OUTPUT_TIMER40_ITI14: output target peripheral TIMER40_ITI14
\arg TRIGSEL_OUTPUT_TIMER41_ITI14: output target peripheral TIMER41_ITI14
\arg TRIGSEL_OUTPUT_TIMER42_ITI14: output target peripheral TIMER42_ITI14
\arg TRIGSEL_OUTPUT_TIMER43_ITI14: output target peripheral TIMER43_ITI14
\arg TRIGSEL_OUTPUT_TIMER44_ITI14: output target peripheral TIMER44_ITI14
\param[in] trigger_source: trigger source value
only one parameter can be selected which is shown as below:
\arg TRIGSEL_INPUT_0: trigger input source 0
\arg TRIGSEL_INPUT_1: trigger input source 1
\arg TRIGSEL_INPUT_TRIGSEL_IN0: trigger input source TRIGSEL_IN0 pin
\arg TRIGSEL_INPUT_TRIGSEL_IN1: trigger input source TRIGSEL_IN1 pin
\arg TRIGSEL_INPUT_TRIGSEL_IN2: trigger input source TRIGSEL_IN2 pin
\arg TRIGSEL_INPUT_TRIGSEL_IN3: trigger input source TRIGSEL_IN3 pin
\arg TRIGSEL_INPUT_TRIGSEL_IN4: trigger input source TRIGSEL_IN4 pin
\arg TRIGSEL_INPUT_TRIGSEL_IN5: trigger input source TRIGSEL_IN5 pin
\arg TRIGSEL_INPUT_TRIGSEL_IN6: trigger input source TRIGSEL_IN6 pin
\arg TRIGSEL_INPUT_TRIGSEL_IN7: trigger input source TRIGSEL_IN7 pin
\arg TRIGSEL_INPUT_TRIGSEL_IN8: trigger input source TRIGSEL_IN8 pin
\arg TRIGSEL_INPUT_TRIGSEL_IN9: trigger input source TRIGSEL_IN9 pin
\arg TRIGSEL_INPUT_TRIGSEL_IN10: trigger input source TRIGSEL_IN10 pin
\arg TRIGSEL_INPUT_TRIGSEL_IN11: trigger input source TRIGSEL_IN11 pin
\arg TRIGSEL_INPUT_TRIGSEL_IN12: trigger input source TRIGSEL_IN12 pin
\arg TRIGSEL_INPUT_TRIGSEL_IN13: trigger input source TRIGSEL_IN13 pin
\arg TRIGSEL_INPUT_LXTAL_TRG: trigger input source LXTAL_TRG
\arg TRIGSEL_INPUT_TIMER0_TRGO0: trigger input source TIMER0 TRGO0
\arg TRIGSEL_INPUT_TIMER0_TRGO1: trigger input source TIMER0 TRGO1
\arg TRIGSEL_INPUT_TIMER0_CH0: trigger input source TIMER0 CH0
\arg TRIGSEL_INPUT_TIMER0_CH1: trigger input source TIMER0 CH1
\arg TRIGSEL_INPUT_TIMER0_CH2: trigger input source TIMER0 CH2
\arg TRIGSEL_INPUT_TIMER0_CH3: trigger input source TIMER0 CH3
\arg TRIGSEL_INPUT_TIMER0_MCH0: trigger input source TIMER0 MCH0
\arg TRIGSEL_INPUT_TIMER0_MCH1: trigger input source TIMER0 MCH1
\arg TRIGSEL_INPUT_TIMER0_MCH2: trigger input source TIMER0 MCH2
\arg TRIGSEL_INPUT_TIMER0_MCH3: trigger input source TIMER0 MCH3
\arg TRIGSEL_INPUT_TIMER0_BRKIN0: trigger input source TIMER0 BRKIN0
\arg TRIGSEL_INPUT_TIMER0_BRKIN1: trigger input source TIMER0 BRKIN1
\arg TRIGSEL_INPUT_TIMER0_BRKIN2: trigger input source TIMER0 BRKIN2
\arg TRIGSEL_INPUT_TIMER0_ETI: trigger input source TIMER0 ETI
\arg TRIGSEL_INPUT_TIMER1_TRGO0: trigger input source TIMER1 TRGO0
\arg TRIGSEL_INPUT_TIMER1_CH0: trigger input source TIMER1 CH0
\arg TRIGSEL_INPUT_TIMER1_CH1: trigger input source TIMER1 CH1
\arg TRIGSEL_INPUT_TIMER1_CH2: trigger input source TIMER1 CH2
\arg TRIGSEL_INPUT_TIMER1_CH3: trigger input source TIMER1 CH2
\arg TRIGSEL_INPUT_TIMER1_ETI: trigger input source TIMER1 ETI
\arg TRIGSEL_INPUT_TIMER2_TRGO0: trigger input source TIMER2 TRGO0
\arg TRIGSEL_INPUT_TIMER2_CH0: trigger input source TIMER2 CH0
\arg TRIGSEL_INPUT_TIMER2_CH1: trigger input source TIMER2 CH1
\arg TRIGSEL_INPUT_TIMER2_CH2: trigger input source TIMER2 CH2
\arg TRIGSEL_INPUT_TIMER2_CH3: trigger input source TIMER2 CH3
\arg TRIGSEL_INPUT_TIMER2_ETI: trigger input source TIMER2 ETI
\arg TRIGSEL_INPUT_TIMER3_TRGO0: trigger input source TIMER3 TRGO0
\arg TRIGSEL_INPUT_TIMER3_CH0: trigger input source TIMER3 CH0
\arg TRIGSEL_INPUT_TIMER3_CH1: trigger input source TIMER3 CH1
\arg TRIGSEL_INPUT_TIMER3_CH2: trigger input source TIMER3 CH2
\arg TRIGSEL_INPUT_TIMER3_CH3: trigger input source TIMER3 CH3
\arg TRIGSEL_INPUT_TIMER3_ETI: trigger input source TIMER3 ETI
\arg TRIGSEL_INPUT_TIMER4_TRGO0: trigger input source TIMER4 TRGO0
\arg TRIGSEL_INPUT_TIMER4_CH0: trigger input source TIMER4 CH0
\arg TRIGSEL_INPUT_TIMER4_CH1: trigger input source TIMER4 CH1
\arg TRIGSEL_INPUT_TIMER4_CH2: trigger input source TIMER4 CH2
\arg TRIGSEL_INPUT_TIMER4_CH3: trigger input source TIMER4 CH3
\arg TRIGSEL_INPUT_TIMER4_ETI: trigger input source TIMER4 ETI
\arg TRIGSEL_INPUT_TIMER5_TRGO0: trigger input source TIMER5 TRGO0
\arg TRIGSEL_INPUT_TIMER6_TRGO0: trigger input source TIMER6 TRGO0
\arg TRIGSEL_INPUT_TIMER7_TRGO0: trigger input source TIMER7 TRGO0
\arg TRIGSEL_INPUT_TIMER7_TRGO1: trigger input source TIMER7 TRGO1
\arg TRIGSEL_INPUT_TIMER7_CH0: trigger input source TIMER7 CH0
\arg TRIGSEL_INPUT_TIMER7_CH1: trigger input source TIMER7 CH1
\arg TRIGSEL_INPUT_TIMER7_CH2: trigger input source TIMER7 CH2
\arg TRIGSEL_INPUT_TIMER7_CH3: trigger input source TIMER7 CH3
\arg TRIGSEL_INPUT_TIMER7_MCH0: trigger input source TIMER7 MCH0
\arg TRIGSEL_INPUT_TIMER7_MCH1: trigger input source TIMER7 MCH1
\arg TRIGSEL_INPUT_TIMER7_MCH2: trigger input source TIMER7 MCH2
\arg TRIGSEL_INPUT_TIMER7_MCH3: trigger input source TIMER7 MCH3
\arg TRIGSEL_INPUT_TIMER7_BRKIN0: trigger input source TIMER7 BRKIN0
\arg TRIGSEL_INPUT_TIMER7_BRKIN1: trigger input source TIMER7 BRKIN1
\arg TRIGSEL_INPUT_TIMER7_BRKIN2: trigger input source TIMER7 BRKIN2
\arg TRIGSEL_INPUT_TIMER7_ETI: trigger input source TIMER7 ETI
\arg TRIGSEL_INPUT_TIMER14_TRGO0: trigger input source TIMER14 TRGO0
\arg TRIGSEL_INPUT_TIMER14_CH0: trigger input source TIMER14 CH0
\arg TRIGSEL_INPUT_TIMER14_CH1: trigger input source TIMER14 CH1
\arg TRIGSEL_INPUT_TIMER14_MCH0: trigger input source TIMER14 MCH0
\arg TRIGSEL_INPUT_TIMER14_BRKIN0: trigger input source TIMER14 BRKIN0
\arg TRIGSEL_INPUT_TIMER15_CH0: trigger input source TIMER15 CH0
\arg TRIGSEL_INPUT_TIMER15_MCH0: trigger input source TIMER15 MCH0
\arg TRIGSEL_INPUT_TIMER15_BRKIN0: trigger input source TIMER15 BRKIN0
\arg TRIGSEL_INPUT_TIMER16_CH0: trigger input source TIMER16 CH0
\arg TRIGSEL_INPUT_TIMER16_MCH0: trigger input source TIMER16 MCH0
\arg TRIGSEL_INPUT_TIMER16_BRKIN0: trigger input source TIMER16 BRKIN0
\arg TRIGSEL_INPUT_TIMER22_TRGO0: trigger input source TIMER22 TRGO0
\arg TRIGSEL_INPUT_TIMER22_CH0: trigger input source TIMER22 CH0
\arg TRIGSEL_INPUT_TIMER22_CH1: trigger input source TIMER22 CH1
\arg TRIGSEL_INPUT_TIMER22_CH2: trigger input source TIMER22 CH2
\arg TRIGSEL_INPUT_TIMER22_CH3: trigger input source TIMER22 CH3
\arg TRIGSEL_INPUT_TIMER22_ETI: trigger input source TIMER22 ETI
\arg TRIGSEL_INPUT_TIMER23_TRGO0: trigger input source TIMER23 TRGO0
\arg TRIGSEL_INPUT_TIMER23_CH0: trigger input source TIMER23 CH0
\arg TRIGSEL_INPUT_TIMER23_CH1: trigger input source TIMER23 CH1
\arg TRIGSEL_INPUT_TIMER23_CH2: trigger input source TIMER23 CH2
\arg TRIGSEL_INPUT_TIMER23_CH3: trigger input source TIMER23 CH3
\arg TRIGSEL_INPUT_TIMER23_ETI: trigger input source TIMER23 ETI
\arg TRIGSEL_INPUT_TIMER30_TRGO0: trigger input source TIMER30 TRGO0
\arg TRIGSEL_INPUT_TIMER30_CH0: trigger input source TIMER30 CH0
\arg TRIGSEL_INPUT_TIMER30_CH1: trigger input source TIMER30 CH1
\arg TRIGSEL_INPUT_TIMER30_CH2: trigger input source TIMER30 CH2
\arg TRIGSEL_INPUT_TIMER30_CH3: trigger input source TIMER30 CH3
\arg TRIGSEL_INPUT_TIMER30_ETI: trigger input source TIMER30 ETI
\arg TRIGSEL_INPUT_TIMER31_TRGO0: trigger input source TIMER31 TRGO0
\arg TRIGSEL_INPUT_TIMER31_CH0: trigger input source TIMER31 CH0
\arg TRIGSEL_INPUT_TIMER31_CH1: trigger input source TIMER31 CH1
\arg TRIGSEL_INPUT_TIMER31_CH2: trigger input source TIMER31 CH2
\arg TRIGSEL_INPUT_TIMER31_CH3: trigger input source TIMER31 CH3
\arg TRIGSEL_INPUT_TIMER31_ETI: trigger input source TIMER31 ETI
\arg TRIGSEL_INPUT_TIMER40_TRGO0: trigger input source TIMER40 TRGO0
\arg TRIGSEL_INPUT_TIMER40_CH0: trigger input source TIMER40 CH0
\arg TRIGSEL_INPUT_TIMER40_CH1: trigger input source TIMER40 CH1
\arg TRIGSEL_INPUT_TIMER40_MCH0: trigger input source TIMER40 MCH0
\arg TRIGSEL_INPUT_TIMER40_BRKIN0: trigger input source TIMER40 BRKIN0
\arg TRIGSEL_INPUT_TIMER41_TRGO0: trigger input source TIMER41 TRGO0
\arg TRIGSEL_INPUT_TIMER41_CH0: trigger input source TIMER41 CH0
\arg TRIGSEL_INPUT_TIMER41_CH1: trigger input source TIMER41 CH1
\arg TRIGSEL_INPUT_TIMER41_MCH0: trigger input source TIMER41 MCH0
\arg TRIGSEL_INPUT_TIMER41_BRKIN0: trigger input source TIMER41 BRKIN0
\arg TRIGSEL_INPUT_TIMER42_TRGO0: trigger input source TIMER42 TRGO0
\arg TRIGSEL_INPUT_TIMER42_CH0: trigger input source TIMER42 CH0
\arg TRIGSEL_INPUT_TIMER42_CH1: trigger input source TIMER42 CH1
\arg TRIGSEL_INPUT_TIMER42_MCH0: trigger input source TIMER42 MCH0
\arg TRIGSEL_INPUT_TIMER42_BRKIN0: trigger input source TIMER42 BRKIN0
\arg TRIGSEL_INPUT_TIMER43_TRGO0: trigger input source TIMER43 TRGO0
\arg TRIGSEL_INPUT_TIMER43_CH0: trigger input source TIMER43 CH0
\arg TRIGSEL_INPUT_TIMER43_CH1: trigger input source TIMER43 CH1
\arg TRIGSEL_INPUT_TIMER43_MCH0: trigger input source TIMER43 MCH0
\arg TRIGSEL_INPUT_TIMER43_BRKIN0: trigger input source TIMER43 BRKIN0
\arg TRIGSEL_INPUT_TIMER44_TRGO0: trigger input source TIMER44 TRGO0
\arg TRIGSEL_INPUT_TIMER44_CH0: trigger input source TIMER44 CH0
\arg TRIGSEL_INPUT_TIMER44_CH1: trigger input source TIMER44 CH1
\arg TRIGSEL_INPUT_TIMER44_MCH0: trigger input source TIMER44 MCH0
\arg TRIGSEL_INPUT_TIMER44_BRKIN0: trigger input source TIMER44 BRKIN0
\arg TRIGSEL_INPUT_TIMER50_TRGO0: trigger input source TIMER50 TRGO0
\arg TRIGSEL_INPUT_TIMER51_TRGO0: trigger input source TIMER51 TRGO0
\arg TRIGSEL_INPUT_RTC_ALARM: trigger input source RTC alarm
\arg TRIGSEL_INPUT_RTC_TPTS: trigger input source RTC tamper and time-stamp
\arg TRIGSEL_INPUT_ADC0_WD0_OUT: trigger input source ADC0 watchdog0 output
\arg TRIGSEL_INPUT_ADC0_WD1_OUT: trigger input source ADC0 watchdog1 output
\arg TRIGSEL_INPUT_ADC0_WD2_OUT: trigger input source ADC0 watchdog2 output
\arg TRIGSEL_INPUT_ADC1_WD0_OUT: trigger input source ADC1 watchdog0 output
\arg TRIGSEL_INPUT_ADC1_WD1_OUT: trigger input source ADC1 watchdog1 output
\arg TRIGSEL_INPUT_ADC1_WD2_OUT: trigger input source ADC1 watchdog2 output
\arg TRIGSEL_INPUT_ADC2_WD0_OUT: trigger input source ADC2 watchdog0 output
\arg TRIGSEL_INPUT_ADC2_WD1_OUT: trigger input source ADC2 watchdog1 output
\arg TRIGSEL_INPUT_ADC2_WD2_OUT: trigger input source ADC2 watchdog2 output
\arg TRIGSEL_INPUT_CMP0_OUT: trigger input source CMP0_OUT
\arg TRIGSEL_INPUT_CMP1_OUT: trigger input source CMP1_OUT
\arg TRIGSEL_INPUT_SAI0_FS0: trigger input source SAI0_FS0
\arg TRIGSEL_INPUT_SAI0_FS1: trigger input source SAI0_FS1
\arg TRIGSEL_INPUT_SAI2_FS0: trigger input source SAI2_FS0
\arg TRIGSEL_INPUT_SAI2_FS1: trigger input source SAI2_FS1
\param[out] none
\retval none
*/
void trigsel_init(trigsel_periph_enum target_periph, trigsel_source_enum trigger_source)
{
/* if register write is enabled, set trigger source to target peripheral */
if (RESET == trigsel_register_lock_get(target_periph)){
TRIGSEL_TARGET_REG(target_periph) &= ~TRIGSEL_TARGET_PERIPH_MASK(target_periph);
TRIGSEL_TARGET_REG(target_periph) |= ((uint32_t)trigger_source << TRIGSEL_TARGET_PERIPH_SHIFT(target_periph)) & TRIGSEL_TARGET_PERIPH_MASK(target_periph);
}
}
/*!
\brief get the trigger input signal for target peripheral
\param[in] target_periph: target peripheral value
only one parameter can be selected which is shown as below:
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT0: output target peripheral TRIGSEL_OUT0 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT1: output target peripheral TRIGSEL_OUT1 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT2: output target peripheral TRIGSEL_OUT2 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT3: output target peripheral TRIGSEL_OUT3 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT4: output target peripheral TRIGSEL_OUT4 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT5: output target peripheral TRIGSEL_OUT5 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT6: output target peripheral TRIGSEL_OUT6 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT7: output target peripheral TRIGSEL_OUT7 pin
\arg TRIGSEL_OUTPUT_ADC0_REGTRG: output target peripheral ADC0_REGTRG
\arg TRIGSEL_OUTPUT_ADC0_INSTRG: output target peripheral ADC0_INSTRG
\arg TRIGSEL_OUTPUT_ADC1_REGTRG: output target peripheral ADC1_REGTRG
\arg TRIGSEL_OUTPUT_ADC1_INSTRG: output target peripheral ADC1_INSTRG
\arg TRIGSEL_OUTPUT_ADC2_REGTRG: output target peripheral ADC2_REGTRG
\arg TRIGSEL_OUTPUT_ADC2_INSTRG: output target peripheral ADC2_INSTRG
\arg TRIGSEL_OUTPUT_DAC0_OUT0_EXTRG: output target peripheral DAC0_OUT0_EXTRG
\arg TRIGSEL_OUTPUT_DAC0_OUT1_EXTRG: output target peripheral DAC0_OUT1_EXTRG
\arg TRIGSEL_OUTPUT_TIMER0_BRKIN0: output target peripheral TIMER0_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER0_BRKIN1: output target peripheral TIMER0_BRKIN1
\arg TRIGSEL_OUTPUT_TIMER0_BRKIN2: output target peripheral TIMER0_BRKIN2
\arg TRIGSEL_OUTPUT_TIMER7_BRKIN0: output target peripheral TIMER7_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER7_BRKIN1: output target peripheral TIMER7_BRKIN1
\arg TRIGSEL_OUTPUT_TIMER7_BRKIN2: output target peripheral TIMER7_BRKIN2
\arg TRIGSEL_OUTPUT_TIMER14_BRKIN0: output target peripheral TIMER14_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER15_BRKIN0: output target peripheral TIMER15_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER16_BRKIN0: output target peripheral TIMER16_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER40_BRKIN0: output target peripheral TIMER40_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER41_BRKIN0: output target peripheral TIMER41_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER42_BRKIN0: output target peripheral TIMER42_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER43_BRKIN0: output target peripheral TIMER43_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER44_BRKIN0: output target peripheral TIMER44_BRKIN0
\arg TRIGSEL_OUTPUT_CAN0_EX_TIME_TICK: output target peripheral CAN0_EX_TIME_TICK
\arg TRIGSEL_OUTPUT_CAN1_EX_TIME_TICK: output target peripheral CAN1_EX_TIME_TICK
\arg TRIGSEL_OUTPUT_CAN2_EX_TIME_TICK: output target peripheral CAN2_EX_TIME_TICK
\arg TRIGSEL_OUTPUT_LPDTS_TRG: output target peripheral LPDTS_TRG
\arg TRIGSEL_OUTPUT_TIMER0_ETI: output target peripheral TIMER0_ETI
\arg TRIGSEL_OUTPUT_TIMER1_ETI: output target peripheral TIMER1_ETI
\arg TRIGSEL_OUTPUT_TIMER2_ETI: output target peripheral TIMER2_ETI
\arg TRIGSEL_OUTPUT_TIMER3_ETI: output target peripheral TIMER3_ETI
\arg TRIGSEL_OUTPUT_TIMER4_ETI: output target peripheral TIMER4_ETI
\arg TRIGSEL_OUTPUT_TIMER7_ETI: output target peripheral TIMER7_ETI
\arg TRIGSEL_OUTPUT_TIMER22_ETI: output target peripheral TIMER22_ETI
\arg TRIGSEL_OUTPUT_TIMER23_ETI: output target peripheral TIMER23_ETI
\arg TRIGSEL_OUTPUT_TIMER30_ETI: output target peripheral TIMER30_ETI
\arg TRIGSEL_OUTPUT_TIMER31_ETI: output target peripheral TIMER31_ETI
\arg TRIGSEL_OUTPUT_EDOUT_TRG: output target peripheral EDOUT_TRG
\arg TRIGSEL_OUTPUT_HPDF_ITRG: output target peripheral HPDF_ITR
\arg TRIGSEL_OUTPUT_TIMER0_ITI14: output target peripheral TIMER0_ITI14
\arg TRIGSEL_OUTPUT_TIMER1_ITI14: output target peripheral TIMER1_ITI14
\arg TRIGSEL_OUTPUT_TIMER2_ITI14: output target peripheral TIMER2_ITI14
\arg TRIGSEL_OUTPUT_TIMER3_ITI14: output target peripheral TIMER3_ITI14
\arg TRIGSEL_OUTPUT_TIMER4_ITI14: output target peripheral TIMER4_ITI14
\arg TRIGSEL_OUTPUT_TIMER7_ITI14: output target peripheral TIMER7_ITI14
\arg TRIGSEL_OUTPUT_TIMER14_ITI14: output target peripheral TIMER14_ITI14
\arg TRIGSEL_OUTPUT_TIMER22_ITI14: output target peripheral TIMER22_ITI14
\arg TRIGSEL_OUTPUT_TIMER23_ITI14: output target peripheral TIMER23_ITI14
\arg TRIGSEL_OUTPUT_TIMER30_ITI14: output target peripheral TIMER30_ITI14
\arg TRIGSEL_OUTPUT_TIMER31_ITI14: output target peripheral TIMER31_ITI14
\arg TRIGSEL_OUTPUT_TIMER40_ITI14: output target peripheral TIMER40_ITI14
\arg TRIGSEL_OUTPUT_TIMER41_ITI14: output target peripheral TIMER41_ITI14
\arg TRIGSEL_OUTPUT_TIMER42_ITI14: output target peripheral TIMER42_ITI14
\arg TRIGSEL_OUTPUT_TIMER43_ITI14: output target peripheral TIMER43_ITI14
\arg TRIGSEL_OUTPUT_TIMER44_ITI14: output target peripheral TIMER44_ITI14
\param[out] none
\retval trigger_source: trigger source value(0~177)
*/
trigsel_source_enum trigsel_trigger_source_get(trigsel_periph_enum target_periph)
{
trigsel_source_enum trigger_source;
trigger_source = (trigsel_source_enum)((TRIGSEL_TARGET_REG(target_periph) & TRIGSEL_TARGET_PERIPH_MASK(target_periph)) >> TRIGSEL_TARGET_PERIPH_SHIFT(target_periph));
return trigger_source;
}
/*!
\brief lock the trigger register
\param[in] target_periph: target peripheral value
only one parameter can be selected which is shown as below:
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT0: output target peripheral TRIGSEL_OUT0 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT1: output target peripheral TRIGSEL_OUT1 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT2: output target peripheral TRIGSEL_OUT2 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT3: output target peripheral TRIGSEL_OUT3 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT4: output target peripheral TRIGSEL_OUT4 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT5: output target peripheral TRIGSEL_OUT5 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT6: output target peripheral TRIGSEL_OUT6 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT7: output target peripheral TRIGSEL_OUT7 pin
\arg TRIGSEL_OUTPUT_ADC0_REGTRG: output target peripheral ADC0_REGTRG
\arg TRIGSEL_OUTPUT_ADC0_INSTRG: output target peripheral ADC0_INSTRG
\arg TRIGSEL_OUTPUT_ADC1_REGTRG: output target peripheral ADC1_REGTRG
\arg TRIGSEL_OUTPUT_ADC1_INSTRG: output target peripheral ADC1_INSTRG
\arg TRIGSEL_OUTPUT_ADC2_REGTRG: output target peripheral ADC2_REGTRG
\arg TRIGSEL_OUTPUT_ADC2_INSTRG: output target peripheral ADC2_INSTRG
\arg TRIGSEL_OUTPUT_DAC0_OUT0_EXTRG: output target peripheral DAC0_OUT0_EXTRG
\arg TRIGSEL_OUTPUT_DAC0_OUT1_EXTRG: output target peripheral DAC0_OUT1_EXTRG
\arg TRIGSEL_OUTPUT_TIMER0_BRKIN0: output target peripheral TIMER0_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER0_BRKIN1: output target peripheral TIMER0_BRKIN1
\arg TRIGSEL_OUTPUT_TIMER0_BRKIN2: output target peripheral TIMER0_BRKIN2
\arg TRIGSEL_OUTPUT_TIMER7_BRKIN0: output target peripheral TIMER7_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER7_BRKIN1: output target peripheral TIMER7_BRKIN1
\arg TRIGSEL_OUTPUT_TIMER7_BRKIN2: output target peripheral TIMER7_BRKIN2
\arg TRIGSEL_OUTPUT_TIMER14_BRKIN0: output target peripheral TIMER14_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER15_BRKIN0: output target peripheral TIMER15_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER16_BRKIN0: output target peripheral TIMER16_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER40_BRKIN0: output target peripheral TIMER40_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER41_BRKIN0: output target peripheral TIMER41_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER42_BRKIN0: output target peripheral TIMER42_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER43_BRKIN0: output target peripheral TIMER43_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER44_BRKIN0: output target peripheral TIMER44_BRKIN0
\arg TRIGSEL_OUTPUT_CAN0_EX_TIME_TICK: output target peripheral CAN0_EX_TIME_TICK
\arg TRIGSEL_OUTPUT_CAN1_EX_TIME_TICK: output target peripheral CAN1_EX_TIME_TICK
\arg TRIGSEL_OUTPUT_CAN2_EX_TIME_TICK: output target peripheral CAN2_EX_TIME_TICK
\arg TRIGSEL_OUTPUT_LPDTS_TRG: output target peripheral LPDTS_TRG
\arg TRIGSEL_OUTPUT_TIMER0_ETI: output target peripheral TIMER0_ETI
\arg TRIGSEL_OUTPUT_TIMER1_ETI: output target peripheral TIMER1_ETI
\arg TRIGSEL_OUTPUT_TIMER2_ETI: output target peripheral TIMER2_ETI
\arg TRIGSEL_OUTPUT_TIMER3_ETI: output target peripheral TIMER3_ETI
\arg TRIGSEL_OUTPUT_TIMER4_ETI: output target peripheral TIMER4_ETI
\arg TRIGSEL_OUTPUT_TIMER7_ETI: output target peripheral TIMER7_ETI
\arg TRIGSEL_OUTPUT_TIMER22_ETI: output target peripheral TIMER22_ETI
\arg TRIGSEL_OUTPUT_TIMER23_ETI: output target peripheral TIMER23_ETI
\arg TRIGSEL_OUTPUT_TIMER30_ETI: output target peripheral TIMER30_ETI
\arg TRIGSEL_OUTPUT_TIMER31_ETI: output target peripheral TIMER31_ETI
\arg TRIGSEL_OUTPUT_EDOUT_TRG: output target peripheral EDOUT_TRG
\arg TRIGSEL_OUTPUT_HPDF_ITRG: output target peripheral HPDF_ITR
\arg TRIGSEL_OUTPUT_TIMER0_ITI14: output target peripheral TIMER0_ITI14
\arg TRIGSEL_OUTPUT_TIMER1_ITI14: output target peripheral TIMER1_ITI14
\arg TRIGSEL_OUTPUT_TIMER2_ITI14: output target peripheral TIMER2_ITI14
\arg TRIGSEL_OUTPUT_TIMER3_ITI14: output target peripheral TIMER3_ITI14
\arg TRIGSEL_OUTPUT_TIMER4_ITI14: output target peripheral TIMER4_ITI14
\arg TRIGSEL_OUTPUT_TIMER7_ITI14: output target peripheral TIMER7_ITI14
\arg TRIGSEL_OUTPUT_TIMER14_ITI14: output target peripheral TIMER14_ITI14
\arg TRIGSEL_OUTPUT_TIMER22_ITI14: output target peripheral TIMER22_ITI14
\arg TRIGSEL_OUTPUT_TIMER23_ITI14: output target peripheral TIMER23_ITI14
\arg TRIGSEL_OUTPUT_TIMER30_ITI14: output target peripheral TIMER30_ITI14
\arg TRIGSEL_OUTPUT_TIMER31_ITI14: output target peripheral TIMER31_ITI14
\arg TRIGSEL_OUTPUT_TIMER40_ITI14: output target peripheral TIMER40_ITI14
\arg TRIGSEL_OUTPUT_TIMER41_ITI14: output target peripheral TIMER41_ITI14
\arg TRIGSEL_OUTPUT_TIMER42_ITI14: output target peripheral TIMER42_ITI14
\arg TRIGSEL_OUTPUT_TIMER43_ITI14: output target peripheral TIMER43_ITI14
\arg TRIGSEL_OUTPUT_TIMER44_ITI14: output target peripheral TIMER44_ITI14
\param[out] none
\retval none
*/
void trigsel_register_lock_set(trigsel_periph_enum target_periph)
{
/*!< lock target peripheral register */
TRIGSEL_TARGET_REG(target_periph) |= TRIGSEL_TARGET_LK;
}
/*!
\brief get the trigger register lock status
\param[in] target_periph: target peripheral value
only one parameter can be selected which is shown as below:
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT0: output target peripheral TRIGSEL_OUT0 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT1: output target peripheral TRIGSEL_OUT1 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT2: output target peripheral TRIGSEL_OUT2 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT3: output target peripheral TRIGSEL_OUT3 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT4: output target peripheral TRIGSEL_OUT4 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT5: output target peripheral TRIGSEL_OUT5 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT6: output target peripheral TRIGSEL_OUT6 pin
\arg TRIGSEL_OUTPUT_TRIGSEL_OUT7: output target peripheral TRIGSEL_OUT7 pin
\arg TRIGSEL_OUTPUT_ADC0_REGTRG: output target peripheral ADC0_REGTRG
\arg TRIGSEL_OUTPUT_ADC0_INSTRG: output target peripheral ADC0_INSTRG
\arg TRIGSEL_OUTPUT_ADC1_REGTRG: output target peripheral ADC1_REGTRG
\arg TRIGSEL_OUTPUT_ADC1_INSTRG: output target peripheral ADC1_INSTRG
\arg TRIGSEL_OUTPUT_ADC2_REGTRG: output target peripheral ADC2_REGTRG
\arg TRIGSEL_OUTPUT_ADC2_INSTRG: output target peripheral ADC2_INSTRG
\arg TRIGSEL_OUTPUT_DAC0_OUT0_EXTRG: output target peripheral DAC0_OUT0_EXTRG
\arg TRIGSEL_OUTPUT_DAC0_OUT1_EXTRG: output target peripheral DAC0_OUT1_EXTRG
\arg TRIGSEL_OUTPUT_TIMER0_BRKIN0: output target peripheral TIMER0_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER0_BRKIN1: output target peripheral TIMER0_BRKIN1
\arg TRIGSEL_OUTPUT_TIMER0_BRKIN2: output target peripheral TIMER0_BRKIN2
\arg TRIGSEL_OUTPUT_TIMER7_BRKIN0: output target peripheral TIMER7_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER7_BRKIN1: output target peripheral TIMER7_BRKIN1
\arg TRIGSEL_OUTPUT_TIMER7_BRKIN2: output target peripheral TIMER7_BRKIN2
\arg TRIGSEL_OUTPUT_TIMER14_BRKIN0: output target peripheral TIMER14_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER15_BRKIN0: output target peripheral TIMER15_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER16_BRKIN0: output target peripheral TIMER16_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER40_BRKIN0: output target peripheral TIMER40_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER41_BRKIN0: output target peripheral TIMER41_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER42_BRKIN0: output target peripheral TIMER42_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER43_BRKIN0: output target peripheral TIMER43_BRKIN0
\arg TRIGSEL_OUTPUT_TIMER44_BRKIN0: output target peripheral TIMER44_BRKIN0
\arg TRIGSEL_OUTPUT_CAN0_EX_TIME_TICK: output target peripheral CAN0_EX_TIME_TICK
\arg TRIGSEL_OUTPUT_CAN1_EX_TIME_TICK: output target peripheral CAN1_EX_TIME_TICK
\arg TRIGSEL_OUTPUT_CAN2_EX_TIME_TICK: output target peripheral CAN2_EX_TIME_TICK
\arg TRIGSEL_OUTPUT_LPDTS_TRG: output target peripheral LPDTS_TRG
\arg TRIGSEL_OUTPUT_TIMER0_ETI: output target peripheral TIMER0_ETI
\arg TRIGSEL_OUTPUT_TIMER1_ETI: output target peripheral TIMER1_ETI
\arg TRIGSEL_OUTPUT_TIMER2_ETI: output target peripheral TIMER2_ETI
\arg TRIGSEL_OUTPUT_TIMER3_ETI: output target peripheral TIMER3_ETI
\arg TRIGSEL_OUTPUT_TIMER4_ETI: output target peripheral TIMER4_ETI
\arg TRIGSEL_OUTPUT_TIMER7_ETI: output target peripheral TIMER7_ETI
\arg TRIGSEL_OUTPUT_TIMER22_ETI: output target peripheral TIMER22_ETI
\arg TRIGSEL_OUTPUT_TIMER23_ETI: output target peripheral TIMER23_ETI
\arg TRIGSEL_OUTPUT_TIMER30_ETI: output target peripheral TIMER30_ETI
\arg TRIGSEL_OUTPUT_TIMER31_ETI: output target peripheral TIMER31_ETI
\arg TRIGSEL_OUTPUT_EDOUT_TRG: output target peripheral EDOUT_TRG
\arg TRIGSEL_OUTPUT_HPDF_ITRG: output target peripheral HPDF_ITR
\arg TRIGSEL_OUTPUT_TIMER0_ITI14: output target peripheral TIMER0_ITI14
\arg TRIGSEL_OUTPUT_TIMER1_ITI14: output target peripheral TIMER1_ITI14
\arg TRIGSEL_OUTPUT_TIMER2_ITI14: output target peripheral TIMER2_ITI14
\arg TRIGSEL_OUTPUT_TIMER3_ITI14: output target peripheral TIMER3_ITI14
\arg TRIGSEL_OUTPUT_TIMER4_ITI14: output target peripheral TIMER4_ITI14
\arg TRIGSEL_OUTPUT_TIMER7_ITI14: output target peripheral TIMER7_ITI14
\arg TRIGSEL_OUTPUT_TIMER14_ITI14: output target peripheral TIMER14_ITI14
\arg TRIGSEL_OUTPUT_TIMER22_ITI14: output target peripheral TIMER22_ITI14
\arg TRIGSEL_OUTPUT_TIMER23_ITI14: output target peripheral TIMER23_ITI14
\arg TRIGSEL_OUTPUT_TIMER30_ITI14: output target peripheral TIMER30_ITI14
\arg TRIGSEL_OUTPUT_TIMER31_ITI14: output target peripheral TIMER31_ITI14
\arg TRIGSEL_OUTPUT_TIMER40_ITI14: output target peripheral TIMER40_ITI14
\arg TRIGSEL_OUTPUT_TIMER41_ITI14: output target peripheral TIMER41_ITI14
\arg TRIGSEL_OUTPUT_TIMER42_ITI14: output target peripheral TIMER42_ITI14
\arg TRIGSEL_OUTPUT_TIMER43_ITI14: output target peripheral TIMER43_ITI14
\arg TRIGSEL_OUTPUT_TIMER44_ITI14: output target peripheral TIMER44_ITI14
\param[out] none
\retval SET or RESET
*/
FlagStatus trigsel_register_lock_get(trigsel_periph_enum target_periph)
{
if(RESET != (TRIGSEL_TARGET_REG(target_periph) & TRIGSEL_TARGET_LK)){
return SET;
}else{
return RESET;
}
}
@@ -0,0 +1,426 @@
/*!
\file gd32h7xx_trng.c
\brief TRNG driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_trng.h"
/*!
\brief deinitialize the TRNG
\param[in] none
\param[out] none
\retval none
*/
void trng_deinit(void)
{
rcu_periph_reset_enable(RCU_TRNGRST);
rcu_periph_reset_disable(RCU_TRNGRST);
}
/*!
\brief enable the TRNG interface
\param[in] none
\param[out] none
\retval none
*/
void trng_enable(void)
{
uint32_t trng_config = TRNG_CTL;
trng_config &= ~TRNG_CTL_CONDRST;
trng_config |= TRNG_CTL_TRNGEN;
TRNG_CTL = trng_config;
}
/*!
\brief disable the TRNG interface
\param[in] none
\param[out] none
\retval none
*/
void trng_disable(void)
{
TRNG_CTL &= ~TRNG_CTL_TRNGEN;
}
/*!
\brief lock the TRNG control bits
\param[in] none
\param[out] none
\retval none
*/
void trng_lock(void)
{
TRNG_CTL |= TRNG_CTL_LK;
}
/*!
\brief configure TRNG working mode
\param[in] mode_select: the TRNG working mode
only one parameter can be selected which is shown as below:
\arg TRNG_MODSEL_LFSR: TRNG working in LFSR mode
\arg TRNG_MODSEL_NIST: TRNG working in NIST mode
\param[out] none
\retval none
*/
void trng_mode_config(trng_modsel_enum mode_select)
{
uint32_t trng_config = TRNG_CTL;
trng_config &= ~TRNG_CTL_MODSEL;
trng_config |= mode_select;
TRNG_CTL = trng_config;
}
/*!
\brief enable the TRNG post-processing module
\param[in] none
\param[out] none
\retval none
*/
void trng_postprocessing_enable(void)
{
TRNG_CTL |= TRNG_CTL_PPEN;
}
/*!
\brief disable the TRNG post-processing module
\param[in] none
\param[out] none
\retval none
*/
void trng_postprocessing_disable(void)
{
TRNG_CTL &= ~TRNG_CTL_PPEN;
}
/*!
\brief enable the TRNG conditioning module
\param[in] none
\param[out] none
\retval none
*/
void trng_conditioning_enable(void)
{
TRNG_CTL |= TRNG_CTL_CONDEN;
}
/*!
\brief disable the TRNG conditioning module
\param[in] none
\param[out] none
\retval none
*/
void trng_conditioning_disable(void)
{
TRNG_CTL &= ~TRNG_CTL_CONDEN;
}
/*!
\brief configure TRNG conditioning module input bitwidth
\param[in] input_bitwidth: the input bit width
only one parameter can be selected which is shown as below:
\arg TRNG_INMOD_256BIT: conditioning module input bitwidth 256bits
\arg TRNG_INMOD_440BIT: conditioning module input bitwidth 440bits
\param[out] none
\retval none
*/
void trng_conditioning_input_bitwidth(trng_inmod_enum input_bitwidth)
{
uint32_t trng_config = TRNG_CTL;
trng_config &= ~TRNG_CTL_INMOD;
trng_config |= input_bitwidth;
TRNG_CTL = trng_config;
}
/*!
\brief configure TRNG conditioning module output bitwidth
\param[in] output_bitwidth:
only one parameter can be selected which is shown as below:
\arg TRNG_OUTMOD_128BIT: conditioning module output bitwidth 128bits
\arg TRNG_OUTMOD_256BIT: conditioning module output bitwidth 256bits
\param[out] none
\retval none
*/
void trng_conditioning_output_bitwidth(trng_outmod_enum output_bitwidth)
{
uint32_t trng_config = TRNG_CTL;
trng_config &= ~TRNG_CTL_OUTMOD;
trng_config |= (uint32_t)output_bitwidth;
TRNG_CTL = trng_config;
}
/*!
\brief enable TRNG replace test
\param[in] none
\param[out] none
\retval none
*/
void trng_replace_test_enable(void)
{
TRNG_CTL |= TRNG_CTL_RTEN;
}
/*!
\brief disable TRNG replace test
\param[in] none
\param[out] none
\retval none
*/
void trng_replace_test_disable(void)
{
TRNG_CTL &= ~TRNG_CTL_RTEN;
}
/*!
\brief enable hash algorithm init when conditioning module enabled
\param[in] none
\param[out] none
\retval none
*/
void trng_hash_init_enable(void)
{
TRNG_CTL |= TRNG_CTL_INIT;
}
/*!
\brief disable hash algorithm init when conditioning module enabled
\param[in] none
\param[out] none
\retval none
*/
void trng_hash_init_disable(void)
{
TRNG_CTL &= ~TRNG_CTL_INIT;
}
/*!
\brief configure TRNG analog power mode
\param[in] powermode: the power mode selection
only one parameter can be selected which is shown as below:
\arg TRNG_NR_ULTRALOW: TRNG analog power mode ultralow
\arg TRNG_NR_LOW: TRNG analog power mode low
\arg TRNG_NR_MEDIUM: TRNG analog power mode medium
\arg TRNG_NR_HIGH: TRNG analog power mode high
\param[out] none
\retval none
*/
void trng_powermode_config(uint32_t powermode)
{
uint32_t trng_config = TRNG_CTL;
trng_config &= ~TRNG_CTL_NR;
trng_config |= powermode;
TRNG_CTL = trng_config;
}
/*!
\brief configure TRNG clock divider
\param[in] clkdiv: TRNG clock divider
only one parameter can be selected which is shown as below:
\arg TRNG_CLK_DIVx (x=1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768)
\param[out] none
\retval none
*/
void trng_clockdiv_config(uint32_t clkdiv)
{
uint32_t trng_config = TRNG_CTL;
trng_config &= ~TRNG_CTL_CLKDIV;
trng_config |= clkdiv;
TRNG_CTL = trng_config;
}
/*!
\brief enable the TRNG clock error detection
\param[in] none
\param[out] none
\retval none
*/
void trng_clockerror_detection_enable(void)
{
TRNG_CTL |= TRNG_CTL_CED;
}
/*!
\brief disable the TRNG clock error detection
\param[in] none
\param[out] none
\retval none
*/
void trng_clockerror_detection_disable(void)
{
TRNG_CTL &= ~TRNG_CTL_CED;
}
/*!
\brief get the true random data
\param[in] none
\param[out] none
\retval the generated random data
*/
uint32_t trng_get_true_random_data(void)
{
return (TRNG_DATA);
}
/*!
\brief enable the conditioning logic reset
\param[in] none
\param[out] none
\retval none
*/
void trng_conditioning_reset_enable(void)
{
TRNG_CTL |= TRNG_CTL_CONDRST;
}
/*!
\brief disable the conditioning logic reset
\param[in] none
\param[out] none
\retval none
*/
void trng_conditioning_reset_disable(void)
{
TRNG_CTL &= ~TRNG_CTL_CONDRST;
}
/*!
\brief configure the conditioning module hash algorithm
\param[in] module_algo: module hash algorithm
only one parameter can be selected which is shown as below:
\arg TRNG_ALGO_SHA1: TRNG conditioning module hash SHA1
\arg TRNG_ALGO_MD5: TRNG conditioning module hash MD5
\arg TRNG_ALGO_SHA224: TRNG conditioning module hash SHA224
\arg TRNG_ALGO_SHA256: TRNG conditioning module hash SHA256
\param[out] none
\retval none
*/
void trng_conditioning_algo_config(uint32_t module_algo)
{
uint32_t tmp = TRNG_CTL;
tmp &= ~(TRNG_CTL_ALGO);
tmp |= module_algo;
TRNG_CTL = tmp;
}
/*!
\brief configure health tests default value
\param[in] adpo_threshold: adaptive proportion test threshold value
\param[in] rep_threshold: repetitive (00/11) test threshold value
\param[out] none
\retval none
*/
void trng_health_tests_config(uint32_t adpo_threshold, uint8_t rep_threshold)
{
uint32_t tmp = TRNG_HTCFG;
tmp &= ~(TRNG_HTCFG_APTTH | TRNG_HTCFG_RCTTH);
tmp |= (((uint32_t)(adpo_threshold << 16U) & TRNG_HTCFG_APTTH) | (rep_threshold & TRNG_HTCFG_RCTTH));
TRNG_HTCFG = tmp;
}
/*!
\brief get the TRNG status flags
\param[in] flag: TRNG status flag, refer to trng_flag_enum
only one parameter can be selected which is shown as below:
\arg TRNG_FLAG_DRDY: random data ready status
\arg TRNG_FLAG_CECS: clock error current status
\arg TRNG_FLAG_SECS: seed error current status
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus trng_flag_get(trng_flag_enum flag)
{
if(RESET != (TRNG_STAT & flag)){
return SET;
}else{
return RESET;
}
}
/*!
\brief enable the TRNG interrupt
\param[in] none
\param[out] none
\retval none
*/
void trng_interrupt_enable(void)
{
TRNG_CTL |= TRNG_CTL_IE;
}
/*!
\brief disable the TRNG interrupt
\param[in] none
\param[out] none
\retval none
*/
void trng_interrupt_disable(void)
{
TRNG_CTL &= ~TRNG_CTL_IE;
}
/*!
\brief get the TRNG interrupt flags
\param[in] int_flag: TRNG interrupt flag, refer to trng_int_flag_enum
only one parameter can be selected which is shown as below:
\arg TRNG_INT_FLAG_CEIF: clock error interrupt flag
\arg TRNG_INT_FLAG_SEIF: seed error interrupt flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus trng_interrupt_flag_get(trng_int_flag_enum int_flag)
{
if(RESET != (TRNG_STAT & int_flag)){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear the TRNG interrupt flags
\param[in] int_flag: TRNG interrupt flag, refer to trng_int_flag_enum
only one parameter can be selected which is shown as below:
\arg TRNG_INT_FLAG_CEIF: clock error interrupt flag
\arg TRNG_INT_FLAG_SEIF: seed error interrupt flag
\param[out] none
\retval none
*/
void trng_interrupt_flag_clear(trng_int_flag_enum int_flag)
{
TRNG_STAT &= ~(uint32_t)int_flag;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,153 @@
/*!
\file gd32h7xx_vref.c
\brief VREF driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_vref.h"
/*!
\brief deinitialize the VREF
\param[in] none
\param[out] none
\retval none
*/
void vref_deinit(void)
{
rcu_periph_reset_enable(RCU_VREFRST);
rcu_periph_reset_disable(RCU_VREFRST);
}
/*!
\brief enable VREF
\param[in] none
\param[out] none
\retval none
*/
void vref_enable(void)
{
VREF_CS |= VREF_EN;
}
/*!
\brief disable VREF
\param[in] none
\param[out] none
\retval none
*/
void vref_disable(void)
{
VREF_CS &= (uint32_t)~VREF_EN;
}
/*!
\brief enable VREF high impendance mode
\param[in] none
\param[out] none
\retval none
*/
void vref_high_impedance_mode_enable(void)
{
VREF_CS |= VREF_HIGH_IMPEDANCE_MODE;
}
/*!
\brief disable VREF high impendance mode
\param[in] none
\param[out] none
\retval none
*/
void vref_high_impedance_mode_disable(void)
{
VREF_CS &= (uint32_t)~VREF_HIGH_IMPEDANCE_MODE;
}
/*!
\brief get the status of VREF
\param[in] none
\param[out] none
\retval the status of VREF output
\arg SET: the VREF output is ready
\arg RESET: the VREF output is not ready
*/
FlagStatus vref_status_get(void)
{
if(RESET != (VREF_CS & (uint32_t)VREF_CS_VREFRDY)){
return SET;
}else{
return RESET;
}
}
/*!
\brief select the VREF voltage reference
\param[in] vref_voltage: voltage reference select,
only one parameter can be selected which is shown as below:
\arg VREF_VOLTAGE_SEL_2_5V: VREF voltage reference select 2.5 V
\arg VREF_VOLTAGE_SEL_2_048V: VREF voltage reference select 2.048 V
\arg VREF_VOLTAGE_SEL_1_8V: VREF voltage reference select 1.8 V
\arg VREF_VOLTAGE_SEL_1_5V: VREF voltage reference select 1.5 V
\param[out] none
\retval none
*/
void vref_voltage_select(uint32_t vref_voltage)
{
uint32_t temp = VREF_CS;
/* clear old value */
temp &= ~(uint32_t)VREF_VOLTAGE_SEL_1_5V;
temp |= (uint32_t)vref_voltage;
VREF_CS = temp;
}
/*!
\brief set the calibration value of VREF
\param[in] value: calibration value (0x00 - 0x3F)
\param[out] none
\retval none
*/
void vref_calib_value_set(uint8_t value)
{
VREF_CALIB = (uint32_t)(VREF_CALIB_VREFCAL & value);
}
/*!
\brief get the calibration value of VREF
\param[in] none
\param[out] none
\retval calibration value (0x00 - 0x3F)
*/
uint8_t vref_calib_value_get(void)
{
uint8_t temp = (uint8_t)VREF_CALIB;
return temp;
}
@@ -0,0 +1,131 @@
/*!
\file gd32h7xx_wwdgt.c
\brief WWDGT driver
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
*/
/*
Copyright (c) 2025, 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 "gd32h7xx_wwdgt.h"
/* WWDGT_CTL register value */
#define CTL_CNT(regval) (BITS(0,6) & ((uint32_t)(regval) << 0U))
/* WWDGT_CFG register value */
#define CFG_WIN(regval) (BITS(0,6) & ((uint32_t)(regval) << 0U))
/*!
\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 WWDGT counter
\param[in] none
\param[out] none
\retval none
*/
void wwdgt_enable(void)
{
WWDGT_CTL |= WWDGT_CTL_WDGTEN;
}
/*!
\brief configure the WWDGT counter value
\param[in] counter_value: 0x00 - 0x7F
\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: 0x0000 - 0x007F
\param[in] window: 0x0000 - 0x007F
\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 = (PCLK3/4096)/1
\arg WWDGT_CFG_PSC_DIV2: the time base of window watchdog counter = (PCLK3/4096)/2
\arg WWDGT_CFG_PSC_DIV4: the time base of window watchdog counter = (PCLK3/4096)/4
\arg WWDGT_CFG_PSC_DIV8: the time base of window watchdog counter = (PCLK3/4096)/8
\param[out] none
\retval none
*/
void wwdgt_config(uint16_t counter, uint16_t window, uint32_t prescaler)
{
WWDGT_CTL = (uint32_t)(CTL_CNT(counter));
WWDGT_CFG = (uint32_t)(CFG_WIN(window) | prescaler);
}
/*!
\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;
}
/*!
\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)RESET;
}