Skocz do zawartości

Problem z uruchomieniem sprzętowego SPI


Pomocna odpowiedź

Napisano

Witam, ostatnio próbowałem napisać komunikacje SPI z wykorzystaniem wbudowanych peryferiów. No i za cholere nie nie udało mi się tego ruszyć aże nie posiadam analizatora stanów logicznych nie jestem w stanie nawet stwierdzić czy nie wysyłam czy nie odbieram danych. Używam 2x ATMega32a. Oto program:

Master

#include <avr/io.h>
#include "SPI.h"

int main(void)
{
SPIMasterInit();
while(1)
{
SPIFastTX(0xff);
for (uint16_t i =0; i < 10000; i++){};
SPIFastTX(0x00);
for (uint16_t i =0; i < 10000; i++){};
SPIFastTX(0xff);
for (uint16_t i =0; i < 10000; i++){};
SPIFastTX(0x00);
for (uint16_t i =0; i < 10000; i++){};
}
}

Slave

#include <avr/io.h>
#include "SPI.h"

int main(void)
{
SPISlaveInit();
DDRD = 0b00000011;
while(1)
{
if(SPIFastRX() == 0xff)
PORTD = 1;
else
PORTD = 0;
}
}

SPI.c

#include <avr/io.h>
#include "SPI.h"

uint8_t SPIBuf [16];
uint8_t SPIDataPointer;
uint8_t SPIBytes;
uint8_t SPIStatus;  //0 = Transmit  1 = Receive

void SPIMasterInit(void) // Init SPI as master or slave
{
//Set IO ports
SPI_DDR |= (1<<MOSI_BIT) | (1<<SCK_BIT);
SPI_DDR &= ~(1<<MISO_BIT);

//Set registers
SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR1); //SPI Enable, prescaler 16
}

void SPISlaveInit(void) // Init SPI as master or slave
{
//Set IO ports
SPI_DDR |= (1<<MISO_BIT);
//SPI_DDR &= ~(1<<MOSI_BIT) | (1<<SCK_BIT);

//Set registers
SPCR = (1<<SPE); //SPI Enable with interrupt
}

void SPIStartTransmit(uint8_t bytes)
{
SPIDataPointer = 0;
SPDR = SPIBuf[0];
SPIDataPointer++;
SPIBytes = bytes - 1;
}

void SPIStartReceive(uint8_t bytes)
{
SPIDataPointer = 0;
SPIStatus = 1;
SPIBytes = bytes - 1;
}

void SPIFastTX(uint8_t data)
{
//if(SPIBytes > 0) return;
//while(!(SPSR & (1<<SPIF)));
SPDR = data;
while(!(SPSR & (1<<SPIF)));
}

uint8_t SPIFastRX(void)
{
//if(SPIBytes > 0) return 0;
while(!(SPSR & (1<<SPIF)))
return SPDR;
}

int ISR(SPI_STC_vect)
{
if(SPIStatus == 0)
{
	if(SPIDataPointer <= SPIBytes)
	{
		SPDR = SPIBuf[SPIDataPointer];
		SPIDataPointer++;
	}
}
else
{
	if (SPIDataPointer <= SPIBytes)
	{
		SPIBuf[SPIDataPointer] = SPDR;
		SPIDataPointer++;
	}
}
return 0;
}

SPI.h

#ifndef SPI_H_
#define SPI_H_

#define SPI_DDR DDRB
#define SPI_PORT PORTB
#define SPI_PIN PINB
#define MOSI_BIT PB5
#define MISO_BIT PB6
#define SCK_BIT PB7

#define SPI_SLAVE 0
#define SPI_MASTER 1

void SPIMasterInit(void);
void SPISlaveInit(void);
void SPIStartTransmit(uint8_t bytes);
void SPIStartReceive(uint8_t bytes);
void SPIFastTX(uint8_t data);
uint8_t SPIFastRX(void);

#endif /* SPI_H_ */

I płytka:

Z góry dzięki za pomoc.

Dużo można by pisać, ale skrócę to do jednego pytania:

Czy przeczytałeś rozdział dot. SPI w karcie katalogowej procesora mega32? Jest tam dokładnie wytłumaczone jak to działa i są nawet gotowe funkcje wysyłania i odbierania. Zwróć szczególną uwagę na znaczenie i (niesymetryczny) sposób używania linii SS (Slave Select). Po lekturze wróć do kodu i sam powiedz co robisz źle.

Acha, i nie używaj do opóźniania pętli w takiej formie, bo po kompilacji może z nich nic nie zostać. Jeżeli już bardzo to lubisz, odliczaj zmienne z atrybutem volatile. A najlepiej korzystaj z opóźnień z biblioteki standardowej - masz ją nawet jeśli piszesz na goły procesor.

Jako swoiste kompendium wiedzy możesz też posłużyć się tym:

http://www.atmel.com/Images/Atmel-2585-Setup-and-Use-of-the-SPI_ApplicationNote_AVR151.pdf

No ok, ustawiłem u Mastera SS jako wyjście i na próbę usunąłem główną pętlę. No i teraz dioda zapala się na ok. sekundę i gaśnie a potem zero reakcji. I to niezależnie ile jak dużych delay'ów dam i ile razy wykonam zestaw TX + _delay_ms. Nie mam pojęcia o co chodzi. Być może to nie u mastera jest błąd a u slave'a 🙁.

Edit: Zmieniłem program slave i już działa. Dzięki za pomoc.

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...