Ник:
Пароль:

Контакты

E-mail: info@starterkit.ru
тел.: +7 922 680-21-73
тел.: +7 922 680-21-74
Телеграм: t.me/starterkit_ru
Партнеры:
otladka.com.ua - г.Киев

Способы оплаты

User Info


Добро пожаловать,
Guest

Регистрация или входРегистрация или вход
Потеряли пароль?Потеряли пароль?

Ник:
Пароль:

ПользователейПользователей:2
Поисковых ботовПоисковых ботов:2
ГостейГостей:1

ОбновитьПодробнееВсегоВсего:5
Форум » starterkit.ru » Отладочные платы » SK-iMX233
Драйвер LRADC - датчик температуры на внешнем диоде
Pavel Ivanchenko
Добавлено 08.09.2010 09:12 Редактировалось 08.09.2010 09:13
0
Сообщение: 1
Pavel Ivanchenko
Admin
4.39

Пункты: 91532
Регистрация: 24.03.2009
Пол: Мужчина
sasamy пишет:
Цитата
Чудесный форум не дает создавать новые сообщения :) напишу в старой теме, касается lradc - написал небольшой драйвер для измерения температуры при помощи простого диода 1n4148. Как известно сопротивление p-n перехода в прямом направлении прямо пропорционально температуре а у i.mx233 на физических каналах 0 и 1 есть встроенные программируемые источники тока, в даташите есть формула по которой можно посчитать температуру, исходя из нее и сделано все. Драйер для hwmon так что будет виден как датчик в lm-sensors. Точность невелика, поэтому усреднил большое количесво выборок - 64 (8 значений напряжения для каждого из 8 значений температуры которые устредняются), разброс значений получается порядка 2 град. Диод подключается на разъем Х6: 11 - анод , 1 - катод. Нужно будет калибровать для каждого конкретного случа, например у меня показывает больше чем реальная темепература градусов на 6-7.

Код

/*
* i.mx233 external temperature sensing with a diode
*
* 2010 Alexander Kudjashev
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/


#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/sysfs.h>
#include <linux/hwmon.h>
#include <linux/mutex.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <asm/processor.h> /* cpu_relax */
#include <mach/hardware.h>
#include <mach/lradc.h>
#include <mach/regs-power.h>
#include <mach/regs-lradc.h>

#define REGS_LRADC_BASE IO_ADDRESS(LRADC_PHYS_ADDR)
#define TERM_CHANNEL 0
#define LRADC_IRQ_MASK (1 << TERM_CHANNEL)
#define KELVIN_TO_CELSIUS_CONST (273*1000)

struct mxsterm {
struct device *hwmon_dev;
struct mutex lock;
};

static uint32_t get_codevalue(void)
{
int i;
uint32_t codevalue;

codevalue = 0;

for (i = 0; i < 8; i++) {
__raw_writel(BF_LRADC_CTRL0_SCHEDULE(1 << TERM_CHANNEL),
REGS_LRADC_BASE + HW_LRADC_CTRL0_SET);

/* Wait for conversion complete*/
while (!(__raw_readl(REGS_LRADC_BASE + HW_LRADC_CTRL1)
& LRADC_IRQ_MASK))
cpu_relax();

/* Clear the interrupt flag */
__raw_writel(LRADC_IRQ_MASK,
REGS_LRADC_BASE + HW_LRADC_CTRL1_CLR);

/* read temperature value and clr lradc */
codevalue += __raw_readl(REGS_LRADC_BASE +
HW_LRADC_CHn(TERM_CHANNEL)) & BM_LRADC_CHn_VALUE;

__raw_writel(BM_LRADC_CHn_VALUE,
REGS_LRADC_BASE + HW_LRADC_CHn_CLR(TERM_CHANNEL));
}

return (codevalue >> 3);
}

/*
* Use the the lradc0 channel
*
*/
static int measure_temperature(void)
{
int code1, code2, ret_temp, i;

/* Enable temperature sensor current source */
__raw_writel(BM_LRADC_CTRL2_TEMP_SENSOR_IENABLE0,
REGS_LRADC_BASE + HW_LRADC_CTRL2_SET);

/* mux to the lradc 0th temp channe0 */
__raw_writel((0xF << (4 * TERM_CHANNEL)),
REGS_LRADC_BASE + HW_LRADC_CTRL4_CLR);

/* Clear the interrupt flag */
__raw_writel(LRADC_IRQ_MASK,
REGS_LRADC_BASE + HW_LRADC_CTRL1_CLR);

ret_temp = 0;

for (i = 0; i < 8; i++) {
__raw_writel(BM_LRADC_CTRL2_TEMP_ISRC0,
REGS_LRADC_BASE + HW_LRADC_CTRL2_CLR);

__raw_writel(BF_LRADC_CTRL2_TEMP_ISRC0(BV_LRADC_CTRL2_TEMP_ISRC0__300),
REGS_LRADC_BASE + HW_LRADC_CTRL2_SET);

code1 = get_codevalue();

__raw_writel(BM_LRADC_CTRL2_TEMP_ISRC0,
REGS_LRADC_BASE + HW_LRADC_CTRL2_CLR);

__raw_writel(BF_LRADC_CTRL2_TEMP_ISRC0(BV_LRADC_CTRL2_TEMP_ISRC0__20),
REGS_LRADC_BASE + HW_LRADC_CTRL2_SET);

code2 = get_codevalue();

/* degrees Kelvin = (Codemax – Codemin) * 1.104 */
ret_temp += (code1 - code2) * 1104;
}

/* Disable temperature sensor current source */
__raw_writel(BM_LRADC_CTRL2_TEMP_SENSOR_IENABLE0,
REGS_LRADC_BASE + HW_LRADC_CTRL2_CLR);

return ((ret_temp >> 3) - KELVIN_TO_CELSIUS_CONST);
}

static ssize_t mxsterm_sense_temp(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mxsterm *mxsterm_data = dev_get_drvdata(dev);
int status;
int val;

if (mutex_lock_interruptible(&mxsterm_data->lock))
return -ERESTARTSYS;

val = measure_temperature();
status = sprintf(buf, "%d\n", val);

mutex_unlock(&mxsterm_data->lock);
return status;
}

static DEVICE_ATTR(temp1_input, S_IRUGO, mxsterm_sense_temp, NULL);

static ssize_t mxsterm_show_name(struct device *dev, struct device_attribute
*devattr, char *buf)
{

return sprintf(buf, "%s\n", "mxsterm");
}

static DEVICE_ATTR(name, S_IRUGO, mxsterm_show_name, NULL);

static int __init mxsterm_probe(struct platform_device *pdev)
{
struct mxsterm *mxsterm_data;
int status;

mxsterm_data = kzalloc(sizeof *mxsterm_data, GFP_KERNEL);
if (!mxsterm_data)
return -ENOMEM;

mutex_init(&mxsterm_data->lock);

/* sysfs hook */
mxsterm_data->hwmon_dev = hwmon_device_register(&pdev->dev);
if (IS_ERR(mxsterm_data->hwmon_dev)) {
dev_dbg(&pdev->dev, "hwmon_device_register failed.\n");
status = PTR_ERR(mxsterm_data->hwmon_dev);
goto out_dev_reg_failed;
}
platform_set_drvdata(pdev, mxsterm_data);

if ((status = device_create_file(&pdev->dev, &dev_attr_temp1_input))
|| (status = device_create_file(&pdev->dev, &dev_attr_name))) {
dev_dbg(&pdev->dev, "device_create_file failure.\n");
goto out_dev_create_file_failed;
}

return 0;

out_dev_create_file_failed:
device_remove_file(&pdev->dev, &dev_attr_temp1_input);
hwmon_device_unregister(mxsterm_data->hwmon_dev);
out_dev_reg_failed:
platform_set_drvdata(pdev, NULL);
kfree(mxsterm_data);

return status;
}

static int mxsterm_remove(struct platform_device *pdev)
{
struct mxsterm *mxsterm_data = platform_get_drvdata(pdev);

hwmon_device_unregister(mxsterm_data->hwmon_dev);
device_remove_file(&pdev->dev, &dev_attr_temp1_input);
device_remove_file(&pdev->dev, &dev_attr_name);
platform_set_drvdata(pdev, NULL);
kfree(mxsterm_data);

return 0;
}

static struct platform_driver mxsterm_driver = {
.driver = {
.name = "mxsterm",
},
.probe = mxsterm_probe,
.remove = mxsterm_remove,
};

static struct platform_device *mxsterm_device;

static int __init mxsterm_init(void)
{
int ret = 0;

ret = platform_driver_register(&mxsterm_driver);

if (!ret) {
mxsterm_device = platform_device_alloc("mxsterm", 0);

if (mxsterm_device)
ret = platform_device_add(mxsterm_device);
else
ret = -ENOMEM;

if (ret) {
platform_device_put(mxsterm_device);
platform_driver_unregister(&mxsterm_driver);
}
}

return ret;
}

static void __exit mxsterm_exit(void)
{
platform_device_unregister(mxsterm_device);
platform_driver_unregister(&mxsterm_driver);
}

module_init(mxsterm_init);
module_exit(mxsterm_exit);


MODULE_AUTHOR("Alexander Kudjashev");
MODULE_DESCRIPTION("External temperature sensing with a diode");
MODULE_LICENSE("GPL");
Спуститься к концу Подняться к началу
Персональная информация
snacker
Добавлено 13.09.2010 10:18 Сообщение: 2
snacker
0

Пункты: 300
Регистрация: 09.01.2010
Пол: Мужчина
Павел, я новичок в программировании под Линукс. Не подскажете, как я могу использовать ваш драйвер в своем приложении?
Я пишу свой код с функцией main, в которой мне, к примеру, нужно узнать температуру, что я должен сделать? Какие заголовочные файлы включать? И ваш драйвер в каком виде должен быть - отдельно компилиться или его нужно будет включать в проект?
Спуститься к концу Подняться к началу
Персональная информация
Pavel Ivanchenko
Добавлено 13.09.2010 10:56 Сообщение: 3
Pavel Ivanchenko
Admin
4.39

Пункты: 91532
Регистрация: 24.03.2009
Пол: Мужчина
Я не являюсь автором драйвера (скажем спасибо sasamy).
Включите его в ядро, по аналогии - положите в соответствующую папку с драйверами, добавте его сборку в makefile и добавте его активацию в konfig, далее через menuconfig включите его в ядро и пересоберите систему.
Как его в собственном приложении использовать, вариантов много можно придумать:
"Правильный"
Посмотреть как lm-sensors опрашивает и пересчитывает датчики и сдеоать по аналогии.
"Чайниковый №1"
Запустить из своей апликухи lm-sensors, вывод которой перенаправить в файл, потом вычленить температуру из лога.
...
Спуститься к концу Подняться к началу
Персональная информация
snacker
Добавлено 13.09.2010 11:32 Сообщение: 4
snacker
0

Пункты: 300
Регистрация: 09.01.2010
Пол: Мужчина
Я так понимаю, что если я пойду по первому пути - напишу код по аналогии, то мне не надо будет ничего включать в ядро.
Спуститься к концу Подняться к началу
Персональная информация
Pavel Ivanchenko
Добавлено 13.09.2010 11:57 Сообщение: 5
Pavel Ivanchenko
Admin
4.39

Пункты: 91532
Регистрация: 24.03.2009
Пол: Мужчина
В любом случае нужно будет включить драйвер в ядро (lm-sensors от драйвера данные берет).
Спуститься к концу Подняться к началу
Персональная информация
Jury093
Добавлено 13.09.2010 12:20 Сообщение: 6
Jury093
4.5

Пункты: 54233
Регистрация: 25.05.2009
Пол: Мужчина
Из: Санкт-Петербург
Цитата
Я так понимаю, что если я пойду по первому пути - напишу код по аналогии, то мне не надо будет ничего включать в ядро.

В данном случае драйвер - это некая прокладка между железом (датчиком, диодом) и стандартными программами, которые знать не знают о таком железе и черпают информацию через драйвер.

Если в своей программе вы подмените на свои функции драйвера Александра - настройку GPIO, работу с необходимой периферией АРМа, опрос датчика. То да, можно драйвер не собирать.
В этом случае вы получите жесткую связку из железа и своей проги без возможности использовать сторонние утилиты..

На любой вопрос есть любой ответ.
Спуститься к концу Подняться к началу
Персональная информация
sasamy
Добавлено 13.09.2010 14:22 Редактировалось 13.09.2010 14:23 Сообщение: 7
sasamy
4.70

Пункты: 77333
Регистрация: 14.08.2009
Цитата

Я пишу свой код с функцией main, в которой мне, к примеру, нужно узнать температуру, что я должен сделать?


Если конкретно для этого датчика - доcтаточно прочитать через sysfs известный файл. В общем случае lm-sensors сканирует налчие датчиков - по какому принципу я не интересовался. Для этого драйвера например в командной строке (значение будет в миллиградусах)
Код

#cat /sys/class/hwmon/hwmon0/device/temp1_input


Или из своей программы

Код

#include <stdio.h>

int main(void)
{
FILE *f;
int val;

f = fopen("/sys/class/hwmon/hwmon0/device/temp1_input", "r");
if (f == NULL) {
fprintf (stderr, "Cannot open file\n");
return 1;
}

if (EOF != fscanf(f, "%d", &val))
printf ("the approximated value %d C\n", val / 1000);
else
printf ("read error\n");

return 0;
}
Спуститься к концу Подняться к началу
Персональная информация
snacker
Добавлено 13.09.2010 15:37 Сообщение: 8
snacker
0

Пункты: 300
Регистрация: 09.01.2010
Пол: Мужчина
Цитата
Если в своей программе вы подмените на свои функции драйвера Александра - настройку GPIO, работу с необходимой периферией АРМа, опрос датчика. То да, можно драйвер не собирать.

Jury093, я так и подумал.

sasamy, спасибо.
Спуститься к концу Подняться к началу
Персональная информация
sasamy
Добавлено 13.09.2010 17:46 Сообщение: 9
sasamy
4.70

Пункты: 77333
Регистрация: 14.08.2009
Цитата
Я так понимаю, что если я пойду по первому пути - напишу код по аналогии, то мне не надо будет ничего включать в ядро.


А завтра понадобится более точное измерение температуры - поставите туда датчик например с i2c интерфейсом и будете весь код переписывать, тогда как используя lm-sensors нужно будет поменять пару строк в программе, или захочется на другом микроконтроллере сделать. OC предоставляет уровень абстракции над "железом" - используя его абсолютно неважно как подключен и даже на какой архитектуре все сделано.
Спуститься к концу Подняться к началу
Персональная информация
Jury093
Добавлено 13.09.2010 22:19 Сообщение: 10
Jury093
4.5

Пункты: 54233
Регистрация: 25.05.2009
Пол: Мужчина
Из: Санкт-Петербург
Цитата
OC предоставляет уровень абстракции над "железом" - используя его абсолютно неважно как подключен и даже на какой архитектуре все сделано.

Ja-ja, их бин натюрлих, Саш, ты прав на все 100. Я использовал слегка другие слова
Код
В этом случае вы получите жесткую связку из железа и своей проги без возможности использовать сторонние утилиты..

Но вопрошавшему может нет нужды ковырять линух/ядро, а есть желание написать что-то простейшее под свои нужды.

Не помню, писал тут или нет - спасибо тебе что разрабатываешь и выкладываешь исходники - есть чему у тебя поучиться..

На любой вопрос есть любой ответ.
Спуститься к концу Подняться к началу
Персональная информация
Форум » starterkit.ru » Отладочные платы » SK-iMX233