4 * This file is part of BeRTOS.
6 * Bertos is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * As a special exception, you may use this file as part of a free software
21 * library without restriction. Specifically, if other files instantiate
22 * templates or use macros or inline functions from this file, or you compile
23 * this file and link it with other files to produce an executable, this
24 * file does not by itself cause the resulting executable to be covered by
25 * the GNU General Public License. This exception does not however
26 * invalidate any other reasons why the executable file might be covered by
27 * the GNU General Public License.
29 * Copyright 2005 Develer S.r.l. (http://www.develer.com/)
33 * \brief Thermo-control driver.
35 * The Thermo controll can works both with kernel or without it. In the case
36 * we use kernel, the thermo controll is done by one process that poll every
37 * CONFIG_THERMO_INTERVAL_MS the temperature sensor and make all operation to
38 * follow the target temperature. While we not use the kernel the module works
39 * with one timer interrupt in the same way of the kenel case.
41 * \author Giovanni Bajo <rasky@develer.com>
42 * \author Francesco Sacchi <batt@develer.com>
43 * \author Daniele Basile <asterix@develer.com>
47 #include "hw/thermo_map.h"
48 #include "hw/hw_thermo.h"
50 #include "cfg/cfg_thermo.h"
52 #include <cfg/module.h>
53 #include <cfg/macros.h>
54 #include <cfg/debug.h>
55 // Define logging setting (for cfg/log.h module).
56 #define LOG_LEVEL CONFIG_THERMO_LOG_LEVEL
57 #define LOG_VERBOSITY CONFIG_THERMO_LOG_FORMAT
60 #include <drv/thermo.h>
61 #include <drv/timer.h>
64 #include <kern/proc.h>
67 #define THERMO_HEATING BV(0)
68 #define THERMO_FREEZING BV(1)
69 #define THERMO_TGT_REACH BV(2)
70 #define THERMOERRF_NTCSHORT BV(3)
71 #define THERMOERRF_NTCOPEN BV(4)
72 #define THERMOERRF_TIMEOUT BV(5)
73 #define THERMO_ACTIVE BV(6)
74 #define THERMO_TIMER BV(7)
76 #define THERMO_ERRMASK (THERMOERRF_NTCSHORT | THERMOERRF_NTCOPEN | THERMOERRF_TIMEOUT)
80 /** Stack process for Thermo process. */
81 static PROC_DEFINE_STACK(thermo_poll_stack, 400);
83 /** Timer for thermo-regulation. */
84 static Timer thermo_timer;
87 typedef struct ThermoControlDev
89 deg_t hifi_samples[CONFIG_THERMO_HIFI_NUM_SAMPLES];
90 deg_t cur_hifi_sample;
92 thermostatus_t status;
97 /** Array of thermo-devices. */
98 ThermoControlDev devs[THERMO_CNT];
101 * Return the status of the specific \a dev thermo-device.
103 thermostatus_t thermo_status(ThermoDev dev)
105 ASSERT(dev < THERMO_CNT);
106 return devs[dev].status;
111 * Do a single thermo control for device \a dev.
113 static void thermo_do(ThermoDev index)
115 ThermoControlDev* dev = &devs[index];
117 deg_t tolerance = thermo_hw_tolerance(index);
119 cur_temp = thermo_hw_read(index);
121 // Store the sample into the hifi FIFO buffer for later interpolation
122 dev->hifi_samples[dev->cur_hifi_sample] = cur_temp;
123 if (++dev->cur_hifi_sample == CONFIG_THERMO_HIFI_NUM_SAMPLES)
124 dev->cur_hifi_sample = 0;
126 cur_temp = thermo_readTemperature(index);
128 if (cur_temp == NTC_SHORT_CIRCUIT || cur_temp == NTC_OPEN_CIRCUIT)
130 if (cur_temp == NTC_SHORT_CIRCUIT)
132 LOG_INFOB(if (!(dev->status & THERMOERRF_NTCSHORT))
133 LOG_INFO("dev[%d], thermo_do: NTC_SHORT\n",index););
135 dev->status |= THERMOERRF_NTCSHORT;
140 LOG_INFOB(if (!(dev->status & THERMOERRF_NTCOPEN))
141 LOG_INFO("dev[%d], thermo_do: NTC_OPEN\n", index););
143 dev->status |= THERMOERRF_NTCOPEN;
146 /* Reset timeout when there is an ntc error */
147 dev->expire = thermo_hw_timeout(index) + timer_clock();
148 thermo_hw_off(index);
151 dev->status &= ~(THERMOERRF_NTCOPEN | THERMOERRF_NTCSHORT);
153 if ((cur_temp < dev->target - tolerance) || (cur_temp > dev->target + tolerance))
155 dev->status &= ~THERMO_TGT_REACH;
157 /* Check for timeout */
158 if (timer_clock() - dev->expire > 0)
160 dev->status |= THERMOERRF_TIMEOUT;
161 LOG_INFO("dev[%d], thermo_do: TIMEOUT\n", index);
167 dev->status &= ~THERMO_ERRMASK;
168 dev->status |= THERMO_TGT_REACH;
170 /* Reset timeout in case we go out of target in the future */
171 dev->expire = thermo_hw_timeout(index) + timer_clock();
174 if (cur_temp < dev->target)
175 dev->status = (dev->status | THERMO_HEATING) & ~THERMO_FREEZING;
177 dev->status = (dev->status & ~THERMO_HEATING) | THERMO_FREEZING;
179 thermo_hw_set(index, dev->target, cur_temp);
183 static void poll(void)
185 for (int i = 0; i < THERMO_CNT; ++i)
186 if (devs[i].status & THERMO_ACTIVE)
188 LOG_INFO("THERMO [%d] on_time[%ld],\n", i, ticks_to_ms(devs[i].on_time));
189 if ((devs[i].status & THERMO_TIMER) && (devs[i].on_time - timer_clock() < 0))
195 thermo_do((ThermoDev)i);
200 static void NORETURN thermo_poll(void)
205 timer_delay(CONFIG_THERMO_INTERVAL_MS);
210 * Thermo soft interrupt.
212 static void thermo_softint(void)
215 timer_add(&thermo_timer);
220 * Starts a thermo-regulation for channel \a dev, and turn off timer
221 * when \a on_time was elapsed.
223 void thermo_timer(ThermoDev dev, mtime_t on_time)
225 ASSERT(dev < THERMO_CNT);
226 devs[dev].on_time = timer_clock() + ms_to_ticks(on_time);
227 devs[dev].status |= THERMO_TIMER;
233 * Set the target temperature \a temperature for a specific \a dev thermo-device.
235 void thermo_setTarget(ThermoDev dev, deg_t temperature)
237 ASSERT(dev < THERMO_CNT);
238 devs[dev].target = temperature;
239 devs[dev].expire = timer_clock() + thermo_hw_timeout(dev);
241 LOG_INFO("THERMO Set Target dev[%d], T[%d.%d]\n", dev, temperature / 10, temperature % 10);
245 * Starts a thermo-regulation for channel \a dev.
247 void thermo_start(ThermoDev dev)
252 ASSERT(dev < THERMO_CNT);
254 devs[dev].status |= THERMO_ACTIVE;
255 LOG_INFO("THERMO Start dev[%d], status[%04x]\n", dev, devs[dev].status);
257 /* Initialize the hifi FIFO with a constant value (the current temperature) */
258 temp = thermo_hw_read(dev);
259 for (i = 0; i < CONFIG_THERMO_HIFI_NUM_SAMPLES; ++i)
260 devs[dev].hifi_samples[i] = temp;
261 devs[dev].cur_hifi_sample = 0;
264 devs[dev].expire = timer_clock() + thermo_hw_timeout(dev);
268 * Stops a thermo-regulation for channel \a dev.
270 void thermo_stop(ThermoDev dev)
272 ASSERT(dev < THERMO_CNT);
274 devs[dev].status &= ~THERMO_ACTIVE;
280 * Clear errors for channel \a dev.
282 void thermo_clearErrors(ThermoDev dev)
284 ASSERT(dev < THERMO_CNT);
285 devs[dev].status &= ~(THERMO_ERRMASK);
290 * Read the temperature of the thermo-device \a dev using mobile mean.
292 deg_t thermo_readTemperature(ThermoDev dev)
299 for (i = 0; i < CONFIG_THERMO_HIFI_NUM_SAMPLES; i++)
300 accum += devs[dev].hifi_samples[i];
302 return (deg_t)(accum / CONFIG_THERMO_HIFI_NUM_SAMPLES);
308 * Init thermo-control and associated hw.
310 void thermo_init(void)
314 /* Set all status to off */
315 for (int i = 0; i < THERMO_CNT; i++)
316 devs[i].status = THERMO_OFF;
321 proc_new_with_name("Thermo", thermo_poll, NULL, sizeof(thermo_poll_stack), thermo_poll_stack);
323 timer_setDelay(&thermo_timer, ms_to_ticks(CONFIG_THERMO_INTERVAL_MS));
324 timer_setSoftint(&thermo_timer, (Hook)thermo_softint, 0);
325 timer_add(&thermo_timer);