/* * batterie.c * * Created on: Sep 12, 2022 * Author: dimercur */ #include "batterie.h" #include "stm32l0xx.h" #include "stm32l0xx_ll_gpio.h" #include "timers.h" typedef enum { CHARGEUR_NOT_PLUGGED, CHARGEUR_IN_CHARGE, CHARGEUR_CHARGE_COMPLETE, CHARGEUR_ERROR } BATTERIE_StatusChargerTypedef; #define BATTERIE_MAX_ERROR 3 extern ADC_HandleTypeDef hadc; uint8_t conversion_complete; uint16_t adc_raw_value; StaticTask_t xTaskBatterie; /* Buffer that the task being created will use as its stack. Note this is an array of StackType_t variables. The size of StackType_t is dependent on the RTOS port. */ StackType_t xStackBatterie[ STACK_SIZE ]; TaskHandle_t xHandleBatterie = NULL; TaskHandle_t task_handler; TaskHandle_t charger_thread_handler; /* TimerButton sert à attendre ~ 3secondes avant de prendre en compte les IT bouton * En effet, au demarrage, le bouton est appuyé pour lancer le systeme. ceci genere alors une IT bouton, * ammenant à envoyer le message MSG_ID_BUTTON_PRESSED, demandant l'arret du systeme * * De ce fait, avec cette tempo, on s'assure de ne pas prendre en compte les IT dans les 3 premieres secondes. */ StaticTimer_t xBufferTimerButton; TimerHandle_t xHandleTimerButton = NULL; void vTimerButtonCallback( TimerHandle_t xTimer ); uint8_t BUTTON_Inactivity=1; //start with button on/off inactive void BATTERIE_VoltageThread(void* params); void BATTERIE_Init(void) { //task_handler = NULL; //charger_thread_handler = NULL; /* Create the task without using any dynamic memory allocation. */ xHandleBatterie = xTaskCreateStatic( BATTERIE_VoltageThread, /* Function that implements the task. */ "BATTERIE Voltage", /* Text name for the task. */ STACK_SIZE, /* Number of indexes in the xStack array. */ NULL, /* Parameter passed into the task. */ PriorityBatterieHandler,/* Priority at which the task is created. */ xStackBatterie, /* Array to use as the task's stack. */ &xTaskBatterie); /* Variable to hold the task's data structure. */ /* Create a periodic task without using any dynamic memory allocation. */ xHandleTimerButton = xTimerCreateStatic( "Inactivity Button Timer", pdMS_TO_TICKS(BUTTON_INACTIVITY_PERIODE), pdTRUE, ( void * ) 0, vTimerButtonCallback, &xBufferTimerButton); xTimerStart(xHandleTimerButton,0 ); vTaskResume(xHandleBatterie); } /* * Lit les pins GPIO */ BATTERIE_StatusChargerTypedef BATTERIE_LireStatusChargeur(void) { uint32_t st2 = LL_GPIO_ReadInputPort(CHARGER_ST2_GPIO_Port) & CHARGER_ST2_Pin; uint32_t st1 = LL_GPIO_ReadInputPort(CHARGER_ST1_GPIO_Port) & CHARGER_ST1_Pin; BATTERIE_StatusChargerTypedef status; if (st1 && st2) status = CHARGEUR_NOT_PLUGGED; else if (st1 && !st2) status = CHARGEUR_CHARGE_COMPLETE; else if (!st1 && st2) status = CHARGEUR_IN_CHARGE; else /* !st1 && !st2 */ status = CHARGEUR_ERROR; return status; } int BATTERIE_LireTension(uint16_t *val) { uint32_t ulNotificationValue; conversion_complete = 0; adc_raw_value = 0; task_handler = xTaskGetCurrentTaskHandle(); if (HAL_ADC_Start_IT(&hadc) != HAL_OK) return -1; ulNotificationValue = ulTaskNotifyTake( pdTRUE, pdMS_TO_TICKS(100)); // wait max 100 ms if (ulNotificationValue == 1) { /* The transmission ended as expected. */ *val = adc_raw_value; } else { /* The call to ulTaskNotifyTake() timed out. */ return -2; } task_handler = NULL; return 0; } /* * Il faut considerer ces valeurs comme les seuils de baculement dans une categorie * ou une autre * * Seuil : critical low high * Tension batterie: 2.9 critic 3.1 low 3.3 med 3.6 high 4.2 * */ #ifdef TESTS uint8_t BATTERIE_LEVEL_CRITICAL=135; uint8_t BATTERIE_LEVEL_LOW=145; uint8_t BATTERIE_LEVEL_HIGH=155; uint8_t BATTERIE_LEVEL_CHARGE_LOW=150; uint8_t BATTERIE_LEVEL_CHARGE_HIGH=170; uint8_t BATTERIE_currentValue; #else #define BATTERIE_LEVEL_CRITICAL 135 #define BATTERIE_LEVEL_LOW 145 #define BATTERIE_LEVEL_HIGH 155 #define BATTERIE_LEVEL_CHARGE_LOW 150 #define BATTERIE_LEVEL_CHARGE_HIGH 170 #endif /* TESTS */ uint16_t BATTERIE_BatteryLevel(uint8_t voltage, BATTERIE_StatusChargerTypedef chargerStatus) { uint16_t msgId=0; #ifdef TESTS BATTERIE_currentValue=voltage; #endif /* TESTS */ switch (chargerStatus) { case CHARGEUR_CHARGE_COMPLETE: msgId = MSG_ID_BAT_CHARGE_COMPLETE; break; case CHARGEUR_IN_CHARGE: if (voltage<=BATTERIE_LEVEL_CHARGE_LOW) msgId = MSG_ID_BAT_CHARGE_LOW; else if (voltage>=BATTERIE_LEVEL_CHARGE_HIGH) msgId = MSG_ID_BAT_CHARGE_HIGH; else msgId = MSG_ID_BAT_CHARGE_MED; break; case CHARGEUR_NOT_PLUGGED: if (voltage<=BATTERIE_LEVEL_CRITICAL) msgId = MSG_ID_BAT_CRITICAL_LOW; else if (voltage<=BATTERIE_LEVEL_LOW) msgId = MSG_ID_BAT_LOW; else if (voltage>=BATTERIE_LEVEL_HIGH) msgId = MSG_ID_BAT_HIGH; else msgId = MSG_ID_BAT_MED; break; default: msgId = MSG_ID_BAT_CHARGE_ERR; } return msgId; } void BATTERIE_VoltageThread(void* params) { static uint16_t tension; static uint8_t batteryErrorCnt=0; BATTERIE_StatusChargerTypedef currentStatus; uint16_t messageID; TickType_t xLastWakeTime; // Initialise the xLastWakeTime variable with the current time. xLastWakeTime = xTaskGetTickCount(); while (1) { if (BATTERIE_LireTension(&tension) ==0) { currentStatus = BATTERIE_LireStatusChargeur(); if (currentStatus == CHARGEUR_ERROR) { batteryErrorCnt++; if (batteryErrorCnt>=BATTERIE_MAX_ERROR) MESSAGE_SendMailbox(APPLICATION_Mailbox, MSG_ID_BAT_CHARGE_ERR, (QueueHandle_t)0x0, (void*)NULL); } else { messageID = BATTERIE_BatteryLevel(tension, currentStatus); MESSAGE_SendMailbox(APPLICATION_Mailbox, messageID, (QueueHandle_t)0x0, (void*)NULL); } #ifdef TESTS MESSAGE_SendMailbox(APPLICATION_Mailbox, MSG_ID_BAT_LEVEL, (QueueHandle_t)0x0, (void*)&tension); #endif /* TESTS*/ } else { MESSAGE_SendMailbox(APPLICATION_Mailbox, MSG_ID_BAT_ADC_ERR, (QueueHandle_t)0x0, (void*)0x0); } // Wait for the next cycle. vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS(BATTERIE_PERIODE_SCRUTATION)); } } void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; adc_raw_value = HAL_ADC_GetValue(hadc); if (task_handler != NULL) { /* Notify the task that an event has been emitted. */ vTaskNotifyGiveFromISR(task_handler, &xHigherPriorityTaskWoken ); /* There are no more eventin progress, so no tasks to notify. */ task_handler = NULL; /* If xHigherPriorityTaskWoken is now set to pdTRUE then a context switch should be performed to ensure the interrupt returns directly to the highest priority task. The macro used for this purpose is dependent on the port in use and may be called portEND_SWITCHING_ISR(). */ portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); } } void vTimerButtonCallback( TimerHandle_t xTimer ) { BUTTON_Inactivity=0; xTimerStop(xHandleTimerButton,0 ); } /** * @brief This function handles EXTI line0 interrupt. */ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; // if (GPIO_Pin == USB_SENSE_Pin) { // Le chargeur vient d'etre branché ou debranché // if (HAL_GPIO_ReadPin(USB_SENSE_GPIO_Port, GPIO_Pin)==GPIO_PIN_SET) // le chargeur est branché // MESSAGE_SendMailboxFromISR(APPLICATION_Mailbox, MSG_ID_BAT_CHARGE_ON, (QueueHandle_t)0x0, 0x0, &xHigherPriorityTaskWoken); // else // MESSAGE_SendMailboxFromISR(APPLICATION_Mailbox, MSG_ID_BAT_CHARGE_OFF, (QueueHandle_t)0x0, 0x0, &xHigherPriorityTaskWoken); // } // else if (GPIO_Pin == BUTTON_SENSE_Pin) { // on vient d'appuyer sur le bouton on/off if (!BUTTON_Inactivity) { if (HAL_GPIO_ReadPin(BUTTON_SENSE_GPIO_Port, GPIO_Pin)==GPIO_PIN_RESET) // GPIOB.3 = 0 => le bouton est appuyé MESSAGE_SendMailboxFromISR(APPLICATION_Mailbox, MSG_ID_BUTTON_PRESSED, (QueueHandle_t)0x0, 0x0, &xHigherPriorityTaskWoken); } } if (xHigherPriorityTaskWoken) { /* If xHigherPriorityTaskWoken is now set to pdTRUE then a context switch should be performed to ensure the interrupt returns directly to the highest priority task. The macro used for this purpose is dependent on the port in use and may be called portEND_SWITCHING_ISR(). */ portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); } }