Newer
Older
/*
* temperatureRegulation.c
*
* Created on: Apr 16, 2023
* Author: Flax
*
* Prefix : REG
*/
// ==============
// Local includes
// ==============
#include "temperatureRegulation.h"
// ==============
// Local typedefs
// ==============
typedef enum {
REG_MODE_OFF,
REG_MODE_REGUL,
REG_MODE_ADC_PRE,
REG_MODE_ADC_START,
REG_MODE_ADC_WAIT,
}e_REGMode;
// ===============
// Local constants
// ===============
#define cREGTempSPTMax (400U)
#define cREGTempSPTMin (50U)
#define cREGTempSPTDft (250U)
#define cREGTempSPTStbyDft (100U)
#define cREGPwmMax (1023)
#define cREGErrorTempThres (50)
#define cREGErrorTimeout (5000)
#define cRegPIDInteg (5)
#define cRegPIDDeriv (5)
// Temperature measure transfer function parameters
// OPA gain : 681
// Input divider bridge gain : 100k / (100k + 5k6) = 0.946969
// On legacy Arduino code : gain = 0.39, offset = 23.9, resolution 10 bits
// Translated to 12 bits : 0.0975 ~= 100 / 1024
#define ADC_TO_TEMP_GAIN_NUM (100U)
#define ADC_TO_TEMP_GAIN_DEN (1024U)
#define ADC_TO_TEMP_OFFSET (24U)
#define cREGAdcErrorThres (4090U)
#define cREGAdcAcqCycle (100U)
#define mREGSetPwm(val) (mREGPwmSetCompareValue(cREGPwmMax - val))
// ===============
// Local variables
// ===============
static e_REGMode RegModeCurrent_E;
static bool RegOffState_B;
static bool RegStandbyState_B;
static bool RegErrorState_B;
static uint16_t RegTempSPT_U16;
static uint16_t RegTempMeas_U16[2U];
static uint16_t RegTempMeasBuffer_U16A[2U];
static int32_t RegPwmDyc_S32;
static uint32_t RegPwmDyc_U32;
static uint16_t RegTempDegFilt_U16;
static uint16_t RegTempFiltCnt_U16;
static uint32_t RegErrorTimeoutCnt_U32;
// ADC
static uint16_t RegAdcCycleCnt_U16;
static bool RegAdcOngoing_B;
// PID
static int32_t RegEpsilon_S32A[2U];
// DEBUG
uint8_t debug_buffer_U8A[3];
uint16_t time_debug_U16 = 0;
// DEBUG
// ==========================
// Local functions prototypes
// ==========================
// ===========================
// Local functions definitions
// ===========================
// ============================
// Shared functions definitions
// ============================
void REGInit (void)
{
RegOffState_B = true;
RegStandbyState_B = false;
RegModeCurrent_E = REG_MODE_OFF;
// TODO : load NVM values
RegTempSPT_U16 = cREGTempSPTDft;
RegTempSPTStby_U16 = cREGTempSPTStbyDft;
RegErrorTimeoutCnt_U32 = cREGErrorTimeout;
}
void REGStart (void)
{
mREDAdcEnable();
LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH1);
LL_TIM_EnableCounter(TIM2);
RegModeCurrent_E = REG_MODE_ADC_PRE;
}
void REGStop (void)
{
}
void REGCyclicTask (void)
{
case REG_MODE_OFF:
break;
case REG_MODE_REGUL:
if (RegAdcCycleCnt_U16 < cREGAdcAcqCycle)
if (mREGAdcIsReady())
{
RegAdcOngoing_B = true;
RegModeCurrent_E = REG_MODE_ADC_PRE;
}
else
{
// ADC not ready
RegTempMeasBuffer_U16A[1] = 0xFFFF;
RegAdcCycleCnt_U16 = 0;
}
break;
case REG_MODE_ADC_PRE:
RegModeCurrent_E = REG_MODE_ADC_START;
break;
case REG_MODE_ADC_START:
mREGAdcStartConversion();
RegModeCurrent_E = REG_MODE_ADC_WAIT;
break;
case REG_MODE_ADC_WAIT:
if (mREGAdcEndOfConversion() == true)
// Read ADC input
RegTempMeasBuffer_U16A[1] = mREGAdcReadValue();
// Calculate average
RegTempMeasBuffer_U16A[0] += RegTempMeasBuffer_U16A[1];
RegTempMeasBuffer_U16A[0] = RegTempMeasBuffer_U16A[0] >> 1U;
RegTempMeas_U16[1] = RegTempMeas_U16[0]; // Memorise previous value
RegTempMeas_U16[0] = RegTempMeasBuffer_U16A[0];
if (RegTempMeasBuffer_U16A[1] >= cREGAdcErrorThres)
{
// Error
RegErrorState_B = true;
}
RegAdcCycleCnt_U16 = 0;
RegAdcOngoing_B = false;
RegModeCurrent_E = REG_MODE_REGUL;
break;
default:
break;
}
// Convert to degrees
RegTempDeg_U16 = (uint16_t)(((((uint32_t)ADC_TO_TEMP_GAIN_NUM * (uint32_t)(RegTempMeas_U16[0])) / (uint32_t)ADC_TO_TEMP_GAIN_DEN) + (uint32_t)ADC_TO_TEMP_OFFSET) & (uint32_t)0x0000FFFF);
/**********************************************************************************/
/* PID */
/**********************************************************************************/
// Regulation is done in degrees
RegEpsilon_S32A[1] = RegEpsilon_S32A[0]; // Memorise previous value
RegEpsilon_S32A[0] = RegTempSPT_U16 - RegTempDeg_U16;
// Check error - Overheat
if (RegEpsilon_S32A[0] > cREGErrorTempThres)
{
if (RegErrorTimeoutCnt_U32 > 0)
{
RegErrorTimeoutCnt_U32--;
}
else
{
// Error - Too much temperature error for too long
RegErrorState_B = true;
}
}
else
{
RegErrorTimeoutCnt_U32 = cREGErrorTimeout;
}
// Process PID output
RegPwmDyc_S32 = (RegEpsilon_S32A[0] * cRegPIDProp)
+ ((RegEpsilon_S32A[0] - RegEpsilon_S32A[1]) * cRegPIDDeriv)
+ ((RegEpsilon_S32A[0] + RegEpsilon_S32A[1]) * cRegPIDInteg);
// Check regulation state before processing the output PWM
// if ((RegErrorState_B == false) && (RegOffState_B == false))
if ((RegOffState_B == false))
{
RegPwmDyc_U32 = (uint32_t)cREGPwmMax;
}
else if (RegPwmDyc_S32 > 0)
{// Only keep positive values
RegPwmDyc_U32 = RegPwmDyc_S32;
}
else
{
RegPwmDyc_U32 = 0U;
}
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
// DEBUG
// https://github.com/nathandunk/BetterSerialPlotter#example-arduino-code
time_debug_U16++;
if (time_debug_U16 == 1000)
{
time_debug_U16 = 0;
}
DISPValueToDigits(time_debug_U16, debug_buffer_U8A);
LL_USART_TransmitData8(USART2, 0x74); // "t"
while (LL_USART_IsActiveFlag_TXE(USART2) == 0) {}
LL_USART_TransmitData8(USART2, 0x30 + debug_buffer_U8A[0]);
while (LL_USART_IsActiveFlag_TXE(USART2) == 0) {}
LL_USART_TransmitData8(USART2, 0x30 + debug_buffer_U8A[1]);
while (LL_USART_IsActiveFlag_TXE(USART2) == 0) {}
LL_USART_TransmitData8(USART2, 0x30 + debug_buffer_U8A[2]);
while (LL_USART_IsActiveFlag_TXE(USART2) == 0) {}
LL_USART_TransmitData8(USART2, 0x09); // "/t"
while (LL_USART_IsActiveFlag_TXE(USART2) == 0) {}
DISPValueToDigits(RegTempDeg_U16 / 10, debug_buffer_U8A);
LL_USART_TransmitData8(USART2, 0x30); // "0"
while (LL_USART_IsActiveFlag_TXE(USART2) == 0) {}
LL_USART_TransmitData8(USART2, 0x2E); // "."
while (LL_USART_IsActiveFlag_TXE(USART2) == 0) {}
LL_USART_TransmitData8(USART2, 0x30 + debug_buffer_U8A[0]);
while (LL_USART_IsActiveFlag_TXE(USART2) == 0) {}
LL_USART_TransmitData8(USART2, 0x30 + debug_buffer_U8A[1]);
while (LL_USART_IsActiveFlag_TXE(USART2) == 0) {}
LL_USART_TransmitData8(USART2, 0x30 + debug_buffer_U8A[2]);
while (LL_USART_IsActiveFlag_TXE(USART2) == 0) {}
LL_USART_TransmitData8(USART2, 0x09); // "/t"
while (LL_USART_IsActiveFlag_TXE(USART2) == 0) {}
DISPValueToDigits(RegPwmDyc_U32 / 10, debug_buffer_U8A);
LL_USART_TransmitData8(USART2, 0x30); // "0"
while (LL_USART_IsActiveFlag_TXE(USART2) == 0) {}
LL_USART_TransmitData8(USART2, 0x2E); // "."
while (LL_USART_IsActiveFlag_TXE(USART2) == 0) {}
LL_USART_TransmitData8(USART2, 0x30 + debug_buffer_U8A[0]);
while (LL_USART_IsActiveFlag_TXE(USART2) == 0) {}
LL_USART_TransmitData8(USART2, 0x30 + debug_buffer_U8A[1]);
while (LL_USART_IsActiveFlag_TXE(USART2) == 0) {}
LL_USART_TransmitData8(USART2, 0x30 + debug_buffer_U8A[2]);
while (LL_USART_IsActiveFlag_TXE(USART2) == 0) {}
LL_USART_TransmitData8(USART2, 0x0A); // "/n"
while (LL_USART_IsActiveFlag_TXE(USART2) == 0) {}
LL_USART_TransmitData8(USART2, 0x0D); // "/r"
while (LL_USART_IsActiveFlag_TXE(USART2) == 0) {}
// DEBUG
/**********************************************************************************/
if (RegAdcOngoing_B == false)
{
// mREGSetPwm(cREGPwmMax);
mREGSetPwm(RegPwmDyc_U32);
//mREGPwmSetCompareValue(cREGPwmMax / 32);
}
else
{
// No switching during ADC acquisition
mREGSetPwm(0U);
}
// Filter physical temperature - for cleaner display
if (RegTempFiltCnt_U16 < cREGAdcToTempFilter)
{
RegTempFiltCnt_U16++;
}
else
{ // Sub-sampling for cleaner display
RegTempFiltCnt_U16 = 0U;
RegTempDegFilt_U16 = RegTempDeg_U16;
}
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
bool REGIsError (void)
{
return RegErrorState_B;
}
bool REGIsStandby(void)
{
return RegStandbyState_B;
}
bool REGIsOff(void)
{
return RegOffState_B;
}
void REGErrorReset (void)
{
RegOffState_B = false;
}
void REGStandbySet(void)
{
RegStandbyState_B = true;
}
void REGStandbyReset(void)
{
RegStandbyState_B = false;
}
void REGOffSet(void)
{
RegOffState_B = true;
}
void REGOffReset(void)
{
RegOffState_B = false;
}
bool REGSPTSet (uint16_t temp_spt_u16)
{
bool ret_B = false;
if ((temp_spt_u16 <= (uint16_t)cREGTempSPTMax) && (temp_spt_u16 >= (uint16_t)cREGTempSPTMin))
{
RegTempSPT_U16 = temp_spt_u16;
ret_B = true;
}
return (ret_B);
}
uint16_t REGSPTGet (void)
{
return RegTempSPT_U16;
}
uint16_t REGTempGet (void)
{
bool REGSPTStbySet (uint16_t temp_spt_u16)
{
bool ret_B = false;
if ((temp_spt_u16 <= (uint16_t)cREGTempSPTMax) && (temp_spt_u16 >= (uint16_t)cREGTempSPTMin))
{
RegTempSPTStby_U16 = temp_spt_u16;
ret_B = true;
}
return (ret_B);
}
uint16_t REGSPTStbyGet (void)
{
return RegTempSPTStby_U16;
}