Акселерометры LIS3DH от STMicroelectronics достаточно популярны в использовании. Принципы их работы и способы подключения хорошо описаны в сети, однако мало что известно о том, каким образом подключить такой акселерометр к микроконтроллерам Nuvoton. В качестве примера была использована отладочная плата Nuvoton NuTiny-SDK-Nano130 (рисунок 1) c МК Nano130KE3BN на борту. Серия Nano130 использует ядро ARM Cortex-M0 и имеет низкое энергопотребление (ultra-low power).
Рисунок 1 - NuTiny-SDK-Nano130
Рисунок 2 - STEVAL-MKI105V1
|
Подключение. Подключить акселерометр по SPI достаточно просто. В нашем случае использовалась плата от ST с акселерометром LIS3DH – STEVAL-MKI105V1 (рисунок 2). Схема подключения представлена на рисунке 4.
Микроконтроллер Nano130 содержит три модуля SPI, которые имеют следующие характеристики:
- Работа в режиме Ведущего (Master mode) и Ведомого (Slave mode);
- Поддержка режима однобитовой и двухбитовой передачи;
- Конфигурируемая длина транзакции (от 8 до 32 бит);
- Поддерживает MSB first и LSB first последовательности передачи.
|
Для того чтобы подключиться к первому модулю SPI (SPI0), нужно найти номера контактов, соответствующие MISO, MOSI, SPICLK и SPISS. В reference manual на плату на 5 странице размещена таблица назначения контактов (рисунок 3).
Рис. 3 – Назначения контактов
Рис. 4 – Схема подключения
Инициализация SPI. Прежде всего необходимо скачать библиотеку BSP c сайта nuvoton.com, разархивировать ее и подключить к проекту. Первым делом необходимо задать источник тактирования для ядра и всей использующейся периферии:
voidSYS_Init (void)
{
/* Разблокируем защитный регистр*/
SYS_UnlockReg();
/*Выбираем в качестве источника тактирования шины HCLK внешний кварц HXT*/
CLK_SetHCLK(CLK_CLKSEL0_HCLK_S_HXT,CLK_HCLK_CLK_DIVIDER(1));
/* Включаем внешний кварц HXT 12МГц */
CLK_EnableXtalRC(CLK_PWRCTL_HXT_EN_Msk);
/* Ждем, когда кварц будет готов */
CLK_WaitClockReady (CLK_CLKSTATUS_HXT_STB_Msk);
/* Устанавливаем частоту тактирования шины HCLK 32МГц */
CLK_SetCoreClock(32000000);
/* Выбираем источник тактирования для каждого модуля периферии */
CLK_SetModuleClock(UART1_MODULE, CLK_CLKSEL1_UART_S_HXT, CLK_UART_CLK_DIVIDER(1));
CLK_SetModuleClock(SPI0_MODULE, CLK_CLKSEL2_SPI0_S_HCLK, 0);
/* Включаемсамимодули */
CLK_EnableModuleClock(UART1_MODULE);
CLK_EnableModuleClock(SPI0_MODULE);
/* Обновляемзначениетактированияядра
Необходимо обновлять всякий раз, когда меняется частота тактирования HCLK */
SystemCoreClockUpdate();
Помимо тактирования в системных регистрах настраивается альтернативные функции контактов, после чего защитный регистр можно закрывать:
/* Устанавливаем пины порта PE в альтернативную функцию UART1 RXDи TXD */
SYS->PE_H_MFP = (SYS_PE_H_MFP_PE10_MFP_UART1_TX | SYS_PE_H_MFP_PE9_MFP_UART1_RX);
/* Устанавливаем пины порта PE в альтернативную функцию SPI0 */
SYS->PE_L_MFP = (SYS_PE_L_MFP_PE4_MFP_SPI0_MOSI0 |
SYS_PE_L_MFP_PE3_MFP_SPI0_MISO0 | SYS_PE_L_MFP_PE2_MFP_SPI0_SCLK |
SYS_PE_L_MFP_PE1_MFP_SPI0_SS0);
/* Закрываем защитный регистр */
SYS_LockReg();
}
Далее необходимо настроить сам модуль SPI, следуя следующим пунктам:
- Выбор частоты тактирования модуля.
- Выбор режима работы (Master/Slave), выбор количество передаваемых/принимаемых бит.
- Выбор логического уровня в SPLCLK, когда SPI не активен (высокий/низкий уровень), выбор по какому фронту SPICLK будет производиться передача и прием.
Все вышеперечисленные пункты выполняются библиотечной функцией SPI_Open.
- Настройка режима работы вывода SPISS.
voidSPI_Init (void)
{
/* Настраиваем SPI0 как Мaster, MSBfirst, 8-bitтранзакция, SPIMode-3 тайминг, частота 1Mhz */
SPI_Open(SPI0, SPI_MASTER, SPI_MODE_3, 8, 1000000);
SPI0->SSR &= ~SPI_SSR_AUTOSS_Msk; //Отключаем автоматическое переключение SPISS
SPI0->SSR &= ~SPI_SSR_SS_LVL_Msk; //Ведомое устройство активно при низком уровне выходного сигнала SPISS
SPI0->SSR |= SPI_SSR_SS_LTRIG_Msk; //Выбор ведомого устройства по триггеру уровня
}
Пропишем удобную функции переключения SPISS:
#define CS_On() SPI0->SSR |= 0x01
#define CS_Off() SPI0->SSR &= ~(0x01)
Перед началом транзакции необходимо сначала выполнить команду CS_On (), а после окончания – обратную ей команду CS_Off ().
- Для передачи нужных данных необходимо их записать в регистр SPI_TX0. Для начала отправки нужно выставить единицу в первый бит регистра SPI_CTL – GO_BUSY. После окончания транзакции этот бит автоматически сбросится в ноль. Не используя прерывания, можно обойтись бесконечным циклом проверки бита GO_BUSY:
SPI_WRITE_TX0 (SPI0, 0xFF); //Запись в регистр SPI_TX0 значения 0xFF
SPI_TRIGGER(SPI0);//Выставляем GO_BUSY в единицу
while (SPI0->CTL & 0x01); //Ждем, когда транзакция закончится
- Принятые по SPI данные записываются в регистр SPI_RX0.
Инициализация LIS3DH. В описание на акселерометр подробно описаны все имеющиеся регистры и их назначение. Каждый регистр имеет свой адрес, он написан в скобках после названия регистра:
Рис.5 – Регистр WHO_AM_I
Например, регистр WHO_AM_I имеет адрес 0Fh. Данный регистр доступен только для чтения и хранит идентификационный номер устройства. Адрес регистра нам необходим чтобы обратиться к нему при передаче команды чтения по SPI.
Для настройки LIS3DH необходимо внимательно прочитать назначение каждого регистра. Прежде всего необходимо настроить частоту обновления данных акселерометра и включить необходимые каналы. Для этого нужно обратиться к регистру CTRL_REG1:
Рис. 6 – Регистр CTRL_REG1
Нулевой, первый и второй биты отвечают за включение соответствующего канала X, Y и Z (по умолчанию включены). Четвертый бит отвечает за включение режима пониженного потребления (по умолчанию выключен). Старшие четыре бита (ODR [3:0]) отвечают за частоту обновления данных с каналов акселерометра.
Например, чтобы выставить частоту обновления 200 Гц со всех трех каналов акселерометра, работающего в режиме пониженного потребления необходимо выполнить следующие действия:
CS_On(); //SPISSв ноль, т.е. начало передачи
SPI_WRITE_TX0 (SPI0, 0x20); //Команда: запись, Адрес регистра CTRL_REG1: 0x20
SPI_TRIGGER(SPI0);
while (SPI0->CTL & 0x01); //Ждемконцатранзакции
SPI_WRITE_TX0 (SPI0, 0x6F); //Или 0110111b, т.е. Low-power mode, X, Y, Z вкл., 200 Гц
SPI_TRIGGER(SPI0);
while (SPI0->CTL & 0x01); //Ждемконцатранзакции
CS_Off(); //SPISSв единицу, т.е. конец передачи
На этом основанная инициализация акселерометра заканчивается. LIS3DH имеет еще 6 регистров CTRL_REG, для дополнительных настроек.
Теперь, после настройки акселерометра, нужно время от времени (не более 200 раз в секунду) считывать значение регистра интересующего нас канала. Например, чтобы получить данные с канала X, необходимо считать значения с двух регистров – старшего OUT_X_H (29h) и младшего OUT_X_L (28h). Непосредственно в случае режима пониженного потребления значащим является старший регистр, так как разрешение в таком режиме снижается до 8 бит. Порядок действий следующий:
СS_On(); //SPISSв ноль, т.е. начало передачи
SPI_WRITE_TX0 (SPI0, 0xA9); //Команда – чтение, Адрес регистра OUT_X_H:0x29
SPI_TRIGGER(SPI0);
while (SPI0->CTL & 0x01); //Ожидание конца транзакции
x_axis = SPI_READ_RX0(SPI0); //В переменную x_axisзаписываем значение регистра OUT_X_H
for (i=0;i<60000;i++); //Задержка между двумя принятыми значениями
SPI_TRIGGER(SPI0); //Получаем значения вновь
while (SPI0->CTL & 0x01); //Ожидание конца транзакции
x_axis = SPI_READ_RX0(SPI0); //В переменную x_axisзаписываем значение регистра OUT_X_H
for (i=0;i<60000;i++); //Задержка между двумя принятыми значениями
SPI_TRIGGER(SPI0); //Получаем значения вновь
while (SPI0->CTL & 0x01); //Ожидание конца транзакции
CS_Off(); //SPISSв единицу, т.е. конец передачи
Данные команды можно поместить в бесконечный цикл для постоянного обновления и получения новых данных с акселерометра.
Предложенное решение найдет успешное применение в устройствах сигнализации, а также в устройствах мониторинга транспортных средств.
Бесплатная консультация
Специальные цены под проект
Хотите получить образцы?По вопросам приобретения и обсуждения проекта, а также технической информации обращаться:
Сейлз-инженер:
Григорий Котельников
+7 (343) 372-92-28 доб. 419
Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в вашем браузере должен быть включен Javascript.