Forum: Mikrocontroller und Digitale Elektronik ATMEGA 1280 USART0 in SPI MODE


von Jochen (Gast)


Lesenswert?

Hallo Leute,

habe folgendes Problem, will mein Display EA DOGM and die USART0 in SPI 
Mode anschließen. Ich verwende einen ATmega 1280 TQFP100

Das Display war bisher direkt an der SPI Schnittstelle dran, da ich aber 
diese nun für eine SDCard Ansteuerung brauche, muss ich nun die USART0 
in SPI Mode verwenden.

Wie gesagt das Display funktionierte bisher tatellos an SPI, das einzige 
was nun geändert wurde, ist MOSI und SCK vom Display an USART 
angeschlossen
die restlichen PINs blieben unberührt.

DISPLAY MOSI -> TXD
DISPLAY SCK -> XCK0

Init Funktion
1
#define XCK0_DDR  DDRE
2
#define XCK0  PD2
3
4
// Initialize the SPI as master
5
void uart_spi_init()
6
{
7
  // DDRB = 0xFF;
8
  // SPI max. speed
9
  // the DOGM128 lcd controller can work at 20 MHz
10
        // SPIMODE 3
11
  //SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPHA) | (1 << CPOL);
12
  //SPSR = (1 << SPI2X);
13
14
15
DDRB = 0xFF;
16
DDRE = 0xFF;
17
18
UBRR0 = 0;
19
20
// Set the XCK0 port pin as an output, enables master mode
21
XCK0_DDR |= (1 << XCK0);
22
23
// Set MSPI mode of operation and SPI mode 3
24
UCSR0C = (1 << UMSEL01) | (1 << UMSEL00) | (1 << UCSZ00)| (0 << UCSZ01) | (1 << UCPOL0);
25
26
// Enable the receiver and transmitter
27
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
28
29
UBRR0 = 7;
30
}


und Sende Funktion
1
void send_byte (uint8_t data)
2
{
3
  clr_cs ();
4
5
  //SPI SENDBYTE
6
  //SPDR = data;
7
  //while (!(SPSR & (1<<SPIF)));
8
9
  while (!(UCSR0A & (1 << UDRE0))); //USART in SPIMODE
10
  UDR0 = data; //USART in SPIMODE
11
12
  set_cs ();
13
}

Aber mit diesen Änderungen Funktioniert mein Display nicht mehr!
Display funktioniert noch, habe noch eine zwei Platine mit der SPI 
Ansteuerung!

Habe ich irgendetwas übersehen? Es muss an der Initialisierung oder am 
Senden liegen!!

Danke für eure Hilfe

Gruß
Jochen

von spess53 (Gast)


Lesenswert?

Hi

>while (!(UCSR0A & (1 << UDRE0))); //USART in SPIMODE

Im Gegensatz zum SPI ist das Datenregister der UART gepuffert. UDRE gibt 
nur an, das ein Byte an UDR übergeben werden kann, nicht , das das 
Byte fertig gesendet wurde. Bevor du den Status der Steuerleitungen 
(CS,A0..) änderst, must du mit TXC prüfen, ob das letzte Byte komplett 
gesendet wurde.

MfG Spess

von Jochen (Gast)


Lesenswert?

Hi,

vielen Dank für die Info, habs entsprechend geändert!
1
void send_byte (uint8_t data)
2
{
3
  clr_cs ();
4
5
  while (!(UCSR0A & (1 << UDRE0)));
6
  UDR0 = data;
7
  while (!(UCSR0A & (1 << TXC0)));
8
9
  set_cs ();
10
}

Leider hat das auch nicht geholfen. Hast du noch eine Idee?

von spess53 (Gast)


Lesenswert?

Hi

Bei mir läuft das mit folgender UCSR0C-Initialisierung:
1
  ldi r16,1<<UMSEL01 | 1<<UMSEL00
2
  sts UCSR0C,r16

MfG Spess

von Dirk B. (sharandac)


Lesenswert?

Salut ...

ich benutze den USART0 auf einen Atmega2561, ich denke mal von den 
Register sollte das das selbe sein in etwa. Hier mein Code zum Init und 
senden/empfangen.
1
void SPI_init( void )
2
{
3
    UBRR0 = 0;
4
    /* Setting the XCKn port pin as output, enables master mode. */
5
    SPI_DDR |= ( 1 << XCK1 );
6
    /* Set MSPI mode of operation and SPI data mode 0. */
7
    UCSR0C = (1<<UMSEL01)|(1<<UMSEL00);
8
    /* Enable receiver and transmitter. */
9
    UCSR0B = (1<<RXEN0)|(1<<TXEN0);
10
    /* Set baud rate. */
11
    /* IMPORTANT: The Baud Rate must be set after the transmitter is enabled */
12
    UBRR0 = 0;
13
}
14
15
char SPI_ReadWrite( char Data )
16
{
17
  /* Wait for empty transmit buffer */
18
  while ( !( UCSR0A & (1<<UDRE0)) );
19
  /* Put data into buffer, sends the data */
20
  UDR0 = Data;
21
  /* Wait for data to be received */
22
  while ( !(UCSR0A & (1<<RXC0)) );
23
  /* Get and return received data from buffer */
24
  return UDR0;
25
}

Bei tut dieser Code mit einem ENC28j60. Evtl. musst du noch den Mode und 
Speed ändern auf deine Bedürfnisse.

CA Dirk

von Jochen (Gast)


Lesenswert?

Hallo Dirk,


SPI_DDR ist DDRE???

und

XCK1 ist PE2???

Sonst habe ich alles identisch, nur SPIMODE 3 das ich mit

(1 << UCSZ00)| (0 << UCSZ01) | (1 << UCPOL0)

eingestellt habe.


Ich denke die Speed, bzw Baudrate dürfte keine Rolle spielen!

Oder doch?

Gruß
Jochen

von Dirk B. (sharandac)


Lesenswert?

Salut ...

so weit ich das noch in Erinnerung habe war die Baudrate bei den 
Displays nicht so dolle.

SPI_DDR = DDRE

und XCK0 liegt auf PE2, da ist ein kleiner Fehler in meinem Listing, 
dort steht XCK1 :-). Aber interessant dürfte für dich eigentlich nur das 
abholen der Daten sein.

N8 Dirk

von Marcus P. (mapa)


Lesenswert?

Hallo,

versuche mal ein NOP oder ein kleine Pause nach dem Senden, also
1
void send_byte (uint8_t data)
2
{
3
  clr_cs ();
4
5
  //SPI SENDBYTE
6
  //SPDR = data;
7
  //while (!(SPSR & (1<<SPIF)));
8
9
  while (!(UCSR0A & (1 << UDRE0)));
10
  UDR0 = data; 
11
12
  _delay_ms (0.001); // ODER NOP;
13
14
  while (!(UCSR0A & (1 << TXC0)));
15
  set_cs ();
16
}

Die Displays brauchen eine kurze Pause bis Sie wieder den nächsten 
Befehl annehmen können. Wenn es zu schnell geht, dann reagiert das 
Display nicht mehr.

Gruß
Marcus Parentis

von AVRuser (Gast)


Lesenswert?

Hallo,

wo ist der /CS des SPI-Displays angeschlossen? Er sollte einen eigenen 
Pin bekommen; der /SS von der SPI-Schnittstelle wird ja wohl für die 
SDCard verwendet ...

> Ich denke die Speed, bzw Baudrate dürfte keine Rolle spielen! Oder doch?

Darüber sollte das Datenblatt des Displays Auskunft geben (max. SPI 
clock); zu schneller Takt kann Probleme geben.
Da das Display an der (richtigen) SPI-Schnittstelle gelaufen hat, kannst 
du diese Takteinstellungen doch für den SPI-USART übernehmen.

von Jochen (Gast)


Lesenswert?

Hallo,

also Marcus hatte recht, es lag an den Timings.
Sobald ich eine Pause einbaue, dann gehts!

Danke für Eure Hilfe und ein schönes Wochenende..


Gruß
Jochen

von Karl-heinz L. (karl-heinz-l)


Lesenswert?

Hallo Jochen,
im Datenblatt vom ATmega128x/644x/256x steht, nur die mega 
1281/6441/2561
haben den UART0 di/do Modus. Bei den anderen gehen die PINs nach 
MISO/MOSI

• PDO/TXD0 – Port E, Bit 1
PDO, SPI Serial Programming Data Output. During Serial Program 
Downloading, this pin is
used as data output line for the ATmega1281/2561. For 
ATmega640/1280/2560 this function is
placed on MISO.
TXD0, USART0 Transmit pin.
• PDI/RXD0/PCINT8 – Port E, Bit 0
PDI, SPI Serial Programming Data Input. During Serial Program 
Downloading, this pin is used
as data input line for the ATmega1281/2561. For ATmega640/1280/2560 this 
function is placed
on MOSI.
RXD0, USART0 Receive Pin. Receive Data (Data input pin for the USART0). 
When the
USART0 receiver is enabled this pin is configured as an input regardless 
of the value of DDRE0.
When the USART0 forces this pin to be an input, a logical one in PORTE0 
will turn on the internal
pull-up


Gruß Karl-Heinz

von spess53 (Gast)


Lesenswert?

Hi

Diese Zuordnung gilt nur für ISP. UART im SPI-Mode wird davon nicht 
tangiert.

MfG Spess

von Karl-heinz L. (karl-heinz-l)


Lesenswert?

Danke für die Info,
 Ich baue mir gerade ein Bord mit 2560 , externes Ram, Ethernet 
Controller, usart to usb chip, serial eeprom ,Micro-SD, jtag , ISP . Die 
freien Ports werde ich auf Wannenstecker ausführen.  Für den Ethernet 
Chip werde ich exklusive ein SPI port  z.b. PortE verwenden.
Der TCP/IP Stack wird eine Mischung von U.Radig Stack  und dem openMPC 
Stack.
Beide Stacks laufen auf meine Demo Boards mega644p und mega2560.
Mal sehen wie weit ich mit meinem Projekt komme.
Im Endausbau werde ich auch einen Ethernet Bootloader dazu packen.
Gruß KH

von Karl-heinz L. (karl-heinz-l)


Lesenswert?

Was mir noch aufgefallen ist, im AVR-Studio Simulator kann man den 
USART0 welcher auf PORTE zeigt , nur auf USART synchron stellen und 
nicht wie bei allen anderen auf SPI Master ?

Gruß KH

von Karl-heinz L. (karl-heinz-l)


Lesenswert?

ich habe mein Problem gelöst, im Datenblatt steht man muss nach dem 
Senden das UDRx lesen. deshalb sieht man bei vielen Implementierungen 
SPI_ReadWrite an einem Stück.

Wenn man mit SPI_Put oder SPI_Get arbeitet, muss im SPI_Put ein warten 
und lesen vom UDRx erfolgen. Diese Daten gebe ich mit einem Flag und 
einer Variable an die SPI_Get Prozedur weiter.

mit dieser kleinen Änderung läuft der Stack von U.Radig auch auf USART 
im SPI Mode,  könnte für manche Leute hilfreich sein.

Gilt für USART0:

static inline void spi_put( unsigned char value )
{

              /* Wait for empty transmit buffer */
              while ( !( UCSR0A & (1<<UDRE0)) );

              /* Put data into buffer, sends the data */
              UDR0 = value;
              while ( !(UCSR0A & (1<<RXC0)) );
              SendReceive=UDR0; //read data and flag read done to 
spi_get
              SendReceiveFlag=true;
}


static inline unsigned char spi_get(void)
{
              if (SendReceiveFlag==true)
              {
                SendReceiveFlag=false;
                return SendReceive;
              }

              while ( !(UCSR0A & (1<<RXC0)) );
              return UDR0;
}

von Karl-heinz L. (karl-heinz-l)


Lesenswert?

ich habe mein Problem gelöst, im Datenblatt steht man muss nach dem 
Senden das UDRx lesen. deshalb sieht man bei vielen Implementierungen 
SPI_ReadWrite an einem Stück.
Wenn man mit SPI_Put oder SPI_Get arbeitet, muss im SPI_Put ein warten 
und lesen vom UDRx erfolgen. Diese Daten gebe ich mit einem Flag und 
einer Variable an die SPI_Get Prozedur weiter.

mit dieser kleinen Änderung läuft der Stack von U.Radig auch auf USART 
SPI Mode,  könnte für manche Leute hilfreich sein.
static inline void spi_put( unsigned char value )
{

              /* Wait for empty transmit buffer */
              while ( !( UCSR0A & (1<<UDRE0)) );

              /* Put data into buffer, sends the data */
              UDR0 = value;
              while ( !(UCSR0A & (1<<RXC0)) );
              SendReceive=UDR0; //read data and flag read done to 
spi_get
              SendReceiveFlag=true;
}


static inline unsigned char spi_get(void)
{
              if (SendReceiveFlag==true)
             {
                 SendReceiveFlag=false;
                return SendReceive;
             }

              while ( !(UCSR0A & (1<<RXC0)) );
              return UDR0;
}

von David C. (Gast)


Lesenswert?

Hallo Leute,

ich möchte eine atmega1281 durch USART1 als SPI_Master verwenden. Das 
ist die C Code aus Datasheet:

// Initialisierung SPI_Master (ATMEGA1281)
void USART_Init( unsigned int baud )
{
  UBRR1L = 0;
  /* Setting the XCKn port pin as output, enables master mode. */
  XCK1_DDR |= (1<<XCK1);
  /* Set MSPI mode of operation and SPI data mode 0. */
  UCSR1C = (1<<UMSEL11)|(1<<UMSEL10)|(0<<UCPHA1)|(0<<UCPOL1);
  /* Enable receiver and transmitter. */
  UCSR1B = (1<<RXEN1)|(1<<TXEN1);
  /* Set baud rate. */
  /* IMPORTANT: The Baud Rate must be set after the transmitter is 
enabled*/
  UBRR1L = baud;
}

// Senden der Daten von Master

unsigned char USART_Receive(void)
{
  unsigned char data;
  /* Wait for empty transmit buffer */
  while ( !( UCSR1A & (1<<UDRE1)) );
  /* Put data into buffer, sends the data */
  UDR1 = data;
  /* Wait for data to be received */
  while ( !(UCSR1A & (1<<RXC1)) );
  /* Get and return received data from buffer */
  return UDR1;
}

aber bei der Übersetzung meldet die folgenden Bits als undeclared:
UBRR1L
XCK1_DDR
XCK1
UCSR1C
UMSEL11
UMSEL10
UCPHA1
UCPOL1
UCSR1B
RXEN1
TXEN1
UCSR1A
UDRE1
UDR1
RXC1

Habt ihr sie extra definiert oder gibt eine Header(Include) File, welche 
diese Bits erkennen kann?

Grüße
David

von David C. (Gast)


Lesenswert?

Ich habe schon definiert:
#define UBRR1  _SFR_MEM16   (0xCC)
#define UBRR1L  _SFR_MEM8  (0xCC)
#define UBRR1H  _SFR_MEM8  (0xCD)
#define XCK1_DDR  DDRD
#define XCK1    PD5
#define UCSR1A  _SFR_MEM8  (0xC8)
#define RXC1  7
#define UDRE1  5
#define UCSR1B  _SFR_MEM8  (0xC9)
#define RXEN1  4
#define TXEN1  3
#define UCSR1C  _SFR_MEM8  (0xCA)
#define UMSEL11  7
#define UMSEL10  6
#define UCPOL1  0
#define UDR1   _SFR_MEM8  (0xCE)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.