| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394 |
- #include "app/vbat/vbat.h"
- #include "drivers/adc/adc.h"
- #include "core/gpio.h"
- #include "core/main.h" // SystemClock_HSI
- #include "core/config_pins.h"
- #include "core/csect.h"
- static bool VBat_Init();
- static void VBat_DeInit();
- static bool VBat_Serve();
- static uint32_t VBat_GetVoltage();
- static void VBat_SetInterval(size_t ms);
- static void VBat_IC_Enable();
- static void VBat_IC_Disable();
- #define pADCHandle (&ADC1Handle)
- #define VBAT_ADC_RESOLUTION eADCRes_12bit
-
- static bool bVBATInitialized = false;
- static uint32_t VBatMontor_LastTick = 0;
- static uint32_t VBatMontor_Interval = VBAT_MONITOR_INTERVAL;
- static uint32_t g_VBatVoltage = VBAT_INVALID_VALUE;
- static uint32_t g_VDDAVoltage = VBAT_INVALID_VALUE;
- #if VBAT_AVERAGING_POINTS > 0
- static uint32_t aVBatVoltage_Avg[ VBAT_AVERAGING_POINTS ] = {0};
- static size_t VBatVoltageAvgIndex = 1; // VBatVoltageAvgIndex=1 means the averaging mode is active since startup
- #if VBAT_AVERAGING_POINTS > 3
- #include "stdlib.h" //qsort
- #endif
- #endif
- const sVBat_Handle_t VBatHandle = {
- .Init = VBat_Init,
- .SetMeasureInterval = VBat_SetInterval,
- .ServeMonitor = VBat_Serve,
- .GetVoltage = VBat_GetVoltage,
- .DeInit = VBat_DeInit,
- };
- static bool VBat_Init()
- {
- bool bRet = false;
- __DI__ bRet = bVBATInitialized; __EI__
- if( !bRet )
- {
- if( SystemClock_HSI( true ) )
- {
- if( pADCHandle->Init( VBAT_ADC_RESOLUTION ) )
- {
- VBat_IC_Disable();
- {
- GPIO_InitTypeDef GPIO_InitStruct = {0};
- // Configure the pin muxing
- GPIO_InitStruct.Pin = CONFIG_PIN__VBAT_ADC;
- GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
- HAL_GPIO_Init(CONFIG_PORT__VBAT_ADC, &GPIO_InitStruct);
- }
- {
- GPIO_InitTypeDef GPIO_InitStruct = {0};
- // Configure the pin muxing
- GPIO_InitStruct.Pin = CONFIG_PIN__VBAT_EN;
- GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
- HAL_GPIO_Init(CONFIG_PORT__VBAT_EN, &GPIO_InitStruct);
- }
- #if VBAT_INIT_FOR_MEASURE == 0
- __DI__
- g_VBatVoltage = VBAT_INVALID_VALUE;
- #if VBAT_AVERAGING_POINTS > 0
- for( size_t i = 0; i < VBAT_AVERAGING_POINTS; ++i )
- { aVBatVoltage_Avg[ i ] = 0; }
- VBatVoltageAvgIndex = 1; // VBatVoltageAvgIndex=1 means the averaging mode is active since startup
- #endif
- __EI__
- #endif
- bRet = true;
- }
- }
- }
- if( !bRet )
- {
- VBat_DeInit();
- SystemClock_HSI( false );
- }
- __DI__ bVBATInitialized = bRet; __EI__
- return bRet;
- }
- static void VBat_DeInit()
- {
- DI();
- if( !bVBATInitialized )
- {
- EI();
- return;
- }
- EI();
- VBat_IC_Disable();
- {
- GPIO_InitTypeDef GPIO_InitStruct = {0};
- // Configure the pin muxing
- GPIO_InitStruct.Pin = CONFIG_PIN__VBAT_ADC;
- GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
- HAL_GPIO_Init(CONFIG_PORT__VBAT_ADC, &GPIO_InitStruct);
- }
- {
- GPIO_InitTypeDef GPIO_InitStruct = {0};
- // Configure the pin muxing
- GPIO_InitStruct.Pin = CONFIG_PIN__VBAT_EN;
- GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
- GPIO_InitStruct.Pull = GPIO_PULLDOWN;
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
- HAL_GPIO_Init(CONFIG_PORT__VBAT_EN, &GPIO_InitStruct);
- }
- pADCHandle->Stop( CONFIG_ADC__VBAT_ADC );
- pADCHandle->DeInit();
- SystemClock_HSI( false );
- __DI__ bVBATInitialized = false; __EI__
- }
- static void VBat_SetInterval(uint32_t ms)
- {
- __DI__ VBatMontor_Interval = ms; __EI__
- }
- // VBat_IC_Enable
- // Enable external battery sensing circuit (MOSFET)
- static void VBat_IC_Enable()
- {
- HAL_GPIO_WritePin( CONFIG_PORT__VBAT_EN, CONFIG_PIN__VBAT_EN, GPIO_PIN_SET );
- // wait until transition process completes in external RC-circuit
- HAL_Wait_us( 100 );
- }
- // VBat_IC_Disable
- // Disable external battery sensing circuit (MOSFET)
- static void VBat_IC_Disable()
- {
- HAL_GPIO_WritePin( CONFIG_PORT__VBAT_EN, CONFIG_PIN__VBAT_EN, GPIO_PIN_RESET );
- }
- #if VBAT_AVERAGING_POINTS == 3
- uint16_t middle_of_3(uint16_t a, uint16_t b, uint16_t c)
- {
- uint16_t middle;
-
- if ((a <= b) && (a <= c)){
- middle = (b <= c) ? b : c;
- }
- else{
- if ((b <= a) && (b <= c)){
- middle = (a <= c) ? a : c;
- }
- else{
- middle = (a <= b) ? a : b;
- }
- }
-
- return middle;
- }
- #endif
- #if VBAT_AVERAGING_POINTS > 3
- static int qsort_compare( const uint32_t * i, const uint32_t * j )
- {
- return ((*i > *j)?1:( (*i < *j)?-1:0 ));
- }
- #endif
- // VBat_Serve()
- // VBat: Battery Voltage sensing measurement
- // Implements the battery voltage sensing using periodical measurements.
- // Take a look on the "picture":
- //
- // |<--------- T ---------->|
- // | |
- // *------------------------|-|-|---------------------------|-|-|------------....--> time
- // ^ Startup Take several measurements Take several measurements
- // Function takes several measurements each interval T (@VBatMontor_Interval) - package of measurements
- // During performing these several measurements the function peforms median filtering.
- // Variable @VBatVoltageAvgIndex is responsible for indexing each measurement in the package.
- static bool VBat_Serve()
- {
- bool bServe = false;
- bool bUpdated = false;
- // Is averaging enabled?
- #if VBAT_AVERAGING_POINTS > 0
- // averaging enabled
- __DI__
- #if VBAT_INIT_FOR_MEASURE == 0
- if( bVBATInitialized )
- {
- #endif
- // Averaging is active if VBatVoltageAvgIndex>0 and VBatVoltageAvgIndex <= VBAT_AVERAGING_POINTS
- if( (VBatVoltageAvgIndex > 0) && (VBatVoltageAvgIndex <= VBAT_AVERAGING_POINTS) )
- {
- // averaging interval
- // Is @VBAT_AVERAGING_INTERVAL timeout ran out?
- bServe = (HAL_GetTick() - VBatMontor_LastTick > VBAT_AVERAGING_INTERVAL );
- }
- else
- {
- // measurement interval (control interval)
- // Is @VBatMontor_LastTick timeout ran out?
- bServe = (HAL_GetTick() - VBatMontor_LastTick > VBatMontor_Interval);
- }
- #if VBAT_INIT_FOR_MEASURE == 0
- }
- #endif
- __EI__
- #else
- // averaging disabled
- #if VBAT_INIT_FOR_MEASURE
- __DI__ bServe = (HAL_GetTick() - VBatMontor_LastTick > VBatMontor_Interval); __EI__
- #else
- __DI__ bServe = bVBATInitialized && (HAL_GetTick() - VBatMontor_LastTick > VBatMontor_Interval); __EI__
- #endif
- #endif
- if( bServe )
- {
- #if VBAT_INIT_FOR_MEASURE
- if( VBat_Init() )
- {
- #endif
- VBat_IC_Enable();
- bool bResult = false;
- uint32_t xVDDAVoltage = 0;
- uint32_t xVBatVoltage = 0;
- uint32_t xVDDAVoltage_ADC = VBAT_INVALID_VALUE;
- uint32_t xVBatVoltage_ADC = VBAT_INVALID_VALUE;
- // To measure actual voltage it is required
- // to measure actual power supply voltage using ADC_CHANNEL_VREFINT
- if( pADCHandle->Start( ADC_CHANNEL_VREFINT ) )
- {
- if( pADCHandle->Measure( VBAT_MONITOR_MEAS_TIMEOUT, &xVDDAVoltage_ADC ) )
- {
- if( pADCHandle->Start( CONFIG_ADC__VBAT_ADC ) )
- {
- if( pADCHandle->Measure( VBAT_MONITOR_MEAS_TIMEOUT, &xVBatVoltage_ADC ) )
- {
- // Calculate VDDA voltage first
- xVDDAVoltage = (ADC_VREF_VOLTAGE_mV * ADC_GetFullScale( VBAT_ADC_RESOLUTION ) / xVDDAVoltage_ADC);
- // Find out the target voltage using VDDA:
- xVBatVoltage = xVDDAVoltage * xVBatVoltage_ADC / ADC_GetFullScale( VBAT_ADC_RESOLUTION );
- bResult = true;
- }
- }
- }
- }
- __DI__
- #if VBAT_AVERAGING_POINTS > 0
- #if VBAT_AVERAGING_POINTS < 3
- #error Invalid VBAT_AVERAGING_POINTS value: the value greater than 2 is required for meadian filter
- #endif
- #if VBAT_AVERAGING_POINTS % 2 == 0
- #error Invalid VBAT_AVERAGING_POINTS value: an odd value is required for meadian filter
- #endif
- if( bResult )
- {
- // The program reach this point due to the following reasons:
- // - in interval mode: @VBatMontor_Interval timeout expires;
- // so it is required to activate averaging mode and collect samples.
- // - in averaging mode: @VBAT_AVERAGING_INTERVAL timeout expires;
- // so it is required to collect current sample and wait for the next one.
- if( VBatVoltageAvgIndex == 0 )
- {
- // so, it is required to switch to averaging mode if it is not active
- VBatVoltageAvgIndex = 1;
- }
- // update VDDA voltage without averaging
- g_VDDAVoltage = xVDDAVoltage;
- // collecting samples
- aVBatVoltage_Avg[ VBatVoltageAvgIndex - 1 ] = xVBatVoltage;
- // take the sample in account, shift to the next filter cell
- VBatVoltageAvgIndex++;
- // are filter cells full?
- if( VBatVoltageAvgIndex > VBAT_AVERAGING_POINTS )
- {
- VBatVoltageAvgIndex = 0; // disable averaging, switch to the interval mode
- bUpdated = true;
- #if VBAT_AVERAGING_POINTS == 3
- g_VBatVoltage = middle_of_3( aVBatVoltage_Avg[0], aVBatVoltage_Avg[1], aVBatVoltage_Avg[2] );
- #elif VBAT_AVERAGING_POINTS > 3
- #warning Uneffective sorting, you sould use VBAT_AVERAGING_POINTS = 3
- qsort( aVBatVoltage_Avg,
- VBAT_AVERAGING_POINTS,
- sizeof(aVBatVoltage_Avg[0]),
- (int(*) (const void *, const void *))qsort_compare );
- g_VBatVoltage = aVBatVoltage_Avg[ ((VBAT_AVERAGING_POINTS - 1U) / 2U) ];
- #else
- #error Invalid VBAT_AVERAGING_POINTS value
- #endif
- }
- }
- else
- {
- g_VDDAVoltage = VBAT_INVALID_VALUE;
- g_VBatVoltage = VBAT_INVALID_VALUE;
- }
- #else
- if( bResult )
- {
- g_VDDAVoltage = xVDDAVoltage;
- g_VBatVoltage = xVBatVoltage;
- bUpdated = true;
- }
- else
- {
- g_VDDAVoltage = VBAT_INVALID_VALUE;
- g_VBatVoltage = VBAT_INVALID_VALUE;
- }
- #endif
- VBatMontor_LastTick = HAL_GetTick();
- __EI__
- VBat_IC_Disable();
- #if VBAT_INIT_FOR_MEASURE
- VBat_DeInit();
- }
- else
- {
- __DI__ g_VBatVoltage = VBAT_INVALID_VALUE; __EI__
- }
- #endif
- }
- (void)g_VDDAVoltage;
- return bUpdated;
- }
- static uint32_t VBat_GetVoltage()
- {
- uint32_t xValue;
- #if VBAT_VOLTAGE_MULTIPLIER > 0 || VBAT_VOLTAGE_DIVIDER > 0
- #if VBAT_VOLTAGE_MULTIPLIER == 2 && VBAT_VOLTAGE_DIVIDER < 2
- __DI__ xValue = (g_VBatVoltage << 1); __EI__
- #else
- __DI__ xValue = g_VBatVoltage; __EI__
- #if VBAT_VOLTAGE_MULTIPLIER > 0
- xValue *= VBAT_VOLTAGE_MULTIPLIER;
- #endif
- #if VBAT_VOLTAGE_DIVIDER > 0
- xValue /= VBAT_VOLTAGE_DIVIDER;
- #endif
- #endif
- #else
- __DI__ xValue = g_VBatVoltage; __EI__
- #endif
- return xValue;
- }
|