SPI.begin не работает после tristate

Я работаю над проектом сверхнизкой мощности, используя ATMEGA328P, nRF24L01 и суперконденсатор 0.47 F для измерения различных датчиков, похожих на проект солнечной энергии Gammon. У меня были проблемы с поддержанием низкого потребления тока nRF24L01, что, как отмечалось здесь, является общей проблемой. Мне удалось снизить ток во время сна только до 950uA, а не до 7uA. Питание nRF24L01 поступает от AMS1117, который включается и выключается с цифрового контакта. Таким образом, во время сна nRF24L01 не потребляет энергию напрямую, поэтому ток должен поступать от SPI. Согласно коду Гаммона, после отправки радиосообщения он устанавливает контакты SPI в качестве ВЫХОДНЫХ и НИЗКИХ после SPI.end(), например:

bool ok = radio.write (&reading, sizeof reading);
radio.startListening ();
radio.powerDown ();
SPI.end ();
// установите контакты в положение OUTPUT и LOW
for (byte i = 9; i <= 13; i++)
    {
    pinMode (i, OUTPUT);    
    digitalWrite (i, LOW); 
    }  // конец цикла for

Поскольку потребление тока исходит от SPI, я решил обратить это вспять, установив контакты SPI на ВХОД, предполагая, что SPI.begin() автоматически вернет их соответствующим образом. В этот момент ток во время сна был ожидаемым 7uA, но никаких сообщений не отправлялось. Я проверил и обнаружил, что существует проблема, когда SPI.end() заставляет SPI.transfer() зависать даже после нового SPI.begin(). К сожалению, в моем случае это решение не сработало.

Я попытался изменить контакты на выходные, когда выходил из сна, но это, очевидно, не сработало. В одном из постов указывалось, что контакты не должны быть настроены как выходные данные перед вызовом SPI.begin (), потому что SPIClass::begin() не имеет кода для этого, и что это, вероятно, сделано по какой-то причине. Действительно, в коде Гаммона, где он устанавливает все контакты на ВЫХОД и НИЗКИЙ уровень во время настройки, чтобы минимизировать потребление тока, он пропускает контакты SPI:

  // установите контакты в положение OUTPUT и LOW
  for (byte i = 0; i <= A5; i++)
    {
    // пропустить радиоприемники
    if (i >= 9 && i <= 13)
      continue;
    pinMode (i, OUTPUT);    
    digitalWrite (i, LOW);  
    }  // конец цикла for  

Чего я не понимаю, так это почему можно установить контакты SPI в качестве ВЫВОДА после SPI.end() и не делать то же самое после выхода из сна и непосредственно перед SPI.begin()? Кроме того, почему, если я тристирую контакты после SPI.end (), шина SPI, похоже, не работает, то есть SPI.begin (), кажется, зависает?

, 👍2

Обсуждение

Интересная проблема. Откуда вы знаете, что "он висит"? Теме форума, на которую вы ссылаетесь, почти 10 лет, и эта точная проблема уже исправлена., @Sim Son

Ты прав. Я не уверен, что он "висит". Но, по-видимому, проблема не была устранена, потому что, просто используя SPI.end (), ток все еще течет по шине SPI., @jhorv


1 ответ


2

Наконец-то я нашел здесь ответ. Точная проблема близка к тому, что я думал: PIN MOSI не установлен низко после SPI.end(). Решение состоит не в том, чтобы установить контакт в качестве ВХОДНОГО, как я сначала подумал, а в том, чтобы установить низкий контакт MOSI, сначала добавив

SPCR &= 0B10111111;

перед тем как перевести систему в спящий режим (который отключает SPI), а затем добавить эту строку

SPCR |= 0B01000000;

после выхода из сна для того,чтобы снова включить SPI.

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

,