SPI Slave в Master и обратно

5N62V
Offline
Зарегистрирован: 25.02.2016

Всем бобра!

Столкнулся с задачей , в которой, кхе-кхе, как бы опыта маловато, т.к. с SPI работал мало, да все на уровне библиотек. Тут надо копнуть глубже, референс мануал почитал, вроде понятно, но меня подводные камни настигают всегда и везде, поэтому буду благодарен за советы.

Итак, есть устройство на Atmega328P которое работает эдаким логгером и прашивателем датчиков. По шине SPI он подключен к главному контроллеру, и как истинный SLAVE, шлет ему инфу по состоянию датчиков , а именно 12 байт, по запросу, который должен приходить раз в секунду. В этом режиме запрос от главного контроллера синхронизирует весь алгоритм. Отправив 12 байт, утройство опрашивает датчики, и, переключив SPI в мастер, пишет лог на карту памяти. Затем опять переключается в слейв, и ждет следующего запроса.

Главный контроллер может выключиться. В этом случае данное устройство должно анализировать состояние CS, и если оно нулевое - уходить в сон. Просыпается оно от внешнего прерывания от RTC раз в секунду, инкреминирует counter, и если counter меньше значения X - опять засыпает.

Скажем, раз в пять минут, в зависимости от значения Х, устройство просыпается, опрашивает датчики и RTC, пишет лог, и опят засыпает, и так до тех пор, пока CS на шине SPI опять не станет единицей. 

Рисунок алгоритма прикладываю. Собственно хочу спросить у людей опытных, какие недостатки такого алгоритма, и какие камни меня могут по этому поводу ожидать.

Глум , подколки - приветствуются, флуд - не очень. :)

5N62V
Offline
Зарегистрирован: 25.02.2016

Насколько я понимаю, переключение мастер-слейв должно выглядеть где-то так(пока без спящего режима):

#include<SPI.h>
#include<SD.h>

#define THRESHOLD 300

File file;

struct {
uint32_t param1;
uint32_t param2;
uint32_t param3;
}data;


void setup(){
init_SPI_slave();
}

void init_SPI_slave(){
DDRB |= (1<<PORTB4);// MISO на выход
PORTB &= ~(1<<PORTB4); //низкий уровень
DDRB &=~((1<<PORTB2)|(1<<PORTB3)|(1<<PORTB5));// CS, MOSI, SCK - входы
SPCR=0b01000000; // только enable
}

void loop(){
if(PINB<<2)sendData();// если главный контроллер включен(CS поднята)
else; // спим до момента опроса датчиков
//опрашиваем датчики
// меняем содержимое data
writeLOG();
}

void writeLOG(){
  //настраиваем SPI как мастер
DDRB |= ((1<<PORTB2)|(1<<PORTB3)|(1<<PORTB5)); //ножки SPI на выход
DDRB &= ~(1<<PORTB4);// MISO на вход
PORTB &= ~((1<<PORTB2)|(1<<PORTB3)|(1<<PORTB5)); //низкий уровень
SPCR = 0b01010000;// enable + master

// тут пишем лог пользуясь SD.h

init_SPI_slave();//вазвращаем настройки на слейв
}

void sendData(){
  byte * ptrData = (byte*)(&data);
  uint8_t counter = 0;
  while(counter<sizeof(data)){
    SPDR = *(ptrData+counter);//вносим байт в регистр данных
    while(!(SPSR & (1<<SPIF)));//ждем пока байт передастся
  }
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

5N62V, попробую на пальцах объянить какую хрень вы несете. Есть человек. Он потерял руку. Ему сделали протез.И ладно подключили управления напрямую к нервам. Заебись. Теперь находится чувак и говорит. Как отключить человека, что бы протез за человека ел,спал, работал ну и так далее. Идиотизм. Так и у Вас. SPI всегда мастер, пототому что там только мастер может тактировать передачу. Теперь возвращаюсь к инвалиду. Вот в протезе сделали будильник. Но стартует передача мастером. Как передать сигналы будильника. Звуком, светом. В общем для этого организована банальная система прерываний. "Слыш барин,почта пожаловала" и чел лезет смотреть СМС.  И человека не надо отключать что бы мобильник напрямую СМС отправил в голову человека.

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

qwone пишет:

5N62V, попробую на пальцах объянить какую хрень вы несете. Есть человек. Он потерял руку. Ему сделали протез.И ладно подключили управления напрямую к нервам. Заебись. Теперь находится чувак и говорит. Как отключить человека, что бы протез за человека ел,спал, работал ну и так далее. Идиотизм. Так и у Вас. SPI всегда мастер, пототому что там только мастер может тактировать передачу. Теперь возвращаюсь к инвалиду. Вот в протезе сделали будильник. Но стартует передача мастером. Как передать сигналы будильника. Звуком, светом. В общем для этого организована банальная система прерываний. "Слыш барин,почта пожаловала" и чел лезет смотреть СМС.  И человека не надо отключать что бы мобильник напрямую СМС отправил в голову человека.

Ёмко. Где то так...

5N62V
Offline
Зарегистрирован: 25.02.2016

qwone пишет:

5N62V, попробую на пальцах объянить какую хрень вы несете. Есть человек. Он потерял руку. Ему сделали протез.И ладно подключили управления напрямую к нервам. Заебись. Теперь находится чувак и говорит. Как отключить человека, что бы протез за человека ел,спал, работал ну и так далее. Идиотизм. Так и у Вас. SPI всегда мастер, пототому что там только мастер может тактировать передачу. Теперь возвращаюсь к инвалиду. Вот в протезе сделали будильник. Но стартует передача мастером. Как передать сигналы будильника. Звуком, светом. В общем для этого организована банальная система прерываний. "Слыш барин,почта пожаловала" и чел лезет смотреть СМС.  И человека не надо отключать что бы мобильник напрямую СМС отправил в голову человека.

Нагородили тут какой-то белеберды. Проще нельзя было написать?  После принятия 12ти байт главный контроллер должен снять тактирование с шины SCL до следующего сеанса. Согласен. Спасибо.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

5N62V пишет:
Нагородили тут какой-то белеберды. Проще нельзя было написать?  После принятия 12ти байт главный контроллер должен снять тактирование с шины SCL до следующего сеанса. Согласен. Спасибо.
Но похоже такой фичи в SPI нет изначально. Опять же если шиной пользуются несколько контролеров, то надо вводить еще одну линию READY. О занято 1 свободно. И скорее всего это уже будет не SPI. В таком случае занимайтесь свой билибердой сами. Я пас.

5N62V
Offline
Зарегистрирован: 25.02.2016

qwone пишет:

 Но похоже такой фичи в SPI нет изначально.

В протоколе SPI много чего нет, т.к. это протокол. А так, полагаю, достаточно пин с которого идет тактирование с выхода переключить на вход, и тактирование снимется.

Или просто инициализацию шины задизэйблить.

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

А в чем проблема? Работает - в проекты, не работает - так спросите что не работает софт или хард.

И скажите про скорость опроса портов.

5N62V
Offline
Зарегистрирован: 25.02.2016

mykaida пишет:

А в чем проблема? Работает - в проекты, не работает - так спросите что не работает софт или хард.

просто я такой реализации нигде не видел, а сделать надо. Вот и спрашиваю советов. Одна подсказка уже есть.

mykaida пишет:

И скажите про скорость опроса портов.

Вопрос не понял. 

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

5N62V пишет:

Вопрос не понял. 

А вдруг ардуинка не сможет работать на этой скорости. И Вам придется переходить на другой чип...

5N62V
Offline
Зарегистрирован: 25.02.2016

mykaida пишет:

А вдруг ардуинка не сможет работать на этой скорости. И Вам придется переходить на другой чип...

Насколько я знаю, на всех процессорах скорость шины настраивается предделителями. В моем коде сокрость шины у ардуины 4МГц. Надо будет под эту скорость подстроить и главный контроллер, который кмк будет на STM32f4 -каком-то там.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

mykaida пишет:
А вдруг ардуинка не сможет работать на этой скорости. И Вам придется переходить на другой чип...
Разумеется. SPI это "домашний порт" . Специально для облуживание устройств находящихся на плате. А если метров с 10 то точно скорость упадет. Сильно слабенькие пины у чипа. Не успеют зарядить емкость проводов на большой скорости.

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

В протеусе соорудите проект, а затем выкладывайте.

5N62V
Offline
Зарегистрирован: 25.02.2016

Чтоб у меня все гладко прошло - да ни в жизть! :)

Не то, чтоб совсем не работает моя задумка, не как-то хреново. Уж лучше бы и вовсе не работала.

Вобщем сам код рабочий, проработал много недель. Логгер писал все как надо. Луп вращается ровно раз в секунду, опрашивает все как надо, и в конце вызывает функцию записи лога на карту SD , использую библиотеку  SD.h

Теперь прикрутил инициализацию SPI как слейва, но при приходе в функцию записи лога шина переинициализируется процом как мастер, пишет лог, и опять в слейв. Пока что никакого обмена с внешним устройством, просто решил проверить как будет вести себя шина. Все работает ровно 304 шага, на 305м перестается видеться файл, и - привет семье. Файлики записываются равные, по 14 848 байт каждый. 

Беру и записываю return; прямо вначале инициализации слейва - все работает как надо. Убераю ретурн - 304 шага работает, дальше - нет. Я в печали.  :( почему именно 304 шага?  перестает срабатывать строчка

 file = SD.open("log.csv", FILE_WRITE);

Самое гадкое: не пойму куда кидаться. Флешку форматировал, контакты протирал. :)

Я понимаю, что задача специфичная, но может у кого проскочит светлая мысля! 

фукнции инициализации:

void init_SPI_slave(){
//return;
DDRB |= (1<<PORTB4);// MISO на выход
PORTB &= ~(1<<PORTB4); //низкий уровень
DDRB &=~((1<<PORTB2)|(1<<PORTB3)|(1<<PORTB5));// CS, MOSI, SCK - входы
SPCR = 0;
SPCR=0b01000000; // только enable

}

void init_SPI_master(){

DDRB |= ((1<<PORTB2)|(1<<PORTB3)|(1<<PORTB5)); //ножки SPI на выход
//DDRB |= ((1<<PORTB3)|(1<<PORTB5)); 
DDRB &= ~(1<<PORTB4);// MISO на вход
PORTB &= ~((1<<PORTB2)|(1<<PORTB3)|(1<<PORTB5)); //низкий уровень
SPCR = 0;
SPCR = 0b01010001;// enable + master

}

Функция записи лога:

void write_log(uint32_t t) {

init_SPI_master();


  file = SD.open("log.csv", FILE_WRITE);
  if (file) {
    file.print(day); file.print(",");
    file.print(month); file.print(",");
    file.print(year); file.print(",");
    file.print(hour); file.print(",");
    file.print(min); file.print(",");
    file.print(sec); file.print(",");
    file.print((float)data.voltage / 1000, 3); file.print(",");
    file.print((float)data.discharge / 1000, 3); file.print(",");
    file.print(data.capacity); file.print(",");
    file.print((float)t / 1000, 1); file.print(",");
    long temp;
    EEPROM.get(INITIAL_CAPACITY_ADDR,temp);
    file.print((int32_t)(((int64_t)data.capacity * 100) / temp)); file.print(",");
    file.println(power);
    file.close();

  }
  else {  Serial.println("NO FILE");}
  init_SPI_slave();
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

5N62V пишет:
Чтоб у меня все гладко прошло - да ни в жизть! :)
Вы наверное коллекционируете сложности. А если они малы, то даже слабенькую сложность надо усложнить до супер. 

  Так вот по теме. Что такое Мастер-слейвы. Это структура провереная жизнью. Начальник и куча подчиненых. Тогда всегда можно упорядочить работу. Но если куча начальников, то в работе начинается жопа. Но для чего нужен начальник? Для проведения своих идей и указаний до подчиненых. Тоже не верно. 1- начальник обязан отсекать все не нужные разговоры не по теме, не по текущей теме. 2- начальник должен позволять подчиненым высказаться, опять же по теме. 3- из этой суммы высказываний сделать выводы и передать что каждый должен подчиненый делать дальше.  Если начальники регулярно меняются, то теперь уже подчиненые дисорганизуются. Недавно предыдущему начальнику высказывал, а пришел новый и с ново здорово. 

  ПС: Если Вас коробит "диктат начальника", то сделайте его "сервером почтовых сообщений друг другу". Если одному подчиненому надо передать сообщение другому подчиненому, то заходит к начальнику и оставляет письмо . И теперь начальник должен заморочится, что бы письмо дошло до адресата. Как это не похоже на человеческую организацию. Но в мире сетей все так и проиходит.

5N62V
Offline
Зарегистрирован: 25.02.2016

Пух, мне Вашего уровня абстрактности не достичь, видимо, никогда.

Тут как бы не структура нашальник - куча подчиненных, а начальник-бригадир-рабочий. Вот бригадир-то и является подчиненным для своего начальника, и начальником для рабочего. А начальник бригадира и рабочий непосредственно не общаются, хотя и сидят а одной шине тактирования.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Ну здесь вы глюканули. линии начальник-бригадир и бригадир-подчиненые это абсолютно разные линии. В первой мастер начальник, во второй бригадир. И строить их надо по разному. Классический SPI нужен для общения с устройствами у которых вообще нет мозгов, только один регистр. Пин CS у них за адрес устроства. Просто да. Но для мозговитых устроств классический SPI очень не удобен. Так как CS от мастера активного устройства надо сразу заводить на прерывание слейва активного устройства. А так же от слейва к мастеру надо вести пин обратку REALY. И все потому что если подан сигнал прерывания, то слейв будет в процедуре обработчике этого прерывания. И надо ждать что бы слейв указал что он готов принять сигнал. Да и принимать будет программно, так как в АВР нет пассивного SPI. Только актив. 

ПС: лучше бы у вас начальник бригадир общались по Serial. гемора было бы поменьше.

5N62V
Offline
Зарегистрирован: 25.02.2016

qwone пишет:

ПС: лучше бы у вас начальник бригадир общались по Serial. гемора было бы поменьше.

Ну, это очевидные вещи. А лучше перейти на другой контроллер, где пару SPI, пару I2C, с пяток UARTов.

qwone пишет:

Ну здесь вы глюканули. линии начальник-бригадир и бригадир-подчиненые это абсолютно разные линии. 

Ну это в Вашем представлении они разные. А в моем - одна и та же линия, просто с временным разделением ее использования. ЦэЭс - разные, правда. По крайней мере я пытаюсь это реализовать. До обеда нашальник сношает бригадира, после обеда  - бригадир рабочего, образно выражаясь.

Скажете так не работает? отчасти будете правы, ибо после 304ого шага не работает, но до 304ого-то работает! Так что пока мы оба правы. Вот только делать не знаю чего. Полезу наверное изучать команды управления SD картой, и буду врукопашную с картой общаться, чтоб понять что ей не так. А то в этой библиотеке черт ногу сломит!