Два вечера я провёл в компании молчащего SD-модуля, потому что подключил его «по-человечески»: от карты к мастеру, от мастера к карте. MOSI модуля уехал на пин 12, MISO — на 11. В головке моей тогда жила картинка, что подписи на плате и подписи на Uno должны совпасть с разных сторон, как нумерация этажей в подъезде с двух концов дома. Не совпали: все пины SPI подписаны с одной точки зрения — точки зрения мастера. MOSI модуля обязан прийти на MOSI Uno, пин 11, и никак иначе.
Вторая ошибка той же сборки была тоньше. CS я повесил на пин 4, потому что в примере из сети стояла четвёрка. В примере был Ethernet-шилд со своей разводкой, о чём сетевой интернет не потрудился сообщить. У отдельного модуля CS — любой свободный пин, но число в SD.begin() обязано совпадать с реальным проводом. Итог: идеальная макетка, три перепрошивки и минут за десять до того, как объявить плату бракованной.
Разберём всё по местам: роли четырёх линий и кто кем командует; распиновку на Uno и Nano (и чем отличается Mega); как жить, когда на одной шине несколько устройств; и скетч-диагностику, которая называет подозреваемого по имени. В симуляторе обмен по шине изображён печатью строк cs=, mosi=, miso= — а кнопкой можно сломать шину ровно так, как её ломают перепутанные провода.
Четыре линии и кто кем командует
SPI — шина мастер-подчинённый, и на ней всегда ровно один начальник. Arduino — мастер: она генерирует такты SCK и решает, когда и с кем говорить. Карта никогда не начинает передачу сама и никогда не тактирует шину — она отвечает ровно столько тактов, сколько мастер выделил. SCK — метроном; MOSI (Master Out, Slave In) — линия данных от мастера к подчинённому; MISO (Master In, Slave Out) — обратно. Обмен полнодуплексный: в каждом такте бит уезжает в одну сторону и бит приезжает из другой.
Четвёртая линия — CS (Chip Select), он же SS (Slave Select). Низкий уровень означает «говорю с тобой», высокий — «можешь спать». Пока CS в высоком уровне, карта обязана молчать и игнорировать любые такты на SCK. Именно эта дисциплина и позволяет вешать несколько устройств на одну шину: у каждого свой CS, мастер поднимает и опускает их по очереди, а слушает в каждый момент только выбранный.
Пины на Uno и Nano одинаковые, потому что это один и тот же чип ATmega328P: MOSI — 11, MISO — 12, SCK — 13. Аппаратный SPI здесь один, и «переназначить» эти линии нельзя — только программной эмуляцией, о которой новичкам лучше вообще не думать. На Mega линии другие: 51, 50, 52. И главная тонкость Uno: пин 10 — аппаратный SS мастера. Его держат в режиме OUTPUT всегда, даже когда CS модуля сидит на другом пине, — иначе SPI-железо решает, что его заставили быть подчинённым, и мастер перестаёт тактировать шину. SD.begin() сама ставит свой CS на выход, но привычка добавить pinMode(10, OUTPUT) — дешёвая страховка. CS по умолчанию мы брали на пин 10 ещё в уроке про первый логгер.
Для сравнения: у I2C всего два провода и адреса вместо линий выбора — мы это проходили в уроке про I2C. SPI берёт другим: скоростью в мегагерцы против сотен килогерц у типовой I2C-периферии и простой логикой без адресов. Дисплею хватает I2C — как в уроке про первый текст на LCD, а карте SD нужны скорости SPI: файловая система ест байты пачками.
| Линия | Пин Uno/Nano | Пин Mega | Что бывает при ошибке |
|---|---|---|---|
| MOSI | 11 | 51 | Перепутал с MISO — SD.begin() возвращает false, в мониторе тишина |
| MISO | 12 | 50 | Обмен без ответов: карта «не слышна», begin падает при исправном железе |
| SCK | 13 | 52 | Нет тактов — обмена нет вовсе; светодиод L при обращениях не мерцает |
| CS | 10 (или любой) | 53 (или любой) | Не тот номер в SD.begin() — false на исправной карте |
| VCC / GND | 5V / GND | 5V / GND | Просадка питания — ошибки проявляются при записи |
Одна шина на всех: CS и змея в MISO
Общая шина устроена так: MOSI и SCK соединяются параллельно всем подчинённым, MISO — тоже параллельно, и вот тут спрятана змея. Выбранное устройство (CS низкий) выталкивает свои биты на MISO. Невыбранное обязано держать свой выход в высокоимпедансном состоянии — «отпустить» провод, чтобы не бороться за него с соседом. Кто умеет отпускать, а кто нет — вопрос конструкции конкретного модуля: буфер или делители, о которых был весь разговор в уроке про устройство модуля. В карточке товара об этом не пишут ни слова.
Приличные SD-модули с буфером 74LVC125A при высоком CS переводят выход в третье состояние, и MISO для шины как будто исчезает. Дешёвые модули с резисторными делителями карту не отпускают никогда: MISO остаётся подключённой постоянно. Пока SD на шине одна — никто ничего не замечает. Но поставьте рядом второе SPI-устройство, которому тоже надо отвечать мастеру, и оно начнёт говорить в провод, зажатый молчащей картой. Симптом железный: каждое устройство по отдельности работает безупречно, а вместе — враньё в данных и необъяснимые отказы.
Мой порядок действий при общей шине такой. Сначала каждое устройство запускается по отдельности со своим CS — так я знаю, что железо живо. Потом объединяю: CS каждого — на своём пине, MOSI и SCK — параллельно. Если связка молчит, первым подозреваемым делаю SD-модуль с делителями: меняю на версию с буфером. Это дешевле, чем день искать призрака.
Скетч-диагностика и модель шины
#include <SPI.h>#include <SD.h> const int CS_SD = 10; void setup() { Serial.begin(9600); pinMode(CS_SD, OUTPUT); digitalWrite(CS_SD, HIGH); // карта не выбрана, пока шину не настроили if (!SD.begin(CS_SD)) { Serial.println("begin=false. Podozrevaemye:"); Serial.println("1. MOSI na 11, MISO na 12, SCK na 13?"); Serial.println("2. CS modulya na pine 10?"); Serial.println("3. VCC na 5V, GND na GND, provoda korotkie?"); Serial.println("4. Karta FAT32 i vstavlena do shchelchka?"); while (true) { } } Serial.println("Shina zhiva, karta primontirovana");} void loop() { }Строки-подсказки идут не случайно, а по частоте причин: провода и CS ломаются чаще питания, питание чаще формата. digitalWrite(CS_SD, HIGH) до инициализации — мелочь с характером: пока шина не настроена, карту лучше держать «спящей», чтобы случайные такты на SCK не вводили её контроллер в ступор. Дальше всё делает SD.begin(): настроит скорости, выберет карту, примонтирует файловую систему — это тема следующего урока.
Про механику сборки. SPI-линии на макетке держите короче 10–15 сантиметров: инициализация стартует шину на пониженной скорости, но записи идут быстрее, и длинные провода со своей ёмкостью ловят мусор. Правила разводки питания и земли из урока про макетку действуют и здесь: длинная сигнальная линия без рядом идущей земли — антенна. А если begin=false при идеальной сборке, метод печати состояний из первого урока про Serial превращает поиск в чтение четырёх строк-подсказок выше.
- 1. Кто генерирует такты SCK на шине SPI?
- 2. MOSI модуля SD соединяется с…
- 3. Пока линия CS устройства в высоком уровне, это устройство…
- 4. Что случится, если оставить пин 10 Uno в режиме INPUT при работе SPI?
- 5. Почему дешёвый SD-модуль с резисторными делителями портит общую шину?
- Все подписи SPI — с точки зрения мастера: MOSI модуля к пину 11, MISO к 12, SCK к 13; Nano ничем не отличается от Uno, у Mega пины 51/50/52
- CS — любой свободный пин, обычно 10; номер в SD.begin() обязан совпадать с реальным проводом
- Пин 10 держите в OUTPUT даже при CS на другом пине — иначе SPI уйдёт в подчинённый режим
- На общей шине MOSI и SCK параллельны всем, но каждое устройство обязано отпускать MISO; модули с делителями этого не умеют
- Порядок диагностики: провода, CS, питание, формат — в порядке частоты причин
- Светодиод L на SCK — бесплатный индикатор обмена; SPI-провода держите короче 10–15 см
Соединение — это ещё не общение. Даже при идеальной разводке SD.begin() может вернуть false, и причин у этого полный магазин: формат карты, питание, плавающий контакт в разъёме. Следующий урок — целиком про эту строчку: что происходит внутри инициализации, почему она занимает сотни миллисекунд и как читать отказ как диагноз, а не как приговор.
Домашнее задание: нарисуйте таблицу соединений для связки SD-модуля и любого второго SPI-устройства из вашей коробки. Для каждого — свой CS на конкретном пине, общие MOSI и SCK, и пометка напротив MISO: умеет ли устройство отпускать шину. Эта бумажка за пять минут экономит вечера.
Частые вопросы по теме урока
- Кто генерирует такты SCK на шине SPI?
- SPI жёстко иерархичен: такты задаёт только мастер. Карта отвечает ровно в выделенные ей такты и никогда не начинает сама. Всегда мастер — у нас Arduino
- MOSI модуля SD соединяется с…
- Все подписи SPI — с позиции мастера: MOSI к MOSI, MISO к MISO. Мой первый тупик с «навстречу» стоил двух вечеров. пином 11: подписи читаются с точки зрения мастера
- Пока линия CS устройства в высоком уровне, это устройство…
- CS — ключ выбора: низкий уровень значит «говорю с тобой». Высокий — устройство спит и не мешает соседям. игнорирует шину и обязано молчать
- Что случится, если оставить пин 10 Uno в режиме INPUT при работе SPI?
- Пин 10 — аппаратный SS мастера. Если он в INPUT, чип решает, что его сделали подчинённым, и мастер-передатчик отключается. SPI-железо уйдёт в режим подчинённого и перестанет тактировать
- Почему дешёвый SD-модуль с резисторными делителями портит общую шину?
- Модуль с буфером отпускает MISO в высокоимпедансное состояние при высоком CS; модуль с делителями держит шину всегда. Второе SPI-устройство начинает говорить в зажатый провод. Делитель не отключает MISO карты, когда карту не выбирают