/** ****************************************************************************** * @file sci_common.c * @author CMS Application Team * @version Vx.x.x * @date 24-April-2022 * @brief This file provides firmware functions to manage the following * functionalities of the Serial Controllor Unit(SCI): @verbatim =============================================================================== ##### How to use this driver ##### =============================================================================== [..] @endverbatim ****************************************************************************** * @attention * * ****************************************************************************** */ #include "sci_common.h" #include <math.h> /* Private define ------------------------------------------------------------*/ #define MAX_SCI_UNIT 3u #define MAX_CHX_NUMR 4u #define SCI_PARAMETER_NOT_USED(p) (void) ((p)) #define WEAK_ERROR_ATTRIBUTE #pragma weak sci_error_log = sci_error_log_internal /* Private typedef -----------------------------------------------------------*/ typedef struct { uint8_t status[MAX_SCI_UNIT][MAX_CHX_NUMR]; } SCICh_Status_Typedef; /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ static SCICh_Status_Typedef SCI_ChxStat; static const uint16_t sps_tab[16] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768}; /* Private function prototypes -----------------------------------------------*/ /* Private functions ---------------------------------------------------------*/ /** * @brief This function is aimed to check SCI unit and its channel is used or not * @param unitId: SCI unit ID is 1 or 2 or 3. * @param channelId: The channel ID in SCI unit is 0, 1, 2 or 3. * @retval unit channel status */ static int8_t Alloc_ChannelFlag(uint8_t unitId, uint8_t channelId) { /* check input parameter */ assert_param(IS_ALL_SCIUNIT(unitId)); assert_param(IS_ALL_SCICH(channelId)); if(SCI_ChxStat.status[unitId][channelId]) return SCI_ERR_CHANNEL_INVALID; else { SCI_ChxStat.status[unitId][channelId] = 1; return SCI_SUCCESS; } } static uint8_t SCI_GetUnitID(uint8_t Unit) { uint8_t chanpos = 0x00, pos = 0x00 , currentchan = 0x00; uint8_t UnitId = 0; for (chanpos = 0x00u; chanpos < 0x04u; chanpos++) { pos = (0x01u) << chanpos; /* Get the port pins position */ currentchan = Unit & pos; if (currentchan == pos) { UnitId = chanpos; break; } } return UnitId; } /** * @brief This function is to free SCI unit and its channel flag * @param unitId: SCI unit ID is 0 or 1. * @param channelId: The channel ID in SCI unit is 0, 1, 2 or 3. * @retval None */ static void Free_ChannelFlag(uint16_t unitId, uint16_t channelId) { /* check input parameter */ assert_param(IS_ALL_SCIUNIT(unitId)); assert_param(IS_ALL_SCICH(channelId)); if(SCI_ChxStat.status[unitId][channelId] == 1) { SCI_ChxStat.status[unitId][channelId] = 0; } } /* Public functions ----------------------------------------------------------*/ /** * @brief Default error logger function, used only if sci_error_log is not defined in the user application. * @param err The error code encountered. * @param file The file name in which the error code was encountered. * @param line The line number at which the error code was encountered. * @retval None */ void sci_error_log_internal(int8_t err, const char *file, int32_t line) { SCI_PARAMETER_NOT_USED(err); SCI_PARAMETER_NOT_USED(file); SCI_PARAMETER_NOT_USED(line); // printf("%s,%d\r\n",file, line); __BKPT(0); while (1) { /* Do nothing. */ } } /** * @brief Calculate the register setting options for baud rate to UART peripheral. * @param fclk_freq: System clock value on chip. * @param baud: The target baud rate which want to setting. * @param pValue: UART baud rate setting option data structure. * @retval None */ float SCIPeriphal_ClockUpdate(SCIAFSelect_TypeDef func, uint32_t fclk, uint32_t ftclk, uint8_t osps, SCIPeriph_Clock_TypeDef *clock) { #define CALCULATE_MAX_ERROR 2 #define CALCULATE_MAX_SPS 0x0F #define CALCULATE_MAX_SDR 0x7F uint8_t i, j, tmp_i, tmp_j; uint8_t init_sdr, max_sps; uint32_t cal_fmck = 0, cal_ftclk = 0; float cur_err = 0, max_err = 100; if (func & SCI_UART_MASK) init_sdr = 2; else if (func & SCI_I2C_MASK) init_sdr = 1; else init_sdr = 0; if (osps) { clock->sps = osps; max_sps = 1; } else max_sps = CALCULATE_MAX_SPS + 1; for (i = 0; i < max_sps; i++) { if (osps) { i = osps; cal_fmck = fclk / sps_tab[osps]; } else cal_fmck = fclk / sps_tab[i]; for (j = init_sdr; j <= CALCULATE_MAX_SDR; j++) { cal_ftclk = cal_fmck / (j + 1) / 2; cur_err = 100 * (float)(cal_ftclk - ftclk) / (float)ftclk; if(fabs(max_err) > fabs(cur_err)) { tmp_i = i; tmp_j = j; max_err = cur_err; } } } clock->sps = tmp_i; clock->sdr = tmp_j; return max_err; } /** * @brief This function is aimed to check sci unit and its channel is used or not * @param func: The AF function for SCI channel periphal. * @param mode: The mode for SCI channel periphal. * @retval SCI channel status */ int SCIChannel_Alloca(SCIAFSelect_TypeDef func, uint16_t mode) { int res = SCI_SUCCESS; uint8_t channelId = 0; uint8_t uinitId = 0; /* check input parameter */ assert_param(IS_ALL_SCIAF(func)); uinitId = SCI_GetUnitID((uint8_t)(((uint16_t)func) >> 12)); #ifdef BAT32G1XX_80PIN if(func == UART0 || func == UART1 || func == UART2 || func == UART3) #else if(func == UART0 || func == UART1 || func == UART2) #endif { if((mode & SCI_UART_Mode_Tx)== SCI_UART_Mode_Tx) // UART_Mode_Tx { channelId = (uint8_t)(0x000F & (uint16_t)func); res = Alloc_ChannelFlag(uinitId, channelId); } if((mode & SCI_UART_Mode_Rx) == SCI_UART_Mode_Rx) // UART_Mode_Rx { channelId = (uint8_t)((0x000F & (uint16_t)func) + 1); res = Alloc_ChannelFlag(uinitId, channelId); } } else res = Alloc_ChannelFlag(uinitId, (uint8_t)(0x000F & (uint16_t)func)); return res; } /** * @brief This function is free the SCI unit and its channel * @param func: The AF function for SCI channel periphal. * @param mode: The mode for SCI channel periphal. * @retval None */ void SCIChannel_Free(SCIAFSelect_TypeDef func, uint16_t mode) { uint8_t channelId = 0; uint8_t uinitId = 0; /* check input parameter */ assert_param(IS_ALL_SCIAF(func)); uinitId = SCI_GetUnitID((uint8_t)(((uint16_t)func) >> 12)); #if defined( BAT32G1XX_100PIN) || defined( BAT32G1XX_80PIN) if(func == UART0 || func == UART1 || func == UART2 || func == UART3) #else if(func == UART0 || func == UART1 || func == UART2) #endif { if((mode & SCI_UART_Mode_Tx)== SCI_UART_Mode_Tx) // UART_Mode_Tx { channelId = (0x0F & func); Free_ChannelFlag(uinitId, channelId); } if((mode & SCI_UART_Mode_Rx) == SCI_UART_Mode_Rx) // UART_Mode_Rx { channelId = ((0x0F & func) + 1); Free_ChannelFlag(uinitId, channelId); } } else Free_ChannelFlag(uinitId, (0x0F & func)); } /** * @brief Set I2Cx bus output enable or disable * @param I2Cx: where x can be 0, 1, 2, 3, 4 or 5 to select the I2C peripheral. * @param NewState: I2Cx bus signal output status. * This parameter can be one of the following values: * @arg ENABLE: I2Cx bus signal output wave enable. * @arg ISABLE: I2Cx bus signal output wave disable. * @retval None. */ void SCI_Output_Cmd(SCIAFSelect_TypeDef SCIx, FunctionalState NewState) { switch(SCIx) { case I2C00: { I2C0_TypeDef *I2C_Instance = &SCI0->I2C0; I2C_Instance->SOE = (NewState == ENABLE) ? SCI_START_EN : SCI_START_DIS; } break; case I2C01: { I2C1_TypeDef *I2C_Instance = &SCI0->I2C1; I2C_Instance->SOE = (NewState == ENABLE) ? SCI_START_EN : SCI_START_DIS; } break; case I2C10: { I2C2_TypeDef *I2C_Instance = &SCI0->I2C2; I2C_Instance->SOE = (NewState == ENABLE) ? SCI_START_EN : SCI_START_DIS; } break; case I2C11: { I2C3_TypeDef *I2C_Instance = &SCI0->I2C3; I2C_Instance->SOE = (NewState == ENABLE) ? SCI_START_EN : SCI_START_DIS; } break; case I2C20: { I2C4_TypeDef *I2C_Instance = &SCI1->I2C4; I2C_Instance->SOE = (NewState == ENABLE) ? SCI_START_EN : SCI_START_DIS; } break; case I2C21: { I2C5_TypeDef *I2C_Instance = &SCI1->I2C5; I2C_Instance->SOE = (NewState == ENABLE) ? SCI_START_EN : SCI_START_DIS; } break; #if defined( BAT32G1XX_100PIN) || defined( BAT32G1XX_80PIN) case I2C30: { I2C6_TypeDef *I2C_Instance = &SCI2->I2C6; I2C_Instance->SOE = (NewState == ENABLE) ? SCI_START_EN : SCI_START_DIS; } break; case I2C31: { I2C7_TypeDef *I2C_Instance = &SCI2->I2C7; I2C_Instance->SOE = (NewState == ENABLE) ? SCI_START_EN : SCI_START_DIS; } break; #endif default: break; } } /** * @brief Set I2Cx bus output channel start or stop * @param I2Cx: where x can be 0, 1, 2, 3, 4 or 5 to select the I2C peripheral. * @param NewState: I2Cx bus signal output status. * This parameter can be one of the following values: * @arg ENABLE: I2Cx bus channle start enable. * @arg DISABLE: I2Cx bus channle stop * @retval None. */ void SCI_ChannelStart_Cmd(SCIAFSelect_TypeDef SCIx, FunctionalState NewState) { assert_param(IS_ALL_SCIAF(SCIx)); switch(SCIx) { case SSPI00: case I2C00: { I2C0_TypeDef *I2C_Instance = &SCI0->I2C0; if(NewState == ENABLE) I2C_Instance->SS = SCI_START_EN; else I2C_Instance->ST = SCI_STOP_EN; } break; case SSPI01: case I2C01: { I2C1_TypeDef *I2C_Instance = &SCI0->I2C1; if(NewState == ENABLE) I2C_Instance->SS = SCI_START_EN; else I2C_Instance->ST = SCI_STOP_EN; } break; case SSPI10: case I2C10: { I2C2_TypeDef *I2C_Instance = &SCI0->I2C2; if(NewState == ENABLE) I2C_Instance->SS = SCI_START_EN; else I2C_Instance->ST = SCI_STOP_EN; } break; case SSPI11: case I2C11: { I2C3_TypeDef *I2C_Instance = &SCI0->I2C3; if(NewState == ENABLE) I2C_Instance->SS = SCI_START_EN; else I2C_Instance->ST = SCI_STOP_EN; } break; case SSPI20: case I2C20: { I2C4_TypeDef *I2C_Instance = &SCI1->I2C4; if(NewState == ENABLE) I2C_Instance->SS = SCI_START_EN; else I2C_Instance->ST = SCI_STOP_EN; } break; case SSPI21: case I2C21: { I2C5_TypeDef *I2C_Instance = &SCI1->I2C5; if(NewState == ENABLE) I2C_Instance->SS = SCI_START_EN; else I2C_Instance->ST = SCI_STOP_EN; } break; default: break; } } /** * @brief Get the specified I2C flag is set. * @param reg: The I2C peripheral for flag status. * @param I2C_FLAG: specifies the flag to check. * This parameter can be one of the following values: * @arg I2C_FLAG_NOACK: Transmission frame have no ack check. * @arg I2C_FLAG_OVERRUN: Data over run. * @retval None. */ FlagStatus SCI_GetFlagStatus(uint16_t reg, uint16_t FLAG) { FlagStatus bitstatus = RESET; /* Check the parameters */ if ((reg & FLAG) != (uint16_t)RESET) { bitstatus = SET; } else { bitstatus = RESET; } return bitstatus; } /** * @brief Clear the specified I2C flag is set. * @param I2Cx: where x can be 0, 1, 2, 4, 5 to select the I2C peripheral. * @param I2C_FLAG: specifies the flag to check. * This parameter can be one of the following values: * @arg I2C_FLAG_NOACK: Transmission frame have no ack check. * @arg I2C_FLAG_OVERRUN: Data over run. * @retval status. */ uint8_t SCI_GetErrStaus(SCIAFSelect_TypeDef SCIx, uint16_t FLAG) { uint8_t status = 0; /* Check the parameters */ assert_param(IS_ALL_SCIAF(SCIx)); /* get the selected I2C flag */ switch(SCIx) { case SSPI00: case I2C00: { I2C0_TypeDef *I2C_Instance = &SCI0->I2C0; status = I2C_Instance->SSR & FLAG; } break; case SSPI01: case I2C01: { I2C1_TypeDef *I2C_Instance = &SCI0->I2C1; status = I2C_Instance->SSR & FLAG; } break; case SSPI10: case I2C10: { I2C2_TypeDef *I2C_Instance = &SCI0->I2C2; status = I2C_Instance->SSR & FLAG; } break; case SSPI11: case I2C11: { I2C3_TypeDef *I2C_Instance = &SCI0->I2C3; status = I2C_Instance->SSR & FLAG; } break; case SSPI20: case I2C20: { I2C4_TypeDef *I2C_Instance = &SCI1->I2C4; status = I2C_Instance->SSR & FLAG; } break; case SSPI21: case I2C21: { I2C5_TypeDef *I2C_Instance = &SCI1->I2C5; status = I2C_Instance->SSR & FLAG; } break; case UART0: { UART0_TypeDef *UART_Instance = &SCI0->UART0; status = UART_Instance->RSSR & FLAG; } break; case UART1: { UART1_TypeDef *UART_Instance = &SCI0->UART1; status = UART_Instance->RSSR & FLAG; } break; case UART2: { UART2_TypeDef *UART_Instance = &SCI1->UART2; status = UART_Instance->RSSR & FLAG; } break; #if defined( BAT32G1XX_100PIN) || defined( BAT32G1XX_80PIN) case UART3: { UART3_TypeDef *UART_Instance = &SCI2->UART3; status = UART_Instance->RSSR & FLAG; } break; case SSPI30: case I2C30: { I2C6_TypeDef *I2C_Instance = &SCI2->I2C6; status = I2C_Instance->SSR & FLAG; } break; case SSPI31: case I2C31: { I2C7_TypeDef *I2C_Instance = &SCI2->I2C7; status = I2C_Instance->SSR & FLAG; } break; #endif default: break; } return status; } /** * @brief Clear the specified I2C flag is set. * @param I2Cx: where x can be 0, 1, 2, 4, 5 to select the I2C peripheral. * @param I2C_FLAG: specifies the flag to check. * This parameter can be one of the following values: * @arg I2C_CLEAR_FLAG_FEF: Transmission frame data error flag * @arg I2C_CLEAR_FLAG_PEF: I2C Parity error flag * @arg I2C_CLEAR_FLAG_OVF: Transmission over run error flag * @retval None. */ void SCI_ClearFlag(SCIAFSelect_TypeDef SCIx, uint16_t FLAG) { /* Check the parameters */ assert_param(IS_ALL_SCIAF(SCIx)); /* Clear the selected I2C flag */ switch(SCIx) { case SSPI00: case I2C00: { I2C0_TypeDef *I2C_Instance = &SCI0->I2C0; I2C_Instance->SIR |= FLAG; } break; case SSPI01: case I2C01: { I2C1_TypeDef *I2C_Instance = &SCI0->I2C1; I2C_Instance->SIR |= FLAG; } break; case SSPI10: case I2C10: { I2C2_TypeDef *I2C_Instance = &SCI0->I2C2; I2C_Instance->SIR |= FLAG; } break; case SSPI11: case I2C11: { I2C3_TypeDef *I2C_Instance = &SCI0->I2C3; I2C_Instance->SIR |= FLAG; } break; case SSPI20: case I2C20: { I2C4_TypeDef *I2C_Instance = &SCI1->I2C4; I2C_Instance->SIR |= FLAG; } break; case SSPI21: case I2C21: { I2C5_TypeDef *I2C_Instance = &SCI1->I2C5; I2C_Instance->SIR |= FLAG; } break; case UART0: { UART0_TypeDef *UART_Instance = &SCI0->UART0; UART_Instance->RSIR |= FLAG; UART_Instance->TSIR |= FLAG; } break; case UART1: { UART1_TypeDef *UART_Instance = &SCI0->UART1; UART_Instance->RSIR |= FLAG; UART_Instance->TSIR |= FLAG; } break; case UART2: { UART2_TypeDef *UART_Instance = &SCI1->UART2; UART_Instance->RSIR |= FLAG; UART_Instance->TSIR |= FLAG; } break; #if defined( BAT32G1XX_100PIN) || defined( BAT32G1XX_80PIN) case UART3: { UART3_TypeDef *UART_Instance = &SCI2->UART3; UART_Instance->RSIR |= FLAG; UART_Instance->TSIR |= FLAG; } break; case SSPI30: case I2C30: { I2C6_TypeDef *I2C_Instance = &SCI2->I2C6; I2C_Instance->SIR |= FLAG; } break; case SSPI31: case I2C31: { I2C7_TypeDef *I2C_Instance = &SCI2->I2C7; I2C_Instance->SIR |= FLAG; } break; #endif default: break; } }