SPI zwischen ATMeag128L + CC2420

d-roehrig

Neues Mitglied
29. Jan. 2009
7
0
0
Sprachen
Hallo,

ich versuche seit ein paar Tagen die SPI des ATMega128 einzurichten, jedoch ohne Erfolg. Wenn ich die Register des CC2420 auslesen will bekomme ich nur 0xff heraus.

In der SPI Initialisierung habe ich MOSI, SCLK und SS als Ausgang und MISO als Eingang eingerichtet. MSTR, SPE sind auf 1, genauso wie SPR1, damit F_osc/64 gesetzt wird. DORD ist auf MSB!

Anschließend versuche ich durch:

PORTB = (0<<DD_CS);
_delay_ms(50);
SPI_Tx(0x51); // sollte SPDR = 0x0ad2 (MDMCTRL0) zurückliefern
_delay_ms(50);
PORTB = (1<<DD_CS);

das Register MDMCTRL0 anzusprechen.

Habt ihr eine Idee woran es liegen könnte. Ich bin ratlos :confused:

Grüße und danke für eure Hilfe...
Dennis
 
Hallo Dennis,

wenn du 0x51 sendest, erhältst du ja erst einmal den Status zurück, nicht den Ihnalt des Registers, du musst noch weitere Dummy-Bytes senden.

Wie sieht denn deine SPI-Initialisierung und die Routine SPI_Tx aus? Du solltest beim ChipSelect nicht das ganze Portregister beschreiben, sondern nur das ensprechende Bit ändern.

Grüße,
Dirk
 
Hallo,

danke für die schnelle Antwort!

Zuerst eine Frage:

Die Dummy Bytes, wie sehen die aus? Im CC2420 Datenblatt habe ich dazu nichts gefunden oder reicht einfach, wenn ich 0x00 sende, damit das Schieberegister die Daten weitergibt.

Das mit dem Portregister habe ich auch bemerkt und geändert ;-). Mein Code sieht bisher so aus:

Code:
#include <avr/io.h>

#define F_CPU 8388608

#include <util/delay.h>

#define BAUD 9600
#define MYUBRR (F_CPU/16/BAUD-1)

#define DD_CS PB0		//Selektiert den Master ??kontrollieren
#define DD_SCK PB1		//Takt
#define DD_MOSI PB2		//Master Out, Slave In
#define DD_MISO PB3		//Master In, Slave Out
/*
#define CC_FIFO PE5
#define CC_FIFOP PE6
#define CC_CCA PD5
#define CC_SFD PD4
#define CC_RESET PB6 */
#define CC_VREG_EN PB7	//VREG Enable

void USART_Init( unsigned int ubrr )
{  
  /* Set baud rate */
  UBRR0H = (unsigned char)(ubrr>>8);
  UBRR0L = (unsigned char)ubrr;

  /* Enable receiver and transmitter */
  UCSR0B = (1<<TXEN0)|(1<<RXEN0);
  
  /* Set frame format: 8data, 2stop bit */
  UCSR0C = (1<<USBS0)|(3<<UCSZ0);
}

void SPI_Init(void)
{
  // MOSI, SCK, CS ausgang, MISO eingang
  DDRB = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_CS)|(0<<DD_MISO)|(1<<CC_VREG_EN);
  // CC2420 einschalten
  PORTB = (1<<CC_VREG_EN);
  // Master, aktiviere SPI, fck/64, MSB first, SPI mode
  SPCR = (1<<MSTR)|(1<<SPE)|(0<<SPR1)|(0<<SPR0)|(0<<DORD)|(0<<CPOL)|(0<<CPHA);


}

void USART_Tx( unsigned char data )
{
  /* Wait for empty transmit buffer */
  while (!( UCSR0A & (1<<UDRE0)));

  /* Put data into buffer, sends the data */
  UDR0 = data;
}

uint8_t USART_Rx(void)
{
  while (!(UCSR0A & (1<<RXC0)));

  return UDR0;
}

void SPI_Tx(char cData)
{
  PORTB &= (0<<DD_CS);
  _delay_ms(50);

  // starte Übertragung
  SPDR = cData;

  // Übertragung beendet?
  while(!(SPSR & (1<<SPIF)));
}

uint8_t SPI_Rx(void)
{
  PORTB |= (1<<DD_CS);
  _delay_ms(50);

  return SPDR;
}

int main( void )
{
  USART_Init(MYUBRR);
  SPI_Init();

  while (1) {
	
    PORTB |= (1<<PB4)|(1<<PB5);  //LED's an 
    _delay_ms(200);

    SPI_Tx(0x51);
    SPI_Tx(0x00);
    SPI_Tx(0x00);

    USART_Tx(SPI_Rx());

    PORTB &= ~(0<<PB4)|~(0<<PB5);  //LED's an
    _delay_ms(200);

  }
  return 0;
}

Ich hoffe das es nur eine kleinigkeit ist die Fehlt.

Gruß,
Dennis
 
Hallo Dennis,

ich würde etwa folgendermaßen vorgehen (code nicht überprüft/optimiert).



CodeBox C

uint8_t SPI_Tx(uint8_t cData)
{
SPDR = cData;
while(!(SPSR & (1<<SPIF)));
return SPDR;
}


uint16_t SPI_ReceiveReg(uint8_t Address) // empfängt Statusbyte und 2 Datenbyte
{

uint8_t state;
uint16_t data;

PortB &= ~(1<<DD_CS); // CS\ low

// hier ggf. Pause (Größenordnung us)

state = SPI_TX(Address); // eventuell den Status auswerten

data = SPI_TX(0xFF)<<8; // MSB
data = data + SPI_TX(0xFF); // LSB

PortB |= 1<<DD_CS; // CS\ high

return data;

}

// Aufruf :

Data = SPI_ReceiveReg(0x51); // Data ist hier 2Byte breit.


Du müsstest als erstes Byte den Status zurückbekommen. Wenn du die Werte mittels USART-Übertragung zum PC überprüfst, musst du sicher sein, dass die Übertragung richtig funktioniert, ggf. hier mal Testwerte übertragen. Wichtig wäre noch der SPI-Mode (0..3), den stellst du mit den Bits CPOL und CPHA im Register SPCR ein.

Wenn du ein Portbit ändern möchtest, änderst du oft den ganzen Port ...


CodeBox C

PORTB = (1<<CC_VREG_EN);

besser wäre es, wenn du wirklich nur die einzelnen Bits änderst.

Dirk
 
Hallo,

ich habe den Code eingebunden, das Setzen des PORTB geändert und eine 25us Pause eingebunden. Jedoch bekomme ich jetzt nicht mehr 0xff heraus sondern 0x00. Richtig sinnvoll sind die Daten jedoch noch nicht. ;)

Woher bekomme ich den genauen SPI Mode? Ich habe bis jetzt die Timing Diagramme des CC2420 und die des ATMega betrachtet. Sicher bin ich mir da aber noch nicht.

Bin leider nen Anfänger in der Sache... :eek:

Hast du denn sonst noch eine Idee an welchen Sachen das liegen könnte?

Besten dank für deine Bemühungen ;)
 
Hi Dennis,

hmmmm, könntest du deinen aktuellen code bitte nochmal in einen Beitrag stellen, entweder ins Code-Tag oder einfach anhängen.

Dirk
 
Na klar. Kein Thema.

Code:
#include <avr/io.h>

#define F_CPU 8388608

#include <util/delay.h>

#define BAUD 9600
#define MYUBRR (F_CPU/16/BAUD-1)

#define DD_CS PB0		//Selektiert den Master ??kontrollieren
#define DD_SCK PB1		//Takt
#define DD_MOSI PB2		//Master Out, Slave In
#define DD_MISO PB3		//Master In, Slave Out
/*
#define CC_FIFO PE5
#define CC_FIFOP PE6
#define CC_CCA PD5
#define CC_SFD PD4
#define CC_RESET PB6 */
#define CC_VREG_EN PB7	//VREG Enable

void USART_Init( unsigned int ubrr )
{  
  /* Set baud rate */
  UBRR0H = (unsigned char)(ubrr>>8);
  UBRR0L = (unsigned char)ubrr;

  /* Enable receiver and transmitter */
  UCSR0B = (1<<TXEN0)|(1<<RXEN0);
  
  /* Set frame format: 8data, 2stop bit */
  UCSR0C = (1<<USBS0)|(3<<UCSZ0);
}

void SPI_Init(void)
{
  // CC2420 einschalten
  PORTB |= (1<<CC_VREG_EN);
  
  // MOSI, SCK, CS ausgang, MISO eingang
  DDRB = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_CS)|(0<<DD_MISO)|(1<<CC_VREG_EN);

  // Master, aktiviere SPI, fck/4, MSB first, SPI mode
  SPCR = (1<<MSTR)|(1<<SPE)|(0<<SPR1)|(0<<SPR0)|(0<<DORD)|(0<<CPOL)|(1<<CPHA);
}

void USART_Tx( uint8_t data )
{
  /* Wait for empty transmit buffer */
  while (!( UCSR0A & (1<<UDRE0)));

  /* Put data into buffer, sends the data */
  UDR0 = data;
}

uint8_t USART_Rx(void)
{
  while (!(UCSR0A & (1<<RXC0)));

  return UDR0;
}

uint8_t SPI_TxRx(uint8_t cData)
{
  SPDR = cData;
  while(!(SPSR & (1<<SPIF)));
  return SPDR;
}

uint16_t SPI_ReceiveReg(uint8_t Address)  // empfängt Statusbyte und 2 Datenbyte
{
  uint8_t state;
  uint16_t data;

  PORTB &= ~(1<<DD_CS);             // CS\ low

  _delay_us(25);					// hier ggf. Pause (Größenordnung us)

  state = SPI_TxRx(Address);        // eventuell den Status auswerten
  data = SPI_TxRx(0xff)<<8;         // MSB
  data = data + SPI_TxRx(0xff);     // LSB

  PORTB |= 1<<DD_CS;                // CS\ high
  return data;
}

int main( void )
{
  uint16_t d;

  USART_Init(MYUBRR);
  SPI_Init();
  _delay_ms(1000);

//	PORTB |= (1<<PB4)|(1<<PB5);  //LED's an 

    d = SPI_ReceiveReg(0x51);

	USART_Tx((uint8_t)(d>>8));  //MSB
    USART_Tx((uint8_t)d);		//LSB

//	PORTB &= ~(0<<PB4)|~(0<<PB5);  //LED's an

  return 0;
}

Grüße
Dennis
 
Hallo Dennis,

hast du CC_RESET (PB6) an den Transceiver angeschlossen. Du mußt dann PB6 als Ausgang definieren und entprechend einen Reset ausführen, im Prinzip ähnlich wie ChipSelect (PB0).

Ich habe gerade nicht viel Zeit, ich schaue mir das später nochmal genauer an.

Am Ende von main vor return solltest du eine while(1){} Schleife einbauen.

Grüße,
Dirk
 
Jaaaa, endlich funktioniert es ;) Vielen dank für deine Hilfe. Werde jetzt erst mal versuchen den CC2420 selber zu konfigurieren. Muss mich erst mal weiter mit den Registern des Chips beschäftigen.

LG
Dennis
 
Hallo,

ja genau der Reset wars, ich dachte bisher das man den nur benötigt, wenn man die Register zurücksetzen will.
Naja, ich habe heute ein paar Register beschrieben und ausgelesen und bereits die Kanalwahl über eine GUI realisiert. Werde mich am Wochenende ein bisschen damit beschäftigen das RXFIFO auszulesen. Ich habe nämlich noch 2 Crossbow micaz hier, die bereits Daten senden.

Vielleicht hast du ja noch nützliche Links?

Viele Grüße,
Dennis
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)