Данный урок посвящен последовательному интерфейсу — SPI. Интерфейс позволяет передавать информацию между несколькими устройствами, не обязательно микроконтроллерами. Особенность заключается в том, что имеется одно ведущее устройство и одно или несколько ведомых. Так же интерфейс используется многими программаторами для прошивки микроконтроллеров.
SPI достаточно прост в использовании, рассмотрим пример, в котором используется один ведущий (master — босс :D) и два ведомых микроконтроллера (slave — работяги).
SCK — Тактовый сигнал. Используется для синхронизации данных.
MOSI — передатчик ведущего, приемник ведомого
MISO — приемник ведущего, передатчик ведомого
SS — выбор ведомого
Для того, чтобы ведомый 0 принимал команды, нужно на его вход SS подать логический 0. Тогда он будет знать, что общение идет именно с ним, ведомый 1 будет все игнорировать. Аналогично, чтобы «активировать» ведомого 1, нужно подать на его вход SS логический 0, а на вход SS ведомого 0 — логическую единицу. В таком случае слушать команды будет только ведомый 1.
В отличие от предыдущих уроков, здесь придется создать 2 прошивки. Задача ведущего: активировать ведомого 0, послать команду мигнуть светодиодом, переключиться на 1, снова послать команду мигнуть светодиодом, повторить. Задача ведомых принять команду и мигать светодиодом. Получится одна прошивка для ведущего, вторая для двух ведомых. Создаем проект, на закладке SPI для master настройки слева, для slave справа. Не забудьте поставить галочку SPI Interrupt у slave.
Прошивка для ведущего будет выглядеть так:
#include <mega8.h> #include <spi.h> #include <delay.h> void main(void) { // Input/Output Ports initialization // Port B initialization // Func7=In Func6=In Func5=Out Func4=In Func3=Out Func2=Out Func1=Out Func0=Out // State7=T State6=T State5=0 State4=T State3=0 State2=0 State1=1 State0=0 PORTB=0x02; DDRB=0x2F; PORTC=0x03; DDRC=0x00; // SPI initialization // SPI Type: Master // SPI Clock Rate: 125,000 kHz // SPI Clock Phase: Cycle Half // SPI Clock Polarity: Low // SPI Data Order: MSB First SPCR=0x52; SPSR=0x00; while (1) { PORTB.2=0; //Переключаемся на ведомого 0 spi('1'); //Отсылаем ему 1, чтобы он включил светодиод delay_ms(100); //ждем spi('0'); //Отсылаем ему 0, чтобы он выключил светодиод delay_ms(100); //ждем PORTB.2=1; //Делаем ведомого 0 не активным PORTB.1=0; //Переключаемся на ведомого 1, далее по аналогии с 0 spi('1'); delay_ms(100); spi('0'); delay_ms(100); PORTB.1=1; }; } |
Для ведомых прошивка будет выглядеть так:
#include <mega8.h> interrupt [SPI_STC] void spi_isr(void) { unsigned char data; data=SPDR; //читаем приходящие байты if(data=='1') //если пришла 1, включить светодиод { PORTD=0xFF; } if(data=='0') //если пришел 0, выключить светодиод { PORTD=0x00; } } void main(void) { PORTB=0x00; DDRB=0x10; PORTD=0x00; DDRD=0xFF; // SPI initialization // SPI Type: Slave // SPI Clock Rate: 125,000 kHz // SPI Clock Phase: Cycle Half // SPI Clock Polarity: Low // SPI Data Order: MSB First SPCR=0xC2; SPSR=0x00; // Clear the SPI interrupt flag #asm in r30,spsr in r30,spdr #endasm // Global enable interrupts #asm("sei") while (1) { }; } |
Обратите внимание, что прием происходит в прерывании, т.е. в основном цикле мы можем делать, что угодно, а как только информация придет по SPI, автоматически начнет исполняться код в прерывании.
В результате микроконтроллеры будут весело перемигиваться. Прошивки и файл протеуса тут
Идут 0 и 1 и идут они таким образом первая пачка допустим у вас 2 байта в двоичном коде указывает принимающему контроллеру сколько будет передано информации тоже в 1 и 0 и приняв эту переменную он в битах получит её.
Можно увеличить количество контактов, будет больше передавать битов одновременно пачкой.
сейчас на стмках уже это есть аппаратное quadspi 🙂
Что-то я не понял…почему все в каких-то кавычках?передавать можно только символы что-ли?
Не стесняемся читаем http://avr-start.ru/?p=4557
Скажите пожалуйста как обращаться к памяти flash AVR если память больше 128кб,к примеру 256кб атмега2560.
Ведь адрес обозначается как 16 бит,значит можно указать 0xffff число а это 65535 байт или
64кб,Значит мы можем обратиться к 64кб младших байт и 64 кб старших байт всего 128 кб.
а как к обращаться ко второй половине 256 кб ???
если я правильно понял суть проблемы в есть функции которые позволяют обращаться по 32битному адресу pgm_read_byte_far(address_long)
Не могли бы Вы сделать урок по подключению внешнего Ацп к микроконтроллеру.
Хочу сделать весы , но не знаю как подключить внешнее Ацп и как написать программу.
Александр, да есть такое в планах, правда не знаю насколько ближайших
Спасибо , буду посматривать сайт почаще. :
Здравствуйте. Купил модуль KX-711 внешнее ацп 24бит.Не могли бы Вы подсказать как его подключить. В сети есть описание как подключить , но исходник написан на авр.студио.
Но я начинал на Ваших уроках в СV AVR для меня это сложновато. Прошивать готовой программой не хочу. Так как люблю разбираться сам и писать. Мне нужен толчек что бы разобраться. Если нет возможности подсказать то хотя бы скажите нужна ли библиотека для этого модуля и если нужна то где ее скачать.
Вы можете посмотреть какой АЦП установлен на плате и возможно поискать готовые библиотеки на сайте производителя
Здравствуйте. Интересует передача и прием нескольких байт.
Если с передачей все ясно (массив и цикл), то что сделать с приемом?
Как можно начало и конец посылки определять? (понятно что можно взять переменную и делать ее инкремент и писать в массив, но что делать, если передача прекратится?)
таймаут или спецсимвол окончания
если длина посылки фиксирована, то выделить под неё кольцевой буффер с запасом на маркер начала и контрольную сумму и ввести таймаут приёма и флаг
по приему первого байта (маркер начала) выставляем флаг в единицу, заполняем кольцевой буффер принятыми данными, по достижении маркером конца буффера завершаем прием и проверяем контрольную сумму сбрасываем флаг, готовы принимать следующий пакет
если по истечении таймаута маркер не достиг конца буффера (при желанииможнои сумму проверить) то пакет был поврежден, обрабатываем ошибку, сбрасываем флаг, готовы принимать следующий
Добрый день!
Ваши уроки просты и понятны. Спасибо!
Не могли бы Вы сделать урок в СV AVR по управлению генератором DDS «AD9832», он как раз общается с МК по SPI?
В протеусе его нет, но можно заменить вторым микроконтроллером и выдавать на ЖКИ информацию, например частоту синуса.
было в планах, хотел сделать платку потестить, потом посмотрел на али там готовых генераторов дофига.
Напаял на плату внешний цап который работает по SPI, после чего перестал прошиваться контроллер, программатор не может его перевести в режим программирования, выдает ошибку avrprog error entering programming mode
Если у цапа есть нога ресета и она не заведена, то заведите. Больше тут особо наверно ничего не придумаешь.
Подскажите пожалуйста, SPI это ведь синхронная передача
нужно ли настраивать частоту spi для ведомых?
как обстоит дело если ведомые имеют разную тактовую частоту, скажем 2.5 и 3.75 МГц, а мастер 1 Мгц?
вот что говорит даташит — In SPI Slave mode, the control logic will sample the incoming signal of the SCK pin. To ensure correct sampling of the clock signal, the frequency of the SPI clock should never exceed fosc/4
Здравствуйте. Подскажите пожалуйста, я сделал что бы при нажатии одной из двух кнопок работал один из ведомых МК. Но вот не
могу заставить что б светодиод не моргал, как это можно сделать?
Добрый день!
Никто не показывает полную схему соединения двух МК.
С кварцами, питанием и т.п. Показывают общие схемы.
Вопрос: как тактировать два МК в режиме SPI?
С уважением, Сергей.
Добрый день!
Подскажите, как тактировать два МК, работающих через SPI?
1) Каждый МК тактируется своим генератором/кварцем?
2) Надо делать некий внешний общий источник генератор тактов?
3) Кварц Мастера запаралелить на входы XTAL1 и XTAL2 и всех делов?
??????
Никто не показывает полную схему и не объясняет (не подсказывает).
Заранее благодарен.
SPI синхронный интерфейс, мастер подает клоки, слейв по ним ориентируется. Поэтому кто как клочится не важно, НО (!) если у вас один камень будет шарашить SPI на 8МГц а второй на 1МГц, то тупо слейв не будет успевать читать. Так что никакой полной схемы тут нет.
У меня вопрос? SPI библиотеки можно увидеть CVAVR ?Открыть и прочитать?
смотря что вы имеете ввиду под SPI библиотекой. Если инициализацию и передачу самого камня, то возможно, но там ничего интересного. Если речь идет о дисплейчиках и прочей периферии, то навряд ли. Можете посмотреть в папке самого CAVR, некоторые из библиотек открыты.
у меня ещё один вопрос к мастеру.SPI пример у вас как передаёт мастер к слейву а как же наоборот .Чтоб слейв передавал мастеру.?
никак, прием и передача производится одновременно, поэтому слейв инициировать может передачу только при помощи костылей.
спасибо
Добрый день!
Передача одного бита понятна. Подскажите, как передать байт, а лучше 2 байта по аппаратному SPI от одной Ftmega8 до другой
никакой разницы, передаете 1-2-10 сколько угодно байт, в чем вопрос?
Здравствуйте, как прошиваются 2 и более МК подключенных по SPI? Возможно ли прошить их когда они распаяны на плате через 1 порт или необходимо прошивать каждый МК по отдельности?
у каждого spi своя ножка CS
Почему то ни в одном туториале по spi не упоминается одна очень важная вещь .Я по своей простоте хотел обойтись только выводом данных (MOSI PB3 ) и линией тактирования (SCK PB5),ну а зачем мне больше ?прижимал к земле устройство другим пином (я говорю про так называемый SS).И вот собственно в чем заковырка ,настраиваю я значит порт DDR на выход только для MOSI и SCK ,собираю код-не работает ,танцую с бубном -не работает .Почему?потому что какая особенность МК(может китайского) что если не назначить DDR SS(он же PB2) то spi не заводится.Это стоило мне очень много времени и нервов
можете ножку CS подтянуть на землю (EN) и не подключать ее к мк.
ivan rusev on 12.03.2019 в 07:49
у меня ещё один вопрос к мастеру.SPI пример у вас как передаёт мастер к слейву а как же наоборот .Чтоб слейв передавал мастеру.?
admin on 12.03.2019 в 23:15
никак, прием и передача производится одновременно, поэтому слейв инициировать может передачу только при помощи костылей
Админ ты че тут пургу то несешь???,чего учишь людей когда сам не знаешь че к чему!!!
Master:
Код:
master_data_out=0xAA;
while (1)
{
PORTB.2=0; //SS to 0
SPDR=master_data_out;
while(!(SPSR & (1SPIF)));
master_data_in=SPDR;
PORTB.2=1; //SS to 1
}
Slave:
Код:
slave_data_out=0x04;
while (1)
{
SPDR=slave_data_out;
while(!(SPSR & (1SPIF)));
slave_data_in=SPDR;
}
меняйте режимы на 1 и 3 при передачи слэйвом.
Прежде чем давать такие однозначные заключения, почитайте про то как работает spi. Слейв не может инициировать передачу без костылей, хотя бы даже потому что мастер клочит линию, а интерфейс синхронный, т.е. данных без клоков не будет. Можно на ходу менять мастера со слейвом, можно дополнительно заводить ноги, чтобы слейв заставлял мастера читать. Но это костыли и если есть выбор то лучше взять другой интерфейс в этом случае. Поэтому мой ответ был справедлив, слейв сам не может передавать данные, данные из слейва читаются одновременно с передачей из мастера и никак иначе. Ну и в этом случае не сложно догадаться что чтобы данные улетели со слейва их надо запихать в SPDR.
Все верно,токо вопрос был в том как передать данные со слэйва,а не то что он не может передать данные без мастера,не путайте новичков. 😀 ,я то все прекрасно понимаю.
Для новичку всего лишь нужно было прочесть данные со слэйва. 😀 ,а вы придрались к словам.
Здравствуйте,
Некоторые девайсы, напр. синтезатор 7001 или DDS AD9850 просят передачи байта начиная с младшего бита.
Есть ли у AVR SPI опция реверса, или байт нужно предварительно оборачивать программно? Если нет, то проще, вроде передать байт программно через любую ногу не заморачиваясь с SPI.
Спасибо за внимание,
Владимир