9ceb218f80
Co-authored-by: Cursor <cursoragent@cursor.com>
277 lines
12 KiB
C
277 lines
12 KiB
C
/*!
|
|
\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;
|
|
}
|