Современная электроника №7/2022
ИНЖЕНЕРНЫЕ РЕШЕНИЯ 52 WWW.SOEL.RU СОВРЕМЕННАЯ ЭЛЕКТРОНИКА ◆ № 7 2022 чик которого досчитает до максималь- ного значения и обнулится по авторе- сету, т.е. через 5 минут. Сами же эти 4 NOP’а требуются для синхронизации «проснувшегося» процессора с такто- вой частотой НЧ-генератора LFOSC0 (16,4 кГц), встроенного в RTC. Фрагмент основной программы с некоторыми комментариями, свя- занный с входом/выходом в/из sleep- режима, приведён ниже. //---------------------- // Вход в sleep-режим //---------------------- SPI0CN0 &= 0xfe;//Запрет SPI. CLKSEL=0x83; //SYSCLK = частота работы RTC (LFOSC0 - 16 кГц). _nop_ (); _nop_ (); _nop_ (); _nop_ (); PMU0CF=0x84;//Установка бита sleep-режима и бита //выхода из него по alarm’у от RTC(5 минут). //------------------------ // Выход из sleep-режима //------------------------ _nop_ (); _nop_ (); _nop_ (); _nop_ (); CLKSEL=0x04; //SYSCLK = LPOSC (20 Мгц). DEL10MS(); //Задержка 10 мс. while ((CLKSEL & 0x80)==0);//Ожи- дание установки SYSCLK = LPOSC. PMU0CF=0x24;//Сброс битa sleep- режима, флага от предыдущего входа // в него и сохранение бита разрешения выхода // из sleep-режима по alarm’у от RTC. SPI0CN0 |= 0x01;//Разрешение SPI. //----------------------- При программировании чтения по SPI из BME280 автор обнаружил один неприятный «баг». Он состоит в том, что при чтении идентификационного номе- ра (ID) и калибровочных коэффициен- тов используется стандартная процедура чтения по SPI, а при чтении показаний АЦП эта процедура даёт неадекватные значения. Для объяснения этого эффек- та и снятия этого бага сделаем некото- рое отступление по поводу стандартных протоколов чтения и записи по SPI. Для того чтобы вывести байт по SPI, требуется записать его в регистр SPI0DAT, дождаться установки бита (флага) окончания передачи (SPI0CN0_ SPIF) и сбросить этот бит. Эта стандарт- ная процедура (подпрограмма записи по SPI) приведена ниже. void outspi(uint8_t byte) { SPI0DAT = byte;// Вывод байта по SPI while (!SPI0CN0_SPIF); // Ожидание окончания вывода байта SPI0CN0_SPIF = 0;// Сброс флага окончания передачи. } При чтении байта по SPI требуется записать в SPI0DAT ничего не значащий фиктивный (подставной – dummy) байт (например, 0xff), дождаться уста- новки флага SPI0CN0_SPIF и сбросить его. Результат чтения будет в регистре SPI0DAT. Подпрограмма чтения по SPI приведена ниже. uint8_t inspi() { uint8_t byte; SPI0DAT = 0xff; // Вывод фиктивного байта. while (!SPI0CN0_SPIF);// Ожидание окончания ввода байта. SPI0CN0_SPIF = 0; // Сброс флага окончания приема. byte = SPI0DAT; // Ввод байта в микроконтроллер return (byte); } Возвращаясь к прерванной последо- вательности изложения, следует пояс- нить, что сама процедура чтения из области памяти BME280 состоит в том, что вначале требуется записать байт адреса, откуда необходимо получить информацию (вышеприведённой под- программой записи), а затем – прочи- тать эту информацию (вышеприведён- ной подпрограммой чтения). Причем, если требуется прочитать несколько (2 и более) подряд расположенных байт, или, другими словами, массив байт (многократное чтение – multiple byte read), нет необходимости перед чтением каждого байта указывать его адрес. Достаточно записать адрес пер- вого элемента массива и далее просто читать подряд столько раз, сколько элементов в массиве. Другими слова- ми, перед чтением каждого следующе- го байта происходит автоматическое инкрементирование адреса. Например, для чтения первого двух- байтного калибровочного коэффи- циента температуры (в справочном листке он обозначен как dig_T1), распо- ложенного по адресам 0x88 (старший байт) и 0x89 (младший байт), необхо- димо вначале записать адрес старшего байта (0x88), а затем произвести дву- кратное чтение. В этом случае такая процедура чтения работает правиль- но, и к ней никаких претензий нет. Иное дело, если требуется прочитать показания АЦП. Эти показания для дав- ления (ADC_P), температуры (ADC_T) и влажности (ADC_H) расположены в памяти BME280 также подряд, начиная с адреса 0xF7 (старший байт показания давления – press_msb). Причем каждое показание АЦП расположено в 3 бай- тах. Например, показание ADC_P рас- положено по адресам 0xF7 (старший байт), 0xF8 (средний байт – press_lsb) и 0xF9 (младший байт – press_xlsb). Далее идёт показание ADC_T, а за ним – ADC_H. Таким образом, все три пока- зания занимают 3 × 3 = 9 байт. Если тре- буется прочитать подряд все 9 байт, то, применив вышеприведённую проце- дуру многократного чтения, вначале следует записать в BME280 адрес пер- вого элемента этого массива, т.е. 0xF7, а затем осуществить 9-кратное чтение. Однако в этом случае получится пол- ная белиберда. В чём же здесь дело? Как выяснил автор, при записи адреса 0xF7 вышеприведённой подпрограм- мой записи байта и последующего чтения байта вышеприведённой под- программой чтения будет произведе- на операция чтения не с адреса 0xF7, а со следующего (0xF8). Другими слова- ми, после записи адреса 0xF7 (см. под- программу записи) в регистр SPI0DAT сразу же запишется содержимое 0xF7, а при последующем чтении после запи- си фиктивного байта (см. подпрограм- му чтения) в SPI0DAT запишется содер- жимое уже следующего байта (0xF8), т.е. после записи адреса происходит его автоматическое инкрементирование, и, таким образом, содержимое регистра с адресом 0xF7 теряется. Решение этой проблемы, а также раз- водка печатных плат, корпус устрой- ства и результаты тестирования ито- гового изделия будут рассмотрены в следующей части статьи. Литература 1. Кузьминов А.Ю. Связь между компьюте- ром и микроконтроллером. Современ- ные аппаратные и программные сред- ства. М.: Перо, 2018. 2. Кузьминов А. Программирование микро- контроллеров EFM8 с помощью встро- енного загрузчика программ // Радио. 2018. № 12.
RkJQdWJsaXNoZXIy MTQ4NjUy