Управление lis302dl через spi

Цифровой акселерометр LIS302DL

В этой статье я постораюсь поделится опытом работы с цифровым акселерометром от ST Microelectronics.

Такой датчик позволяет получать данные о своем ускорении. В отличии от аналоговых датчиков, где для чтения нужен АЦП, здесь необходимо лишь настроить сенсор на нужный режим работы и считать готовую инфу. Чтение происходит посредством либо SPI, либо I2C интерфейса, на выбор. Получив данные, микроконтроллер может использовать их как угодно.

Мне доводилось работать с 2-мя датчиками семейства — lis202dl и lis302dl . Отличаются они только количеством осей, поэтому далее буду говорить о 3-х осевом.

Основные фичи:
Программируемый предел измерения. Можно выбрать 2 фиксированных значения: 2G/8G. Нужно выставлять в зависимости от применения. Если поставить 2G, то можно точнее измерять не очень большие ускорения и наоборот для 8G.

Внутренний программный фильтр. Мега полезная вещь. Меняет характер выдаваемых данных с относительного на абсолютный и наоборот. Поясню на примере: при выключенном фильтре сенсор будет постоянно «чувствовать» притяжение земли и если его ось Z будет направлена перпендикулярно земле, то по ней мы будем постоянно иметь максимальные значение ускорения. А если включить фильтр и оставить датчик в покое, то пока мы не приложим к нему ускорение, на всех осях будет 0.

2 программируемых выхода прерываний. Если не нужно постоянно получать точное значение ускорения, а лишь превышение какого-либо порога, то можно задать этот самый порог и ждать изменения на соответствующей ноге.

Основной и сильно заметный (для начинающего) минус датчика — размер. Он очень маленький. Корпус (LGA14) совершенно не паябельный, но это только на первый взгляд. Я паял его по методу уважаемого DI HALT’а из его статьи о аналоговом акселерометре MMA7260Q . Нарисовал footprint с направляющими уголками. Нанес припоя на дорожки, обильно смазал флюсом, отцентрировал по уголкам, и касаясь дорожек паяльником запаял датчик. Если кто-то захочет повторить, то footprint’ы для Sprint Layout 5 и DipTrace можно найти в конце статьи.
Если же вы не уверены в твердости рук или просто не хотите парится, то можно найти готовые платки переходники, где все уже запаяно до нас. Также есть отладочные платы и от самих ST в том числе.

Схемы подключения на примере Tiny2313:
I2C — не забываем подтяжку обоих линий до VCC. Чтобы чип понял что мы хотим пообщаться с ним по 2-м проводам, нужно седьмую ногу (CS) подтянуть к VCC. Нога SDO в этом режиме служит для задания I2C адреса датчика: если её притянуть к VCC, то датчик отзовется на адрес 0b0011101, если к земле (как в примере) — на 0b0011100.

SPI — вывод CS (Chip Select) можно подключать к любой ноге МК, аппаратный интерфейс его не контролирует и приходится дергать его программно.

На обоих схемах подключены выводы прерываний (INT1, INT2 — восьмая и девятая ноги). Это необязательно, их нужно подключать по необходимости.

Датчик питается напряжением от 2,16 до 3,6 В. Если у МК тоже низкое напряжения питания (в моем случае он с индексом «V», то есть с пониженным VCC), то оптимально питать их от одного источника, например в 3,3 В. Если же у МК VCC = 5В, то варианта 2: либо согласовывать I/O линии по уровням, либо забить и не согласовывать. В одном из девайсов я так и поступил, все работало, но так делать не стоит. Я вас предупредил:)

Что касается программы, то используются аппаратная реализация интерфейса (USI). В прилагаемом архиве лежит проект на СИ для AVR STUDIO. МК — Tiny2313. Подключение к датчику по SPI. Программа читает регистр «WHO I AM» и шлет данные о ускорении по оси X через USART.

STM Урок 41. Подключаем акселерометр LIS3DSH. Часть 1

Урок 41

Подключаем акселерометр LIS3DSH

Тема нашего сегодняшнего занятия – подключение более нового акселерометра по сравнению с тем, который мы использовали для изучения в уроке 39. Данный акселерометр – это также акселерометр, выполненный с использованием технологии MEMS – LIS3DSH .

Во-первых, данный акселерометр наряду с интерфейсом I2C может подключиться и с использованием интерфейса SPI, что делает более надёжной передачу данных и их использование. Во-вторых, данный акселерометр установлен на плате STM32F4 Discovery, с которой мы уже очень продолжительное время работаем, и она уже стала как родная. И это я считаю немаловажной мотивацией. Ну а в-третьих, имеет более совершенные технические характеристики:

Диапазон показаний ±2g/±4g/±6g/±8g/±16g;

Чувствительность 0.06-0.73 mg/digit;

Отклонение от нуля ±60 mg.

Ну а с остальными характеристиками, тонкостями, регистрами и другими подводными камнями акселерометра мы познакомимся в ходе его программирования.

Проект для Cube MX мы создадим из одного из прошлых проектов USB_OTG_CDC, так как вместо USART для передачи показаний акселерометра на ПК мы попробуем воспользоваться USB CDC Device, так как с ним работать более удобно ввиду необязательности использования каких-то промежуточных переходников. Назовем проект ACCEL407.

Запустим проект в Cube MX, отключим I2C, включим SPI1 в режим Full-Duplex Master

Ножки SPI оставим по умолчанию и никуда не перенаправляем

Включим еще 3 ножки. Одну для выбора чипа (CS), другие две для обнаружения прерываний. Возможно последние нам не понадобятся, но для порядка включим, чтобы по ошибки их не задействовать впоследствии на что-то еще.

Также включим на выход лапки портов для управления разноцветными светодиодами на плате

В настройках SPI изменим только скорость передачи

Также изменим настройки в GPIO у лапки порта PE3, выставив ему скорость Medium.

Зайдем в Project -> Settings и изменим там значения стека и кучи, чтобы USB-устройство после установки драйвера нам не давало ошибку (Код 10).

Сгенерируем проект и откроем его в Keil 5. Также по традиции настроим программатор на авторезет. Соберем проект.

Уберем всё, что касается символьного дисплея, так как он нам, скорее всего не потребуется. Уберем подключение библиотеки из main.h:

Здесь оставим только передачу в USB, чтобы проверить, работает ли она.

/* USER CODE BEGIN 2 */

/* USER CODE END 2 */

В бесконечном цикле также оставим только то, что касается передачи в USB

/* USER CODE END WHILE */

Прошьем контроллер, чтобы убедиться в работоспособности порта USB и удалим теперь всю передачу, массив строки и подготовку строки:

/* USER CODE END PV */

/* USER CODE BEGIN 2 */

/* USER CODE END 2 */

/* USER CODE END WHILE */

/* USER CODE END 1 */

Также из файла usbd_cdc_if.c удалим следующие строки, а одну строку раскомментируем обратно:

/* USER CODE BEGIN PRIVATE_VARIABLES */

extern char str_rx[21];

/* USER CODE END PRIVATE_VARIABLES */

static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len)

/* USER CODE BEGIN 6 */

Читайте также  Блок питания радиоприёмника из электронного балласта лдс

/* USER CODE END 6 */

Пересоберём на всякий случай проект, чтобы убедиться, что ошибок у нас нет.

Два файла для работы с акселерометром можно использовать с прошлого занятия, переименовав их подобающим образом, подключив к проекту и внеся некоторые изменения.

Названия, соответственно, изменятся на lis3dsh.h и lis3dsh.c. Заодно удалим из Inc и Src файлы lcd.h и lcd.c. Подключим данные файлы, добавив lis3dsh.c в проекте в группу Application/User, а lis3dsh.h подключив в main.h. Также внесем макроподстановки, наподобие тех, которые мы вносили в проекте под 3 discovery для удобного управления светодиодами.

#define LD_PORT GPIOD

#define LD3 GPIO_PIN_13 //ORANGE

#define LD4 GPIO_PIN_12 //GREEN

#define LD5 GPIO_PIN_14 //RED

#define LD6 GPIO_PIN_15 //BLUE

#define LD3_ON HAL_GPIO_WritePin(LD_PORT, LD3, GPIO_PIN_SET) //ORANGE

#define LD4_ON HAL_GPIO_WritePin(LD_PORT, LD4, GPIO_PIN_SET) //GREEN

#define LD5_ON HAL_GPIO_WritePin(LD_PORT, LD5, GPIO_PIN_SET) //RED

#define LD6_ON HAL_GPIO_WritePin(LD_PORT, LD6, GPIO_PIN_SET) //BLUE

#define LD3_OFF HAL_GPIO_WritePin(LD_PORT, LD3, GPIO_PIN_RESET) //ORANGE

#define LD4_OFF HAL_GPIO_WritePin(LD_PORT, LD4, GPIO_PIN_RESET) //GREEN

#define LD5_OFF HAL_GPIO_WritePin(LD_PORT, LD5, GPIO_PIN_RESET) //RED

#define LD6_OFF HAL_GPIO_WritePin(LD_PORT, LD6, GPIO_PIN_RESET) //BLUE

Состав данных файлов после внесения изменений.

Содержимое файла lis3dsh.h:

#define LD_PORT GPIOD

#define LD3 GPIO_PIN_13 //ORANGE

#define LD4 GPIO_PIN_12 //GREEN

#define LD5 GPIO_PIN_14 //RED

#define LD6 GPIO_PIN_15 //BLUE

#define LD3_ON HAL_GPIO_WritePin(LD_PORT, LD3, GPIO_PIN_SET) //ORANGE

#define LD4_ON HAL_GPIO_WritePin(LD_PORT, LD4, GPIO_PIN_SET) //GREEN

#define LD5_ON HAL_GPIO_WritePin(LD_PORT, LD5, GPIO_PIN_SET) //RED

#define LD6_ON HAL_GPIO_WritePin(LD_PORT, LD6, GPIO_PIN_SET) //BLUE

#define LD3_OFF HAL_GPIO_WritePin(LD_PORT, LD3, GPIO_PIN_RESET) //ORANGE

#define LD4_OFF HAL_GPIO_WritePin(LD_PORT, LD4, GPIO_PIN_RESET) //GREEN

#define LD5_OFF HAL_GPIO_WritePin(LD_PORT, LD5, GPIO_PIN_RESET) //RED

#define LD6_OFF HAL_GPIO_WritePin(LD_PORT, LD6, GPIO_PIN_RESET) //BLUE

Содержимое файла lis3dsh.c:

static void Error (void)

uint8_t Accel_IO_Read(uint16_t DeviceAddr, uint8_t RegisterAddr)

void Accel_IO_Write(uint16_t DeviceAddr, uint8_t RegisterAddr, uint8_t Value)

uint8_t ctrl = 0x00;

void Accel_AccFilterConfig(uint8_t FilterStruct)

void AccInit(uint16_t InitStruct)

void Accel_GetXYZ(int16_t* pData)

Вызовем инициализацию датчика в main();

/* USER CODE BEGIN 2 */

/* USER CODE END 2 */

В функции-обработчике ошибки включим красный светодиод

static void Error (void)

Добавим хэндл нашего SPI:

extern SPI_HandleTypeDef hspi1;

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

Миландр

Текущее время: 2021-июл-30 01:23

Часовой пояс: UTC+03:00

вопрос по SPI

здравствуйте Уважаемые разработчики

столкнулся с непонятной проблемой при использовании связки из контроллеров 1986ВЕ1Т и 1986ВЕ9х связанных по SPI
помимо этого используется DMA и УАПП на 1986ВЕ1Т все передачи осуществляются через ДМА
причем если мы берем 2 контроллера 1986ВЕ9х, то у нас нет никаких проблем с передачей,
а при использовании разных контроллеров после определенного количества 16битных слов сообщение выдаваемое 1986ВЕ1Т начинает искажаться следующим образом:
последнее слово в посылке перемещается на 1 место в посылку остальное выдается по порядку;
для подтверждения прикрепляю пример, в примере использовались: 1986ВЕ1Т в керамическом корпусе ревизия 3, 1986ВЕ9х ревизия 3 корпус пластиковый,
а также картинки с осциллографа и съёмка памяти кейла.
итак система должна работать следующим образом: с 1986ВЕ9х приходит чипселект и клок на 1986ВЕ1Т, а 1986ВЕ1Т работает 4 каналами ДМА (2 выдает 2 принимает) и выдает не то что требуется и не то что записано у него в памяти, причем до 4 байт он выдает нормально, а после начинаются глюки;
такое ощущение что где-то не успевает до передать и отправляет следующей посылкой.
в общем что я делаю не так или какие есть рекомендации по исправлению этого глюка?

да точно. на снимках: желтая и синяя линии выдачи 1986ВЕ1Т(ssp1, ssp2), красная клок, зеленая чипселект

rubygoblin писал(а):

здравствуйте Уважаемые разработчики

столкнулся с непонятной проблемой при использовании связки из контроллеров 1986ВЕ1Т и 1986ВЕ9х связанных по SPI
помимо этого используется DMA и УАПП на 1986ВЕ1Т все передачи осуществляются через ДМА
причем если мы берем 2 контроллера 1986ВЕ9х, то у нас нет никаких проблем с передачей,
а при использовании разных контроллеров после определенного количества 16битных слов сообщение выдаваемое 1986ВЕ1Т начинает искажаться следующим образом:
последнее слово в посылке перемещается на 1 место в посылку остальное выдается по порядку;
для подтверждения прикрепляю пример, в примере использовались: 1986ВЕ1Т в керамическом корпусе ревизия 3, 1986ВЕ9х ревизия 3 корпус пластиковый,
а также картинки с осциллографа и съёмка памяти кейла.
итак система должна работать следующим образом: с 1986ВЕ9х приходит чипселект и клок на 1986ВЕ1Т, а 1986ВЕ1Т работает 4 каналами ДМА (2 выдает 2 принимает) и выдает не то что требуется и не то что записано у него в памяти, причем до 4 байт он выдает нормально, а после начинаются глюки;
такое ощущение что где-то не успевает до передать и отправляет следующей посылкой.
в общем что я делаю не так или какие есть рекомендации по исправлению этого глюка?

да точно. на снимках: желтая и синяя линии выдачи 1986ВЕ1Т(ssp1, ssp2), красная клок, зеленая чипселект

ну . это не совсем решение проблемы, да и второй в конечной системе не требуется, в основном 1986ВЕ1Т и идет на замену 1986ВЕ9х из-за наличия аппаратного ARINC
поэтому используются разные МК.
может дело в том, что они не могут быть состыкованы по SPI?
или у них связка ДМА-SPI работают по разному?
если так то по каким правилам идет перетасовка в сообщении и на какой длине сообщения она начинается?
и сколько таких «переломов» существует, по которым меняются правила выдачи сообщений?

второго к сожалению у меня нету, но я думаю что проблема сохранится потому как с 1986ВЕ9х на 1986ВЕ1Т идет 2 провода: это чипселект и клок больше они ничем, кроме питания, не связаны; выдает в воздух и принимает воздух, ну с приёмом кстати тоже глюки если, но я их пока не отслеживал, сначала с выдачей разберусь, потому как принимаю «эхо»

rubygoblin писал(а):
rubygoblin писал(а):

Последний раз редактировалось rubygoblin 2015-янв-28 14:31, всего редактировалось 1 раз.

rubygoblin писал(а):

менял это значение зависит от SIZE_SPI1_AND_SPI2 изменяя это значение изменяется SIZE_DMA_SPI1_TX_MASSIVE поэтому точно менял. пробовал передавать 4 и 8 байтов в различных режимах 8, 16, 32 ошибка в первых двух случаях последний выдаваемый байт переезжает на первое место а в третьем сообщение набивается в начале и в конце недостоверными данными

ну тогда еще можно попробовать выровнять посылку до 4 и отключить единичные передачи так? не помогло.

Последний раз редактировалось rubygoblin 2015-янв-28 15:04, всего редактировалось 1 раз.

rubygoblin писал(а):

менял это значение зависит от SIZE_SPI1_AND_SPI2 изменяя это значение изменяется SIZE_DMA_SPI1_TX_MASSIVE поэтому точно менял. пробовал передавать 4 и 8 байтов в различных режимах 8, 16, 32 ошибка в первых двух случаях последний выдаваемый байт переезжает на первое место а в третьем сообщение набивается в начале и в конце недостоверными данными

ну тогда еще можно попробовать выровнять посылку до 4 и отключить единичные передачи так?

Читайте также  Tft дисплей 3.2 с открытым исходным кодом

вот еще такая штука. я когда 1 раз столкнулся с этой проблемой подумал, тактовой частоты недостаточно для выдачи и 1 слово остается в фифо и при следующей передаче выдается как 1 . в связи с этим добавил тактовой частоты на 1 слово итог слово перестало переноситься в начало и выдавалось в положенном месте, но все посылка сдвигалась на 1 слово в право и 1 словом становилось всегда 1 и тоже слово или 0x5555 или 0xAAAA это позволяло с учетом сдвинутого слова передавать 24 байта на 32 байтах посылка теряла стабильность и начинала постоянно переключаться добавление тактовой частоты ни к чему не приводило больше

и я так понял Вы считаете что проблема в ДМА? ну последние адреса я просчитывал и писал на них определенные значения. размер массива тоже считал в памяти запись значений по этим адресам тоже говорила что все правильно ну и количество передач учтено в макросе (итоговое значение = значение — 1) адреса источников и назначений в виртуальных структурах совпадает с тем что записано в программе. очень интересно получается. 9х и 1Т имеют одинаковое описание на ДМА(ну кроме того что 1Тработает с областью 0x20100000) на 9х все стабильно передается и принимается, а на 1Т возникают необъяснимые ошибки. непонятно.

STM32F4Discovery + Modbus RTU/ASCII + MEMS LIS302DL

1. Предварительная подготовка

В этой заметке предполагается, что читатель в качестве среды разработки использует Eclipse. Подробнее можно узнать по ссылке.

После первичной подготовки проекта и, в частности, развёртывания библиотеки Standard Peripherals Library, необходимо скачать и установить исходные тексты библиотеки FreeMODBUS. Несмотря на то, что в списках для загрузки фигурируют версии библиотеки вплоть до 1.5, на главной странице проекта в правом верхнем углу последнее упоминание касается библиотеки версии 1.3, поэтому именно эту версию и возьмём за основу для портирования.

После загрузки необходимо распаковать библиотеку в подкаталог проекта lib. Портирование протокола Modbus TCP выходит за рамки данной заметки, поэтому можно сразу же удалить подкаталог lib/freemodbus/modbus/tcp. За основу-шаблон для портирования возьмём AVR-порт из каталога demo/AVR/port, который скопируем в lib/freemodbus. Итоговая структура проекта в Eclipse принимает вид:

Добавим пути до всех имеющих отношение к проекту заголовочных файлов Project -> Properties -> C/C++ General -> Paths and Symbols -> вкладка Includes:

Аналогичным образом на вкладке Source Location пропишем в проекте файлы с исходными текстами:

2. Портирование

2.1. Настройка mbconfig.h

В файле lib/freemodbus/modbus/include/mbconfig.h находим строки:

и изменяем их на:

2.2. Изменения в port.h

Открываем lib/freemodbus/port/port.h и в разделе «Platform includes» добавляем:

Далее находим строчки с макроопределениями ENTER_CRITICAL_SECTION и EXIT_CRITICAL_SECTION и определяем их следующим образом:

2.3. Изменения в porttimer.c

Для измерения различных временных промежутков в рамках работы Modbus протокола, не нарушая общности, условимся использовать Таймер 2. Его необходимо настроить таким образом, чтобы он формировал прерывания с периодом, равным 50 мкс * N, где N — целое положительное число, указанное пользователем.

Шаг 1. Открываем файл lib/freemodbus/port/porttimer.c

Шаг 2. В разделе «Platform includes» открытого файла добавляем:

Шаг 3. Переопределяем функцию xMBPortTimersInit:

Шаг 4. Переопределяем функцию vMBPortTimersEnable:

Шаг 5. Переопределяем функцию vMBPortTimersDisable:

Шаг 6. Добавляем обработчик прерываний Таймера 2:

2.4. Изменения в portserial.c

В качестве приёмо-передающего устройства, опять же не нарушая общности, выберем USART2.

Шаг 1. Открываем файл lib/freemodbus/port/portserial.c

Шаг 2. Переопределяем функцию xMBPortSerialInit, отвечающей за инициализацию USART2:

Шаг 3. Переопределение функции vMBPortSerialEnable, отвечающей за разрешение/запрет прерываний от модуля USART2:

Шаг 4. Переопределение обработчика прерываний USART2:

Шаг 5. Переопределение функции xMBPortSerialPutByte, предназначенной для отправки 1 байта данных в USART2:

Шаг 6. Переопределение функции xMBPortSerialGetByte, предназначенной для приёма 1 байта данных из USART2:

3. Тестирование

3.1. Подготовка

Для запуска успешного обмена информацией через протокол Modbus RTU/ASCII нам необходимо переопределить следующие функции:

имеющие соответственно следующие назначения:

  • чтение значений из нескольких регистров ввода (0x04 Read Input Registers)
  • чтение значений из нескольких регистров хранения (0x03 Read Holding Registers)
  • чтение значений из нескольких регистров флагов (0x01 Read Coil Status)
  • чтение значений из нескольких дискретных входов (0x02 Read Discrete Inputs)

Переопределим функцию eMBRegHoldingCB таким образом, чтобы в зависимости от содержимого регистров хранения включался или выключался один из установленных на плате STM32F4Discovery светодиодов.

Шаг 1. Сделаем необходимые подключения в main.c:

Шаг 2. Библиотека FreeModbus не резервирует память под регистры ввода/хранения/флагов/дискретных входов, т.е. подразумевается ручное/самостоятельное управление ОЗУ. Поэтому выделим память для 4 регистров хранения, начиная с адреса 40001, в файле main.c следующим образом:

Шаг 3. Собственно реализация функции eMBRegHoldingCB:

Шаг 4. Для оставшихся функций добавим соответствующие заглушки:

Шаг 5. Установленные на плате STM32F4Discovery светодиоды подключены к ногам PD12, PD13, PD14 и PD15 микроконтроллера таким образом, что включаются при помощи лог.»1″, а выключаются при помощи лог.»0″. Функция инициализации ног I/O выглядит следующим образом:

Шаг 6. Добавим функцию, выполняющую привязку каждого из четырёх регистров хранения к каждому из четырёх установленных светодиодов:

Из кода видно, что каждый из светодиодов будет гореть только в том случае, если значение соответствующего регистра хранения будет отличным от нуля.

Шаг 7. Файл main.c приобретает следующий вид:

3.2. Запуск

В качестве ПО Modbus master выберем Modbus Poll, имеющий 30-дневный бесплатный тестовый период. Ключевым аргументом в пользу выбора данного ПО стала его одновременная поддержка Modbus/RTU и Modbus/ASCII. Чего, к сожалению, не скажешь об open-source решениях типа QModbus или QModMaster.

Настройки Modbus Poll включают:

Setup -> Read/Write Definition

Connection -> Connect -> кнопка Advanced

В итоге после начала сбора данных Вы должны увидеть окно, похожее на:

4. Пойдём ещё дальше

На отладочной плате STM32F4Discovery, как известно, установлен 3-осевой акселерометр LIS302DL. В составе STM32F4DISCOVERY board firmware package поставляется всё необходимое ПО для инициализации и обмена данными с акселерометром. В частности, нас интересуют файлы:

  • stsw-stm32068/STM32F4-Discovery_FW_V1.1.0/Utilities/STM32F4-Discovery/stm32f4_discovery_lis302dl.h
  • stsw-stm32068/STM32F4-Discovery_FW_V1.1.0/Utilities/STM32F4-Discovery/stm32f4_discovery_lis302dl.c
  • stsw-stm32068/STM32F4-Discovery_FW_V1.1.0/Utilities/STM32F4-Discovery/stm32f4_discovery.h

Скопируем их во вновь созданный подкаталог проекта src/mems. Структура проекта после этого преобразуется к виду:

4.1. Добавление кода для MEMS

Шаг 1. Добавляем описание для четырёх регистров ввода протокола Modbus:

Шаг 2. Добавляем подключение в main.c:

Шаг 3. Добавляем объявление необходимых глобальных переменных в main.c:

Шаг 4. Добавляем функции, реализующие задержку и циклический опрос MEMS-акселерометра:

Шаг 5. Добавляем код инициализации акселерометра LIS302DL:

Шаг 6. Переопределяем метод eMBRegInputCB:

Шаг 7. Добавляем вызов lis302dl_init() в начале функции main, собираем проект и перепрошиваем плату.

4.2. Тестирование

После настроек Modbus Poll, аналогичных предыдущим, и запуска обмена данными окно программы должно стать похожим на:

Самодиагностика МЕМС акселерометра, гироскопа и компаса (self test)

Изучая спецификацию (datasheet) на МЕМС-датчик (акселерометр, гироскоп и проч.) мы сталкиваемся с такой процедурой, как самопроверка (self-test) или самодиагностика. Обычно в спецификациях есть описание, как это делать. Кому интересно: что это и как это правильно делать? — добро пожаловать под кат.

Введение

Самопроверка позволяет определить, что данные с датчика показывают то, что должны показывать. Датчики не всегда имели режим самодиагностики. Чтобы определить соответствие измеряемых данных тому, что указано в спецификации, разработчик должен был проверять это специальными экспериментами. В случае акселерометра — совершать наклоны на определённые углы и снимать изменение показаний. Анализируя результаты, можно было оценить погрешность, выдаваемую датчиком. Если показатели не соответствовали спецификации, датчик признавался бракованным.

Читайте также  Измеритель ёмкости аккумуляторов (с линейным стабилизатором)

Это усложняло массовое производство и во все датчики стали включать процедуру самодиагностики. Замысел процедуры достаточно прост — создать условия, при которых мы будем знать, что должен показывать датчик, и сравнить с тем, что он показывает. Отклонения выше заданных забраковывают датчик. Для компасов делают элемент, создающий магнитное поле (прямо в корпусе датчика). Включение режима самодиагностики включает этот элемент — эталонный источник. Для акселерометра и гироскопа элемент генерирует электростатическое поле, которое отклоняет грузик (см. фото ниже) и имитирует физическое движение или вращение. Величина смещения известна, соответственно известна величина, которую должен показать датчик. Если погрешность снятых показаний в заявленных пределах — значит с датчиком всё в порядке и он работает в соответствии со спецификацией.


(статья из интернет-журнала, откуда я позаимствовал картинку содержит ещё много красивых увеличенных фоток, ссылки см. внизу)

1. Влияние на самопроверку внешних сил

Рассмотрим акселерометр. Как указано ранее, в режиме самодиагностики на микромеханический грузик воздействует электростатическая сила, отклоняющая его на определённое расстояние, и имитирующая тем самым ускорение. Однако ожидаемую величину на выходе датчика мы не увидим. Дело в том, что в спокойном состоянии на грузик действуют другие силы (напр. сила тяжести). Они дополнительно отклоняют грузик.

Для того, чтобы учесть внешние силы, в процедуре самопроверки снимаются показания датчика в обычном режиме. Затем включается источник отклонения (переход в режим «самопроверка») и снова снимаются показания датчика.

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

aвнутр. ист. = aST — aнорм
MIN 2 . Значит возможный разбег величины самопроверки = ±0,0784 м/с 2 . Здесь тоже нужно быть внимательным, т. к. иногда уровень шума указывают с включенным фильтром. Это значит, что замеры нужно делать с теми же настройками фильтра.

В одном положении получились такие результаты:

Затем плату с датчиком положил на бок и получил такие результаты:

Разбег значений получился 11, 2 и 5 g * 10 -3 . Если провести ещё несколько испытаний, то можно уточнить диапазон для конкретно этого датчика:
380 Пример кода самопроверки LIS302DL

В одном положении получились такие результаты:

В другом положении такие результаты:

Разбег значений получился в районе 1 единицы. А это второй режим работы внутреннего источника, когда он тянет в другую сторону (Self-test M):

Здесь мы видим показания другого датчика («Self-test P»):

И второй режим с поворотом платы («Self-test M»):

Согласно спецификации, он не проходит самопроверку — значения по оси Z выступают за заявленный предел: максимум 32, а мы имеем 35.

В одном положении получились такие результаты:

В другом положении:

В этом датчике успешность прохождения самопроверки определяется допустимым отклонением от эталонного значения. Допуск отклонения равен ±3% (стр. 9 первой части спецификации). Т. е. этот датчик в порядке.

Browse the source code of linux/drivers/misc/lis3lv02d/lis3lv02d_spi.c

Warning: That file was not part of the compilation database. It may have many parsing errors.

1 /*
2 * lis3lv02d_spi — SPI glue layer for lis3lv02d
3 *
4 * Copyright (c) 2009 Daniel Mack
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * publishhed by the Free Software Foundation.
9 */
10
11 #include
12 #include
13 #include
14 #include
15 #include
16 #include
17 #include
18 #include
19 #include
20 #include
21 #include
22
23 #include «lis3lv02d.h»
24
25 #define «lis3lv02d_spi»
26 #define 0x80
27
28 static int (struct lis3lv02d *, int , u8 *)
29 <
30 struct spi_device * = lis3->bus_priv;
31 int = spi_w8r8(spi, reg | LIS3_SPI_READ);
32 if (ret 0 )
33 return -EINVAL;
34
35 *v = (u8) ret;
36 return 0 ;
37 >
38
39 static int (struct lis3lv02d *, int , u8 )
40 <
41 u8 [ 2 ] = < reg, val >;
42 struct spi_device * = lis3->bus_priv;
43 return spi_write(spi, tmp, sizeof(tmp));
44 >
45
46 static int (struct lis3lv02d *)
47 <
48 u8 ;
49 int ;
50
51 /* power up the device */
52 ret = lis3->read(lis3, CTRL_REG1, &reg);
53 if (ret 0 )
54 return ret;
55
56 reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
57 return lis3->write(lis3, CTRL_REG1, reg);
58 >
59
60 static union axis_conversion =
61 < .as_array = < 1 , 2 , 3 >>;
62
63 # ifdef CONFIG_OF
64 static const struct of_device_id [] = <
65 < .compatible = "st,lis302dl-spi" >,
66 <>
67 >;
68 MODULE_DEVICE_TABLE(of, lis302dl_spi_dt_ids);
69 # endif
70
71 static int (struct spi_device *)
72 <
73 int ;
74
75 spi->bits_per_word = 8 ;
76 spi->mode = SPI_MODE_0;
77 ret = spi_setup(spi);
78 if (ret 0 )
79 return ret;
80
81 lis3_dev.bus_priv = spi;
82 lis3_dev.init = lis3_spi_init;
83 lis3_dev.read = lis3_spi_read;
84 lis3_dev.write = lis3_spi_write;
85 lis3_dev.irq = spi->irq;
86 lis3_dev.ac = lis3lv02d_axis_normal;
87 lis3_dev.pdata = spi->dev.platform_data;
88
89 # ifdef CONFIG_OF
90 if (of_match_device(lis302dl_spi_dt_ids, &spi->dev)) <
91 lis3_dev.of_node = spi->dev.of_node;
92 ret = lis3lv02d_init_dt(&lis3_dev);
93 if (ret)
94 return ret;
95 >
96 # endif
97 spi_set_drvdata(spi, &lis3_dev);
98
99 return lis3lv02d_init_device(&lis3_dev);
100 >
101
102 static int (struct spi_device *)
103 <
104 struct lis3lv02d * = spi_get_drvdata(spi);
105 lis3lv02d_joystick_disable(lis3);
106 lis3lv02d_poweroff(lis3);
107
108 return lis3lv02d_remove_fs(&lis3_dev);
109 >
110
111 # ifdef CONFIG_PM_SLEEP
112 static int (struct device *)
113 <
114 struct spi_device * = to_spi_device(dev);
115 struct lis3lv02d * = spi_get_drvdata(spi);
116
117 if (!lis3->pdata || !lis3->pdata->wakeup_flags)
118 lis3lv02d_poweroff(&lis3_dev);
119
120 return 0 ;
121 >
122
123 static int (struct device *)
124 <
125 struct spi_device * = to_spi_device(dev);
126 struct lis3lv02d * = spi_get_drvdata(spi);
127
128 if (!lis3->pdata || !lis3->pdata->wakeup_flags)
129 lis3lv02d_poweron(lis3);
130
131 return 0 ;
132 >
133 # endif
134
135 static SIMPLE_DEV_PM_OPS(, lis3lv02d_spi_suspend,
136 lis3lv02d_spi_resume);
137
138 static struct spi_driver = <
139 .driver = <
140 .name = DRV_NAME,
141 .pm = &lis3lv02d_spi_pm,
142 .of_match_table = of_match_ptr(lis302dl_spi_dt_ids),
143 >,
144 .probe = lis302dl_spi_probe,
145 .remove = lis302dl_spi_remove,
146 >;
147
148 module_spi_driver(lis302dl_spi_driver);
149
150 MODULE_AUTHOR( «Daniel Mack » );
151 MODULE_DESCRIPTION( «lis3lv02d SPI glue layer» );
152 MODULE_LICENSE( «GPL» );
153 MODULE_ALIAS( «spi:» DRV_NAME);
154

Warning: That file was not part of the compilation database. It may have many parsing errors.

Generated on 2019-Mar-29 from project linux revision v5.1-rc2
Powered by Code Browser 2.1
Generator usage only permitted with license.