МК - ATmega8. В режиме ведомого, когда кладу данные в SPDR, на ведущий приходят данные сдвинутые на один вправо. Т. е. хочу отправить 0b10000111, а приходит 0b01000011.
Логика программы:
Ведущий (мастер):
установка в 0 SS ведомого, отправка-прием-запись данных, установка в 1 SS ведомого, ждем (например 10 мкс)
Ведомый:
SPDR=0b00000011;
while(1) { //цикл
отправка-прием-запись данных, ждем пока SS не установится в 1, SPDR=0b10000111;
}
Причем самый первый SPDR=0b00000011; приходит верно, а остальные сдвинутым приходят. В чем дело?
настройки для ведущего: 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; // против дребезга
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; // антидребезг }
}
}
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; }
}
}
Да 1 ведущий, 1 ведомый. При нажатии на кнопку я отправляю-принимаю 10 байт. Если у ведомого на SS будет всегда 0, он же не сможет записать данные в SPDR. Если всегда 1 он будет отключен. Не так?
кто вам сказал, что не сможет? ведущий от ведомого отличается только тем, что после записи в SPDR ведущий сразу же начинает выдавать такты SCK, а ведомый не начинает.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Тут ведь какое дело , ведомый пока мастер выдает SCK , может подпихивать байты в SPDR , которые мастер может спокойно получить . Главное успевать за мастером.
У Мастера ожидание после прием-передачи оставил, а управление SS ведомым убрал (теперь он всегда на 0-ле) у ведомого. У ведомого сразу после окончания прием-передачи записываю новые данные в SPDR. Теперь все данные приходят корректно. Спасибо за ответы!
До этого перед тем как записать новые данные в SPDR у ведомого, я проверял SS. И записывал, только если там 1. Могла ли быть ошибка из-за этого?
Кстати, данные приходили до этого так:
нужные данные - 0b01111111; или 0b10000000;
приходящие данные - 0b00111111; или 0b11000000;
Т. е. 7 бит записывается дважды в 7 и 6 ячейку. Остальные сдвигаются с потерией 0-го бита.
Я бы не стал вешать константный 0 на SS . После установки SS в 0 дал бы небольшую задержку перед передачей первого байта, чтобы слейв успел загрузить в регистр данных свой первый предназначенный для отправки байт.