nabbla (nabbla1) wrote,
nabbla
nabbla1

Мучаем 5576ХС4Т - часть 'h39 - приказываю: спи! (по SPI)

[Оглавление (ссылки на остальные части)]Часть 0 - покупаем, паяем, ставим драйвера и софт
Часть 1 - что это вообще за зверь?
Часть 2 - наша первая схема!
Часть 3 - кнопочки и лампочки
Часть 4 - делитель частоты
Часть 5 - подавление дребезга кнопки
Часть 6 - заканчиваем кнопочки и лампочки
Часть 7 - счетчики и жаба
Часть 8 - передатчик UART
Часть 9 - Hello, wolf!
Часть 'hA - приёмник UART
Часть 'hB - UART и жаба
Часть 'hC - полудуплексный UART.
Часть 'hD - МКО (МКИО, Mil-Std 1553) для бедных, введение.
Часть 'hE - приёмопередатчик МКО "из подручных материалов" (в процессе)
Часть 'hF - модуль передатчика МКО
Часть 'h10 - передатчик сообщений МКО
Часть 'h20 - работа с АЦП ADC124s051
Часть 'h21 - преобразование двоичного кода в двоично-десятичный (BCD)
Часть 'h22 - Bin2Bcd с последовательной выдачей данных
Часть 'h23 - перемножитель беззнаковых чисел с округлением
Часть 'h24 - перемножитель беззнаковых чисел, реализация
Часть 'h25 - передаём показания АЦП на компьютер
Часть 'h26 - работа над ошибками (быстрый UART)
Часть 'h27 - PNG и коды коррекции ошибок CRC32
Часть 'h28 - передатчик изображения PNG
Часть 'h29 - принимаем с ПЛИС изображение PNG
Часть 'h2A - ZLIB и коды коррекции ошибок Adler32
Часть 'h2B - ускоряем Adler32
Часть 'h2C - формирователь потока Zlib
Часть 'h2D - передаём сгенерированное PNG-изображение
Часть 'h2E - делим отрезок на равные части
Часть 'h2F - знаковые умножители, тысячи их!
Часть 'h30 - вычислитель множества Мандельброта
Часть 'h31 - ускоренные сумматоры
Часть 'h32 - ускоренные счётчики (делаем часы)
Часть 'h33 - ускоряем ВСЁ
Часть 'h34 - ускоренные перемножители
Часть 'h35 - умножители совсем просто
Часть 'h36 - уравновешенный четверичный умножитель
Часть 'h37 - ускоренные счётчики, работа над ошибками
Часть 'h38 - передатчик байтов SPI
Часть 'h39 - приказываю: спи! (по SPI)


Отдельные байты мы отправлять по SPI научились, теперь надо соединить их в сообщения, даже скорее цепочку сообщений. Под сообщением мы имеем в виду последовательность байт, во время которой nCS (negative Chip Select) непрерывно остаётся нулевым. Затем он примерно на 1 такт SCK становится единичным, затем снова нулевым - и мы передаём следующее сообщение.

Но сначала мы опишем, какие именно сообщения мы хотим отправить на многострадальный Ethernet-контроллер ENC624J600, и как они будут представлены в памяти, именно их отправку мы и понаблюдаем сначала на симуляции, а потом - "в железе".


В datasheet на наш ethernet-контроллер приводится последовательность действий, чтобы перевести его в режим максимально малого энергопотребления (раздел 16.1: General power-down, страница 139):

1. выключаем модуль возведения в степень по модулю и AES, сбросив бит CRYPTEN (EIR<15>). Можно не делать, поскольку "по умолчанию" модуль криптографии и так отключён.

2. выключаем приём пакетов, сбросив бит RXEN (ECON1<0>). Можно не делать, поскольку "по умолчанию" приём пакетов отключён - приёмопередатчик включён, но всё, что он принял - "никуда не идёт"

3. ждём, пока не будут обработаны все оставшиеся пакеты, а именно дожидаемся, пока бит RXBUSY (ESTAT<13>) станет нулевым. Можно не делать, поскольку приём пакетов и так был отключён

4. ждём, пока окончатся все текущие передачи, а именно дожидаемся, пока бит TXRTS (ECON1<1>) станет нулевым. Можно не делать, так как мы не инициировали никаких передач

5. выключаем приёмопередатчик (PHY), установив бит PSLEEP (PHCON1<11>). Это как раз самое важное - по умолчанию приёмопередатчик включён, чтобы поскорее определить скорость соединения, начать мигать лампочками и пр., и потребляет он около 50 мА

6. выключаем модуль Ethernet (он управляет приёмопередатчиком и криптографией), сбрасывая биты ETHEN и STRCH (ECON2<15,14>). Тоже надо сделать - потребление снижается заметно!


Мы сделаем только последние 2 пункта, причём вместе с битами ETHEN и STRCH мы можем сразу же "пощупать" и биты COCON<3:0> (ECON2<11:8>), которые как раз управляют делителем частоты. (Clock Out CONfiguration, Ethernet CONfiguration).

Правда, для этого придётся ещё немного "покурить мануалы". Сначала изучаем, как организована память (раздел 3, стр. 19). Они чего-то перемудрили с памятью, введя 3 практически независимых блока:
- SFR area (Special Function Registers) с адресами от 00h до 9Fh - только она доступна напрямую через SPI. Здесь лежит прорва регистров конфигурации всего и вся. Мы можем использовать команду WCR (Write Control Register) и WCRU (Write Control Register Unbanked), чтобы записать отдельные байты, а также BFS (Bit Field Set), BFC (Bit Field Clear), BFSU (Bit Field Set Unbanked) и BFCU (Bit Field Clear Unbanked), чтобы оперировать отдельными битами, не трогая остальных. Эта область к тому же поделена на 4 "сектора" (Banks), и мы можем либо обращаться к нужным байтам непосредственно (указывая полный адрес), либо сначала выбрать сектор, а затем работать внутри него, что позволяет укоротить команду, уместив её код и начальный адрес в 1 байт вместо 2.

- Main area, в которую входит буфер SRAM (адреса 0000h до 5FFFh) и память для модуля криптографии (адреса 7800h до 7C4Fh). До буфера SRAM через SPI можно "достучаться", отдельными командами, а именно мы задаём указатель для записи и для чтения, и затем при каждом обращении будем передавать/получать один байт, а соответствующий указатель будет смещаться на единичку. Интересно было бы задействовать эту память, всё-таки её 24 килобайта - это вдвое больше, чем "на борту" самой ПЛИС. Но поскольку кроме SPI у нас ничего нет, а максимально допустимая частота SPI - 14 МГц, мы в лучшем случае сможем обращаться к этой памяти на скорости 1,75 Мбайт/с, причём в "полудуплексном режиме" - либо чтение, либо запись. Как-нибудь позже...

- PHY Register area - самый "закопанный" участок. Эта память разбита на 16-битные слова, коих содержится ровно 32 штуки (адреса 00h .. 1Fh). Обращаться к ней можно только через некий MIIM - интерфейс (Media Independent Interface Management).

Итак, разберёмся, как установить бит PSLEEP (PHCON1<11>) в единицу. Он лежит как раз-таки в PHY Register area. Как нам пишут в разделе 3.3.2, записать можно только 16 бит целиком, запись отдельного байта или, тем более бита - не поддерживается. Методика такова:

1. Заносим в регистр MIREGADR адрес того регистра из PHY Register area, в который хотим произвести запись. А именно, мы должны записать нулевой адрес (PHCON1 как раз лежит в памяти самый первый). Сам регистр MIREGADR находится в SFR area, т.е запись в него мы осуществляем командой WCRU. Его адрес - 54h (младший байт) и 55h (старший байт). Все 5 бит адреса лежат в старшем байте, но нас просят также "ещё разок" занести зарезервированное значение 01h в старший байт.

2. Записываем требуемое 16-битное значение в регистр MIWR, адрес 66h (младший байт), 67h (старший байт). Первым надо заполнить младший байт, затем старший. Когда мы запишем значение в старший байт MIWR, начнётся запись этого значения в PHY Register area по заданному нами адресу.

3. Как только запись в регистр началась, устанавливается бит BUSY (MISTAT<0>). Операция может занять 25,6 мкс. Пока она не завершилась, нельзя обращаться к регистрам MIISCAN, MIWR и MIRD. Также, как показал мой опыт, нельзя выключать интерфейс Ethernet (наш следующий пункт), поскольку он отключится мгновенно, так и не передав приёмопередатчику команду "впасть в спячку". Как результат, энергопотребление почти не снизится.

Для исполнения первого пункта нам нужно передать по SPI следующие байты:
22 54 00 01

22 - код команды WCRU (Write Control Register Unbanked), 54 - адрес регистра MIREGADR, 00 01 - значения младшего и старшего байта, соответственно. (00 - тот самый нулевой адрес, 01 - некое "зарезервированное значение", которое нас просят использовать).

Для исполнения второго пункта нам нужно передать по SPI следующие байты:
22 66 00 18

22 - код команды WCRU, 66 - адрес регистра MIWR, 00 18 - то значение, которое мы хотим занести в регистр PHCON1. Все 8 бит младшего байта - зарезервированы, там должны стоять нули, что мы и делаем. Старший байт по умолчанию инициализируется значением 10, а мы туда добавляем единичный бит PSLEEP, что превращает 10 в 18.

Последний пункт мы решим "по рабоче-крестьянски": будем общаться по SPI на такой скорости, чтобы к окончанию передачи команды на выключение Ethernet уже успело бы пройти 25,6 мкс. Команда на выключение Ethernet (и настройку тактовой частоты) займёт 3 байта, т.е 24 бита, ещё по кр. мере по 1 биту придётся на начало и конец посылки (там должны выдерживаться паузы), что даёт суммарно 26 бит. Т.е мы должны "тратить" 1 мкс на передачу каждого бита, что соответствует частоте 1 МГц. Мы никуда не торопимся - почему бы и нет :)


И приведём команду на выключение Ethernet и установку 33 МГц:
22 6F 01

Как всегда, 22 - код команды WCRU, 6F - адрес регистра ECON2 (старший байт), 01 - значение, которое мы заносим. Старшие два бита обнуляются, чтобы отключить Ethernet и погасить светодиоды на разъёме (правда, они и так не подключены!), младшие 4 бита управляют делителем частоты. Код 0001 как раз означает 33,33 МГц - максимальная частота, которую мы можем здесь задать.

Внутри ПЛИС мы собираемся применить небольшую блок ROM (он на самом деле RAM, просто входы для записи не подключены), в котором будет сидеть следующая последовательность:
04 22 54 00 01 04 22 66 00 18 03 22 6F 01 00


Первое число показывает, сколько байт содержит очередная команда: 4. Затем идут эти 4 байта - они передаются "одним куском". Затем снова идёт количество байт: 4. И ещё 4 байта - следующая команда, на запись в регистр MIWR (и в конечном итоге в PHCON1). Наконец, число 3 говорит - следующая команда занимает 3 байта, идут эти 3 байта, и под конец 0, увидев который, передатчик сообщений должен остановиться.

всего 15 байт, хватит 4-разрядной адресации :) А можно и вовсе реализовать его на 7 ЛЭ:
module ETH_SPI_shutdown (input clk, input [3:0] Addr, output reg [7:0] Q = 1'b0);
  always @(posedge clk)
    Q <= (Addr == 'h0)? 8'h04 :
         (Addr == 'h1)? 8'h22 :
         (Addr == 'h2)? 8'h54 :
         (Addr == 'h3)? 8'h00 :
         (Addr == 'h4)? 8'h01 :
         (Addr == 'h5)? 8'h04 :
         (Addr == 'h6)? 8'h22 :
         (Addr == 'h7)? 8'h66 :
         (Addr == 'h8)? 8'h00 :
         (Addr == 'h9)? 8'h18 :
         (Addr == 'hA)? 8'h03 :
         (Addr == 'hB)? 8'h22 :
         (Addr == 'hC)? 8'h6F :
         (Addr == 'hD)? 8'h01 :
         (Addr == 'hE)? 8'h00 :
                        8'hxx;
endmodule


(старший бит, как оказывается, всегда нулевой, поэтому для него отдельный ЛЭ не нужен!)

Осталось за малым - написать этот самый передатчик...
Tags: ПЛИС, работа, странные девайсы
Subscribe

  • Калифорния спятила

    Купил тут ключ для снятия бонок велосипеда (хитрых гаек, скрепляющих передние звёзды): Весь из себя фирменный, других в магазине не было. Но я…

  • Про интерференционный светофильтр

    В данном приборчике, видеоизмерителе параметров сближения, хочется максимально отгородиться от паразитной засветки, проще говоря от Солнца. Для…

  • Королёвские котики и тепловоз

    Акынский пост - "что вижу, о том пою!" Кот-консьерж ушёл в отпуск: в кои-то веки можно не стоять у входа на проходную, а лежать на солнышке!…

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 0 comments