Страница 1 из 1

SPI передача от ведомого

Добавлено: Чт июн 18, 2015 01:26:48
KaiTheKat
МК - ATmega8. В режиме ведомого, когда кладу данные в SPDR, на ведущий приходят данные сдвинутые на один вправо. Т. е. хочу отправить 0b10000111, а приходит 0b01000011.
Логика программы:
Ведущий (мастер):
установка в 0 SS ведомого, отправка-прием-запись данных, установка в 1 SS ведомого, ждем (например 10 мкс)
Ведомый:
SPDR=0b00000011;
while(1) { //цикл
отправка-прием-запись данных, ждем пока SS не установится в 1, SPDR=0b10000111;
}

Причем самый первый SPDR=0b00000011; приходит верно, а остальные сдвинутым приходят. В чем дело?

Re: SPI передача от ведомого

Добавлено: Чт июн 18, 2015 05:48:58
Mishany
надо смотреть настройки SPI, и саму программу... вариантов много

Re: SPI передача от ведомого

Добавлено: Чт июн 18, 2015 07:49:04
ARV
как вариант: у ведущего и ведомого по разным фронтам SCK синхронизируются данные - у одного по переднему, у другого по заднему.

Re: SPI передача от ведомого

Добавлено: Чт июн 18, 2015 13:33:08
KaiTheKat
настройки для ведущего: SPCR=(1<<SPE)|(1<<MSTR);
настройки для ведомого:SPCR=(1<<SPE);
Данные с ведущего на ведомый приходят верные, а с ведомого на ведущий со сдвигом, кроме первого байта.
Код целиком
Ведущий (Мастер):
#define F_CPU 8000000UL
#include <util/delay.h>
#include <avr/io.h>
#include <string.h>

char txbuf[10]; //буфер для передачи
char rxbuf[10]; //буфер для приема
uint8_t a=0;
bool clk=false; // против дребезга

char sendSpi(uint8_t data) { SPDR=data; while(!(SPSR&(1<<SPIF))); return SPDR; } // отправка-прием-запись

int main(void)
{
DDRB=(1<<2)|(1<<3)|(1<<4)|(1<<5); // все порты SPI на выход
DDRD=(1<<0); // для управления SS ведомого
PORTD=(1<<5)|(1<<6); // для кнопок
DDRC=255; PORTC=0; // для вывода полученных данных
SPCR=(1<<SPE)|(1<<MSTR); // SPI включен, режим Мастер

txbuf[0]=0b00000001; txbuf[1]=0b00001101; txbuf[2]=0b01101000; // запись в буфер передачи

while(1)
{
if((clk==false)) {
if(!(PIND&(1<<5))) { clk = true; // после нажатия на кнопку отправляем данные 10 раз (буфер состоит из 10-ти байтов)
for(uint8_t i=0; i<10; i++) { PORTD&=~(1<<0); _delay_ms(1); rxbuf=sendSpi(txbuf); _delay_ms(1); PORTD|=(1<<0); _delay_ms(1); //устанавливаем SS ведомого на 0, отправка данных, устанавливаем SS ведомого на 1, ждем 1 мс }
}
else if(!(PIND&(1<<6))) { clk = true; // после нажатия выводим на портс полученные данные по очереди.
PORTC=rxbuf[a]; a++; if(a>9) { a=0; }
}
}
if((clk==true)&&(PIND&(1<<5))&&(PIND&(1<<6))) { clk = false; // антидребезг }
}
}

Ведомый:
#define F_CPU 8000000UL
#include <util/delay.h>
#include <avr/io.h>
#include <string.h>

char txbuf[10]; //буфер для передачи
char rxbuf[10]; //буфер для приема
uint8_t a=0; bool clk=false; // против дребезга

bool waitSendByte() { // ждем больше 100мс, пока не придут данные от ведущего. Если данные не пришли переходим на след. действие.
for(uint32_t i=0; i<110000; i++) {
if((SPSR&(1<<SPIF))) { return true; }
}
return false;
}
void setSPDR() { // ждем пока SS не установится в 1 (деактивацию SPI)
while(1) {
if((PINB&(1<<2))) { break; }
}
}
int main(void)
{
DDRB=(1<<4); //MISO на выход
DDRD=0; PORTD=(1<<5)|(1<<6); // для кнопок
DDRC=255; PORTC=0; // для вывода полученных данных
SPCR=(1<<SPE); // SPI включен

txbuf[0]=0b0000111; txbuf[1]=0b11110000; txbuf[2]=0b00011100; // запись в буфер передачи
SPDR=0b00000011; // самый первые данные для передачи. они приходят успешно.

while(1)
{
for(uint8_t i=0; i<10; i++) {
if(waitSendByte()) { rxbuf=SPDR; setSPDR(); SPDR=0b00001111; (или SPDR=txbuf;) //отправка-прием-запись данных } else { break; }
}
if((clk==false)) { // после нажатия выводим на портс полученные данные по очереди.
if(!(PIND&(1<<6))) { clk = true; // после
PORTC=rxbuf[a]; a++; if(a>9) { a=0; }
}
}
if((clk==true)&&(PIND&(1<<6))) { clk=false; }
}
}

Re: SPI передача от ведомого

Добавлено: Чт июн 18, 2015 14:35:10
ARV
у вас 1 ведущий и 1 ведомый? если да, то тогда не надо использовать SS, соответственно ждать ничего не надо тоже.

остальное, благодаря чудному оформлению кода, смотреть не стал :dont_know:

Re: SPI передача от ведомого

Добавлено: Чт июн 18, 2015 14:44:02
KaiTheKat
Да 1 ведущий, 1 ведомый. При нажатии на кнопку я отправляю-принимаю 10 байт. Если у ведомого на SS будет всегда 0, он же не сможет записать данные в SPDR. Если всегда 1 он будет отключен. Не так?

Re: SPI передача от ведомого

Добавлено: Чт июн 18, 2015 18:13:14
ARV
кто вам сказал, что не сможет? ведущий от ведомого отличается только тем, что после записи в SPDR ведущий сразу же начинает выдавать такты SCK, а ведомый не начинает.

Re: SPI передача от ведомого

Добавлено: Чт июн 18, 2015 20:15:54
Jack_A
ARV писал(а): после записи в SPDR ведущий сразу же начинает выдавать такты SCK, а ведомый не начинает.
Ведомый вообще никогда SCK не выдает.

Re: SPI передача от ведомого

Добавлено: Чт июн 18, 2015 20:20:14
ARV
Jack_A писал(а):Ведомый вообще никогда SCK не выдает.
ну а я разве что-то другое сказал?

Re: SPI передача от ведомого

Добавлено: Чт июн 18, 2015 20:22:35
Jack_A
Я так понял : "начинает, но не сразу " :)

Re: SPI передача от ведомого

Добавлено: Чт июн 18, 2015 20:23:09
ILYAUL
Тут ведь какое дело , ведомый пока мастер выдает SCK , может подпихивать байты в SPDR , которые мастер может спокойно получить . Главное успевать за мастером.

Re: SPI передача от ведомого

Добавлено: Чт июн 18, 2015 20:34:10
KaiTheKat
У Мастера ожидание после прием-передачи оставил, а управление SS ведомым убрал (теперь он всегда на 0-ле) у ведомого. У ведомого сразу после окончания прием-передачи записываю новые данные в SPDR. Теперь все данные приходят корректно. Спасибо за ответы!

До этого перед тем как записать новые данные в SPDR у ведомого, я проверял SS. И записывал, только если там 1. Могла ли быть ошибка из-за этого?

Кстати, данные приходили до этого так:
нужные данные - 0b01111111; или 0b10000000;
приходящие данные - 0b00111111; или 0b11000000;

Т. е. 7 бит записывается дважды в 7 и 6 ячейку. Остальные сдвигаются с потерией 0-го бита.

Re: SPI передача от ведомого

Добавлено: Чт июн 18, 2015 21:01:30
ILYAUL
SS =0 - указывает ведомому , что с ним хотят пообщаться. Но к сожалению , автоматика не предусмотрена и проверять его вроде как необходимо (DS)

Но есть выход - использовать его как сигнал внешнего прерывания , отлавливая фронты.

Re: SPI передача от ведомого

Добавлено: Чт июн 18, 2015 22:22:55
Jack_A
Я бы не стал вешать константный 0 на SS . После установки SS в 0 дал бы небольшую задержку перед передачей первого байта, чтобы слейв успел загрузить в регистр данных свой первый предназначенный для отправки байт.