/** ****************************************************************************** * @file adc.h * @author AMG Energy Solution Team * @version V1.0.0 * @date 07-Feb-2022 * @brief This file provides all the codes of adc control functions. ****************************************************************************** * @attention * * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. * *

© COPYRIGHT 2022 AMG

****************************************************************************** */ /** @addtogroup mBMS2 * @{ */ /* Includes ------------------------------------------------------------------*/ #include #include "adc.h" #include "delay.h" /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ /* * If you remap the mapping between the channel and the pin with the function * ADC_ChannelRemap, define ADC_CH_REMAP as non-zero, otherwise define as 0. */ #define ADC_CH_REMAP (0u) /* ADC clock selection definition. */ #define ADC_CLK_PCLK (1u) #define ADC_CLK_MPLLQ (2u) #define ADC_CLK_UPLLR (3u) /* ADC1 channel definition for this example. */ #define ADC1_SA_NORMAL_CHANNEL (ADC1_CH0 | ADC1_CH1 | ADC1_CH2 | ADC1_CH3 | ADC1_CH4 | ADC1_CH5 | ADC1_CH6 | ADC1_CH7) #define ADC1_SA_CHANNEL (ADC1_SA_NORMAL_CHANNEL) #define ADC1_SA_CHANNEL_COUNT (8u) #define ADC1_CHANNEL (ADC1_SA_CHANNEL) /* ADC1 channel sampling time. ADC1_CH0 ADC1_CH1 ADC1_CH2 ADC1_CH3 ADC1_CH4 ADC1_CH5 ADC1_CH6 ADC1_CH7 */ #define ADC1_SA_CHANNEL_SAMPLE_TIME { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 } /* ADC2 channel definition for this example. */ #define ADC2_SA_NORMAL_CHANNEL (ADC2_CH6 | ADC2_CH7) #define ADC2_SA_CHANNEL (ADC2_SA_NORMAL_CHANNEL) #define ADC2_SA_CHANNEL_COUNT (2u) /* ADC2 channel sampling time. ADC2_CH6(AD_10), ADC2_CH7(AD_11) */ #define ADC2_SA_CHANNEL_SAMPLE_TIME { 0x30, 0x30 } #define ADC2_CHANNEL (ADC2_SA_CHANNEL) /* DMA definition for ADC1. */ #define ADC1_SA_DMA_UNIT (M4_DMA1) #define ADC1_SA_DMA_CH (DmaCh0) #define ADC1_SA_DMA_PWC (PWC_FCG0_PERIPH_DMA1) #define ADC1_SA_DMA_TRGSRC (EVT_ADC1_EOCA) #define ADC1_SA_DMA_IRQ_NUM (INT_DMA1_TC0) #define ADC1_SA_DMA_INT_CB (Dma1Btc0_IrqHandler) #define ADC1_DMA_IRQ_NVIC_NUM (Int030_IRQn) /* DMA definition for ADC2. */ #define ADC2_SA_DMA_UNIT (M4_DMA1) #define ADC2_SA_DMA_CH (DmaCh2) #define ADC2_SA_DMA_PWC (PWC_FCG0_PERIPH_DMA1) #define ADC2_SA_DMA_TRGSRC (EVT_ADC2_EOCA) #define ADC2_SA_DMA_IRQ_NUM (INT_DMA1_TC2) #define ADC2_SA_DMA_INT_CB (Dma1Btc2_IrqHandler) #define ADC2_DMA_IRQ_NVIC_NUM (Int031_IRQn) #define ADC1_SA_DMA_BUFFER_MAX (1024 / ADC1_SA_CHANNEL_COUNT) #define ADC2_SA_DMA_BUFFER_MAX (1024 / ADC2_SA_CHANNEL_COUNT) /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ // DMA Buffer uint16_t Adc1DmaSaBuff[ADC1_SA_DMA_BUFFER_MAX][ADC1_SA_CHANNEL_COUNT]; uint16_t Adc2DmaSaBuff[ADC2_SA_DMA_BUFFER_MAX][ADC2_SA_CHANNEL_COUNT]; uint8_t m_u8Adc1DmaIrqFlag = 0u; uint8_t m_u8Adc2DmaIrqFlag = 0u; /* Private function prototypes -----------------------------------------------*/ void AdcConfig(void); void AdcInitConfig(void); void AdcChannelConfig(void); void AdcTriggerConfig(void); void DmaConfig(void); void DmaIrqConfig(void); void DmaIrqRegister(stc_irq_regi_conf_t *pstcCfg, uint32_t u32Priority); void AdcSetChannelPinMode(const M4_ADC_TypeDef *ADCx, uint32_t u32Channel, en_pin_mode_t enMode); /* Private functions ---------------------------------------------------------*/ /** ******************************************************************************* ** \brief ADC configuration, including clock configuration, initial configuration, ** channel configuration and trigger source configuration. ** ** \param None. ** ** \retval None. ** ******************************************************************************/ void AdcConfig(void) { // stc_port_init_t stcPortInit; // /* configuration structure initialization */ // MEM_ZERO_STRUCT(stcPortInit); // stcPortInit.enPinMode = Pin_Mode_Out; // stcPortInit.enExInt = Disable; // stcPortInit.enPullUp = Disable; // /* Test Port/Pin initialization */ // PORT_Init(PortE, Pin00, &stcPortInit); AdcInitConfig(); AdcChannelConfig(); AdcTriggerConfig(); memset(Adc1DmaSaBuff, 0xAA, sizeof(Adc1DmaSaBuff)); memset(Adc2DmaSaBuff, 0xBB, sizeof(Adc2DmaSaBuff)); } /** ******************************************************************************* ** \brief ADC initial configuration. ** ******************************************************************************/ void AdcInitConfig(void) { stc_adc_init_t stcAdcInit; MEM_ZERO_STRUCT(stcAdcInit); stcAdcInit.enResolution = AdcResolution_12Bit; stcAdcInit.enDataAlign = AdcDataAlign_Right; stcAdcInit.enAutoClear = AdcClren_Enable; stcAdcInit.enScanMode = AdcMode_SAContinuous; stcAdcInit.enRschsel = AdcRschsel_Restart; /* 1. Enable ADC1. */ PWC_Fcg3PeriphClockCmd(PWC_FCG3_PERIPH_ADC1, Enable); /* 2. Initialize ADC1. */ ADC_Init(M4_ADC1, &stcAdcInit); /* 1. Enable ADC2. */ PWC_Fcg3PeriphClockCmd(PWC_FCG3_PERIPH_ADC2, Enable); /* 2. Initialize ADC2. */ ADC_Init(M4_ADC2, &stcAdcInit); } /** ******************************************************************************* ** \brief ADC channel configuration. ** ******************************************************************************/ void AdcChannelConfig(void) { uint8_t au8Adc1SaSampTime[ADC1_SA_CHANNEL_COUNT] = ADC1_SA_CHANNEL_SAMPLE_TIME; uint8_t au8Adc2SaSampTime[ADC2_SA_CHANNEL_COUNT] = ADC2_SA_CHANNEL_SAMPLE_TIME; stc_adc_ch_cfg_t stcChCfg; MEM_ZERO_STRUCT(stcChCfg); /**************************** Add ADC1 channels ****************************/ /* 1. Set the ADC pin to analog mode. */ AdcSetChannelPinMode(M4_ADC1, ADC1_CHANNEL, Pin_Mode_Ana); stcChCfg.u32Channel = ADC1_SA_CHANNEL; stcChCfg.u8Sequence = ADC_SEQ_A; stcChCfg.pu8SampTime = au8Adc1SaSampTime; /* 2. Add ADC channel. */ ADC_AddAdcChannel(M4_ADC1, &stcChCfg); /**************************** Add ADC2 channels ****************************/ /* 1. Set the ADC pin to analog mode. */ AdcSetChannelPinMode(M4_ADC2, ADC2_CHANNEL, Pin_Mode_Ana); stcChCfg.u32Channel = ADC2_SA_CHANNEL; stcChCfg.u8Sequence = ADC_SEQ_A; stcChCfg.pu8SampTime = au8Adc2SaSampTime; /* 2. Add ADC channel. */ ADC_AddAdcChannel(M4_ADC2, &stcChCfg); } /** ******************************************************************************* ** \brief ADC trigger source configuration. ** ******************************************************************************/ void AdcTriggerConfig(void) { stc_adc_trg_cfg_t stcTrgCfg; MEM_ZERO_STRUCT(stcTrgCfg); /* * If select an event(@ref en_event_src_t) to trigger ADC, * AOS must be enabled first. */ PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS, Enable); /* Trigger ADC1 sequence A. */ stcTrgCfg.u8Sequence = ADC_SEQ_A; stcTrgCfg.enTrgSel = AdcTrgsel_TRGX0; stcTrgCfg.enInTrg0 = EVT_ADC1_EOCA; ADC_ConfigTriggerSrc(M4_ADC1, &stcTrgCfg); // ADC_TriggerSrcCmd(M4_ADC1, ADC_SEQ_A, Enable); /* ADC1 sequence A will be started by software. */ ADC_TriggerSrcCmd(M4_ADC1, ADC_SEQ_A, Disable); /* Trigger ADC2 sequence A. */ stcTrgCfg.u8Sequence = ADC_SEQ_A; stcTrgCfg.enTrgSel = AdcTrgsel_TRGX0; stcTrgCfg.enInTrg0 = EVT_ADC2_EOCA; ADC_ConfigTriggerSrc(M4_ADC2, &stcTrgCfg); /* ADC2 sequence A will be started by software. */ ADC_TriggerSrcCmd(M4_ADC2, ADC_SEQ_A, Disable); } /** ******************************************************************************* ** \brief DMA configuration for ADC1 and ADC2, including initial configuration ** and interrupt configuration. ** ******************************************************************************/ void DmaConfig(void) { DmaInitConfig(); DmaIrqConfig(); } /** ******************************************************************************* ** \brief DMA initial configuration. ** ******************************************************************************/ void DmaInitConfig(void) { stc_dma_config_t stcDmaCfg; MEM_ZERO_STRUCT(stcDmaCfg); stcDmaCfg.u16BlockSize = ADC1_SA_CHANNEL_COUNT; stcDmaCfg.u16TransferCnt = ADC1_SA_DMA_BUFFER_MAX * ADC1_SA_CHANNEL_COUNT; stcDmaCfg.u32SrcAddr = (uint32_t)(&M4_ADC1->DR0); stcDmaCfg.u32DesAddr = (uint32_t)(&Adc1DmaSaBuff[0][0]); stcDmaCfg.u16DesRptSize = ADC1_SA_DMA_BUFFER_MAX * ADC1_SA_CHANNEL_COUNT; stcDmaCfg.u16SrcRptSize = ADC1_SA_CHANNEL_COUNT; stcDmaCfg.u32DmaLlp = 0u; stcDmaCfg.stcSrcNseqCfg.u16Cnt = 0u; stcDmaCfg.stcSrcNseqCfg.u32Offset = 0u; stcDmaCfg.stcDesNseqCfg.u16Cnt = 0u; stcDmaCfg.stcDesNseqCfg.u32Offset = 0u; stcDmaCfg.stcDmaChCfg.enSrcInc = AddressIncrease; stcDmaCfg.stcDmaChCfg.enDesInc = AddressIncrease; stcDmaCfg.stcDmaChCfg.enSrcRptEn = Enable; stcDmaCfg.stcDmaChCfg.enDesRptEn = Enable; stcDmaCfg.stcDmaChCfg.enSrcNseqEn = Disable; stcDmaCfg.stcDmaChCfg.enDesNseqEn = Disable; stcDmaCfg.stcDmaChCfg.enTrnWidth = Dma16Bit; stcDmaCfg.stcDmaChCfg.enLlpEn = Disable; /* Enable DMA interrupt. */ stcDmaCfg.stcDmaChCfg.enIntEn = Enable; PWC_Fcg0PeriphClockCmd(ADC1_SA_DMA_PWC, Enable); DMA_InitChannel(ADC1_SA_DMA_UNIT, ADC1_SA_DMA_CH, &stcDmaCfg); DMA_Cmd(ADC1_SA_DMA_UNIT, Enable); DMA_ChannelCmd(ADC1_SA_DMA_UNIT, ADC1_SA_DMA_CH, Enable); DMA_ClearIrqFlag(ADC1_SA_DMA_UNIT, ADC1_SA_DMA_CH, TrnCpltIrq); /* AOS must be enabled to use DMA */ /* AOS enabled at first. */ /* If you have enabled AOS before, then the following statement is not needed. */ PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS, Enable); DMA_SetTriggerSrc(ADC1_SA_DMA_UNIT, ADC1_SA_DMA_CH, ADC1_SA_DMA_TRGSRC); // DMA ADC2 SA stcDmaCfg.u16BlockSize = ADC2_SA_CHANNEL_COUNT; stcDmaCfg.u16TransferCnt = ADC2_SA_DMA_BUFFER_MAX * ADC2_SA_CHANNEL_COUNT; // stcDmaCfg.u32SrcAddr = (uint32_t)(&M4_ADC2->DR6); stcDmaCfg.u32DesAddr = (uint32_t)(&Adc2DmaSaBuff[0][0]); stcDmaCfg.u16DesRptSize = ADC2_SA_DMA_BUFFER_MAX * ADC2_SA_CHANNEL_COUNT; stcDmaCfg.u16SrcRptSize = ADC2_SA_CHANNEL_COUNT; PWC_Fcg0PeriphClockCmd(ADC2_SA_DMA_PWC, Enable); DMA_InitChannel(ADC2_SA_DMA_UNIT, ADC2_SA_DMA_CH, &stcDmaCfg); DMA_Cmd(ADC2_SA_DMA_UNIT, Enable); DMA_ChannelCmd(ADC2_SA_DMA_UNIT, ADC2_SA_DMA_CH, Enable); DMA_ClearIrqFlag(ADC2_SA_DMA_UNIT, ADC2_SA_DMA_CH, TrnCpltIrq); DMA_SetTriggerSrc(ADC2_SA_DMA_UNIT, ADC2_SA_DMA_CH, ADC2_SA_DMA_TRGSRC); } /** ******************************************************************************* ** \brief DMA initial configuration. ** ******************************************************************************/ void DmaReloadConfig(uint8_t nAdc) { if (nAdc == 0) { DMA_SetBlockSize(ADC1_SA_DMA_UNIT, ADC1_SA_DMA_CH, ADC1_SA_CHANNEL_COUNT); DMA_SetTransferCnt(ADC1_SA_DMA_UNIT, ADC1_SA_DMA_CH, ADC1_SA_DMA_BUFFER_MAX * ADC1_SA_CHANNEL_COUNT); DMA_Cmd(ADC1_SA_DMA_UNIT, Enable); DMA_ChannelCmd(ADC1_SA_DMA_UNIT, ADC1_SA_DMA_CH, Enable); } else { DMA_SetBlockSize(ADC2_SA_DMA_UNIT, ADC2_SA_DMA_CH, ADC2_SA_CHANNEL_COUNT); DMA_SetTransferCnt(ADC2_SA_DMA_UNIT, ADC2_SA_DMA_CH, ADC2_SA_DMA_BUFFER_MAX * ADC2_SA_CHANNEL_COUNT); DMA_Cmd(ADC2_SA_DMA_UNIT, Enable); DMA_ChannelCmd(ADC2_SA_DMA_UNIT, ADC2_SA_DMA_CH, Enable); } } /** ******************************************************************************* ** \brief DMA interrupt configuration. ** ** \note DMA NVIC number: [Int030_IRQn, Int031_IRQn] ** ******************************************************************************/ void DmaIrqConfig(void) { stc_irq_regi_conf_t stcAdcIrqCfg; stcAdcIrqCfg.enIntSrc = ADC1_SA_DMA_IRQ_NUM; stcAdcIrqCfg.enIRQn = ADC1_DMA_IRQ_NVIC_NUM; stcAdcIrqCfg.pfnCallback = &ADC1_SA_DMA_INT_CB; DmaIrqRegister(&stcAdcIrqCfg, DDL_IRQ_PRIORITY_DEFAULT); stcAdcIrqCfg.enIntSrc = ADC2_SA_DMA_IRQ_NUM; stcAdcIrqCfg.enIRQn = ADC2_DMA_IRQ_NVIC_NUM; stcAdcIrqCfg.pfnCallback = &ADC2_SA_DMA_INT_CB; DmaIrqRegister(&stcAdcIrqCfg, DDL_IRQ_PRIORITY_DEFAULT); } /** ******************************************************************************* ** \brief DMA IRQ register function. ** ******************************************************************************/ void DmaIrqRegister(stc_irq_regi_conf_t *pstcCfg, uint32_t u32Priority) { int16_t s16Vnum = pstcCfg->enIRQn; if ((s16Vnum == ADC1_DMA_IRQ_NVIC_NUM) || (s16Vnum == ADC2_DMA_IRQ_NVIC_NUM)) { if (Ok != enIrqRegistration(pstcCfg)) return; } else { return; } NVIC_ClearPendingIRQ(pstcCfg->enIRQn); NVIC_SetPriority(pstcCfg->enIRQn, u32Priority); NVIC_EnableIRQ(pstcCfg->enIRQn); } /** ******************************************************************************* ** \brief Config the pin which is mapping the channel to analog or digit mode. ** ******************************************************************************/ void AdcSetChannelPinMode(const M4_ADC_TypeDef *ADCx, uint32_t u32Channel, en_pin_mode_t enMode) { stc_port_init_t stcPortInit; MEM_ZERO_STRUCT(stcPortInit); stcPortInit.enPinMode = enMode; stcPortInit.enPullUp = Disable; if (M4_ADC1 == ADCx) { PORT_Init(PortA, Pin00, &stcPortInit); PORT_Init(PortA, Pin01, &stcPortInit); PORT_Init(PortA, Pin02, &stcPortInit); PORT_Init(PortA, Pin03, &stcPortInit); PORT_Init(PortA, Pin04, &stcPortInit); PORT_Init(PortA, Pin05, &stcPortInit); PORT_Init(PortA, Pin06, &stcPortInit); PORT_Init(PortA, Pin07, &stcPortInit); } else if (M4_ADC2 == ADCx) { PORT_Init(PortC, Pin00, &stcPortInit); PORT_Init(PortC, Pin01, &stcPortInit); } } /** ******************************************************************************* ** \brief DMA IRQ callbacks. ** ******************************************************************************/ void Dma1Btc0_IrqHandler(void) { DMA_ClearIrqFlag(ADC1_SA_DMA_UNIT, ADC1_SA_DMA_CH, BlkTrnCpltIrq); DMA_ClearIrqFlag(ADC1_SA_DMA_UNIT, ADC1_SA_DMA_CH, TrnCpltIrq); m_u8Adc1DmaIrqFlag = true; // PORT_ResetBits(PortE, Pin00); NVIC_ClearPendingIRQ(ADC1_DMA_IRQ_NVIC_NUM); } void Dma1Btc2_IrqHandler(void) { DMA_ClearIrqFlag(ADC2_SA_DMA_UNIT, ADC2_SA_DMA_CH, BlkTrnCpltIrq); DMA_ClearIrqFlag(ADC2_SA_DMA_UNIT, ADC2_SA_DMA_CH, TrnCpltIrq); m_u8Adc2DmaIrqFlag = true; // PORT_ResetBits(PortE, Pin00); NVIC_ClearPendingIRQ(ADC2_DMA_IRQ_NVIC_NUM); } uint8_t GetAdcIrgFlag(uint8_t nAdc) { uint8_t result = false; if (nAdc == 0) { result = m_u8Adc1DmaIrqFlag; m_u8Adc1DmaIrqFlag = false; } else { result = m_u8Adc2DmaIrqFlag; m_u8Adc2DmaIrqFlag = false; } return result; } uint16_t AvgAdc1DmaValue(uint16_t ch) { uint32_t sum = 0; for (int i = 0; i < ADC1_SA_DMA_BUFFER_MAX; i++) sum += Adc1DmaSaBuff[i][ch]; return (uint16_t)(sum / ADC1_SA_DMA_BUFFER_MAX); } //VI(Voltage and Current) port Initialize void ADC_Port_Init(void) { /* Config ADCs. */ AdcConfig(); /* Config DMA. */ DmaConfig(); } uint16_t AvgAdc2DmaValue(uint16_t ch) { __IO uint32_t sum = 0; for (int i = 0; i < ADC2_SA_DMA_BUFFER_MAX; i++) { sum += Adc2DmaSaBuff[i][ch]; } return (uint32_t)(sum / ADC2_SA_DMA_BUFFER_MAX); } uint32_t CheckAdc2DmaValue(uint16_t ch) { __IO uint32_t sum = 0; for (int i = 0; i < ADC2_SA_DMA_BUFFER_MAX; i++) { if (sum < Adc2DmaSaBuff[i][ch]) sum = Adc2DmaSaBuff[i][ch]; } return sum; } #ifdef CONSOLE_DEBUG void DisplayAdc2DmaBufferValue(uint8_t ch) { for (int i = 0; i < ADC2_SA_DMA_BUFFER_MAX; i++) { printf("(%3d), %04X\r\n", i, Adc2DmaSaBuff[i][ch]); delay_os_ms(1); } } #endif /*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/