mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik spi bei xmega


Autor: stromflo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich versuche gerade die HW SPI vom Atxmega zu konfigurieren. Leider 
bekomme ich an den Ausgängen aber keine Signale. Was mach ich falsch?
Wäre super wenn jemand helfen kann. Später möchte ich mit HW SPI ein 
Schieberegister ansteuern.
#include <avr/io.h>
#include <util/delay.h>

#define SPI_MOSI    5     // PE5 (Pin 41) = SPI MOSI
#define SPI_SCK     7     // PE7 (Pin 43) = SPI SCK

void sync_osc(void);
void outputs_Init(void);
void spi_init(void);
void spi_send (unsigned char Byte);


int main(void){
    sync_osc();
    outputs_Init();
    spi_init();


  while(1){
    spi_send(100);

}

}

void sync_osc(void) {
 /*Oscillator auf 32Mhz einstellen*/
 OSC.CTRL |= OSC_RC32MEN_bm;
 /*Wenn Oscillator stabil wird das Flag RC32MRDY
  * gesetzt und 32Mhz können benutzt werden*/
 while (!(OSC.STATUS & OSC_RC32MRDY_bm)) {};
 CCP = CCP_IOREG_gc;
 /*Clock auf 32Mhz einstellen*/
 CLK.CTRL = CLK_SCLKSEL_RC32M_gc;
}

//Ausgänge konfigurieren
void outputs_Init(void)
{
  PORTE.DIRSET  = (1 << SPI_MOSI) | (1 << SPI_SCK);
}

void spi_init(void)
{
  //16Mhz SPI Speed
  SPIE.CTRL =  SPI_MODE_0_gc | SPI_PRESCALER_DIV16_gc | (1<< SPI_CLK2X_bp) |(1<< SPI_MASTER_bp); // 8Mhz
  SPIE.CTRL = (1<< SPI_ENABLE_bp);
  SPIE.INTCTRL = SPI_INTLVL_OFF_gc;
  SPIE.STATUS = 0;

}

void spi_send (unsigned char Byte)
{
  SPIE.DATA = Byte;   //Sendet ein Byte
  while(!(SPIE.STATUS & (1<<SPI_IF_bp))){} //Wartet bis Byte gesendet wurde

}


Gruß Flo

Autor: Christoph (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
  SPIE.CTRL =  SPI_MODE_0_gc | SPI_PRESCALER_DIV16_gc | (1<< SPI_CLK2X_bp) |(1<< SPI_MASTER_bp); // 8Mhz
  SPIE.CTRL = (1<< SPI_ENABLE_bp);

Die zweite Zeile überschreibt alle Einstellungen die Du in der ersten 
Zeile gemacht hast.

Autor: stromflo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

erstmal danke, dass ist natürlich klar und wird ja so auch nicht 
benötigt.... Keine Ahnung wie mir, das reingerutscht ist.

So hat das ganze nun anschließend funktioniert. Allerdings was ich nicht 
verstehe, warum ich keine sauberen Rechtecke auf den Oszi Schirm 
bekomme. Muss ich hierfür noch irgend eine Konfiguration vornehmen?
#include <avr/io.h>
#include <util/delay.h>

#define SPI_MOSI    5     // PE5 (Pin 41) = SPI MOSI
#define SPI_SCK     7     // PE7 (Pin 43) = SPI SCK
#define SPI_SS     4

void sync_osc(void);
void outputs_Init(void);
void spi_init(void);
void spi_send (unsigned char Byte);


int main(void){
    sync_osc();
    outputs_Init();
    spi_init();


  while(1){
    spi_send(100);

}

}

void sync_osc(void) {
 /*Oscillator auf 32Mhz einstellen*/
 OSC.CTRL |= OSC_RC32MEN_bm;
 /*Wenn Oscillator stabil wird das Flag RC32MRDY
  * gesetzt und 32Mhz können benutzt werden*/
 while (!(OSC.STATUS & OSC_RC32MRDY_bm)) {};
 CCP = CCP_IOREG_gc;
 /*Clock auf 32Mhz einstellen*/
 CLK.CTRL = CLK_SCLKSEL_RC32M_gc;
 /* auto kalibierung ein */
 DFLLRC32M.CTRL = DFLL_ENABLE_bm;

}

//Ausgänge konfigurieren
void outputs_Init(void)
{
  PORTE.DIRSET  = (1 << SPI_MOSI) | (1 << SPI_SCK)|(1<<SPI_SS);
}

void spi_init(void)
{
  SPIE.CTRL =  SPI_MODE_0_gc | SPI_PRESCALER_DIV4_gc | (1<< SPI_ENABLE_bp)|(1<< SPI_CLK2X_bp) |(1<< SPI_MASTER_bp); // 8Mhz
  SPIE.INTCTRL = SPI_INTLVL_OFF_gc;
  SPIE.STATUS = 0;

}

void spi_send (unsigned char Byte)
{
  SPIE.DATA = Byte;   //Sendet ein Byte
   while(!(SPIE.STATUS & (1<<SPI_IF_bp))){} //Wartet bis Byte gesendet wurde
}

Autor: stromflo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

hab mal im Datenblatt gestöbert, scheinbar muss ich den USART SPI Modus 
nehmen, wenn ich SPI im Master Betrieb haben möchte und über DMA steuern 
möchte. Der USART Betrieb ohne DMA hat schon mal funktioniert. Nur 
stecke ich jetzt irgendwie fest. Kenn mich mit der ganzen DMA Geschichte 
noch nicht so gut aus.... Meine Vorstellung war es, dass ich Bytes aus 
einem Puffer über SPI später an Schieberegister schicken kann. Im moment 
hab ich nur ein Oszi dran :)

Es wäre wirklich super wenn mir da jemand helfen kann. Vielleicht liegt 
es auch an der Triggersource, da bin ich mir nicht ganz im klaren....

#include <avr/io.h>
#include <util/delay.h>

#define SCK  5  //RxD
#define MOSI 7  //TxD
#define SS 4  // Als normaler Ausgang nehmen

void port_init(void);
void spi_init(void);
void dma_init(void);
void start_dma(void);
void sync_osc(void);

volatile uint8_t Buffer[255];
uint8_t i;

int main(void){
  sync_osc();
  port_init();
  spi_init();
  dma_init();


  for (i = 0; i < 255 ; i++) {
      Buffer[i] = i;}

     start_dma();

  while(1){


  }
}

void port_init(void){
   // CS, CLK und MOSI als Ausgänge
   PORTE.DIRSET = (1 << MOSI) | (1 << SCK) | (1 << SS);
}

void spi_init(void){
   //Baudrate vorgeben 100khz
   USARTE1.BAUDCTRLA = 159;
   USARTE1.BAUDCTRLB = 0;

   // MSB zuerst, SPI Modus
   USARTE1.CTRLC = USART_CMODE_MSPI_gc;
   //CTRLA auf 0 setzen
   USARTE1.CTRLA = 0;
   // Aktivieren TX, da nur geschrieben werden soll
   USARTE1.CTRLB = USART_TXEN_bm;

}

void dma_init(void){

   DMA.CH0.ADDRCTRL =   DMA_CH_SRCRELOAD_NONE_gc | DMA_CH_SRCDIR_FIXED_gc
   | DMA_CH_DESTRELOAD_NONE_gc | DMA_CH_DESTDIR_FIXED_gc;

    // Triggerung wenn Puffer leer ist
    DMA.CH0.TRIGSRC = DMA_CH_TRIGSRC_USARTE1_DRE_gc;

    DMA.CH0.DESTADDR0 = ((uint32_t) &USARTE1.DATA >>0*8)&0xFF;
    DMA.CH0.DESTADDR1 = ((uint32_t) &USARTE1.DATA >>1*8)&0xFF;
    DMA.CH0.DESTADDR2 = ((uint32_t) &USARTE1.DATA >>2*8)&0xFF;
}

void start_dma(void){

  //Datenpuffer 256
  DMA.CH0.TRFCNT = 256;

   DMA.CH0.SRCADDR0  =(((uint32_t)(&Buffer))>>0*8) & 0xFF;
   DMA.CH0.SRCADDR1  =(((uint32_t)(&Buffer))>>1*8) & 0xFF;
   DMA.CH0.SRCADDR2  =(((uint32_t)(&Buffer))>>2*8) & 0xFF;
      DMA.CH0.CTRLA = DMA_CH_ENABLE_bm | DMA_CH_SINGLE_bm;

}

void sync_osc(void) {
 /*Oscillator auf 32Mhz einstellen*/
 OSC.CTRL |= OSC_RC32MEN_bm;
 /*Wenn Oscillator stabil wird das Flag RC32MRDY
  * gesetzt und 32Mhz können benutzt werden*/
 while (!(OSC.STATUS & OSC_RC32MRDY_bm)) {};
 CCP = CCP_IOREG_gc;
 /*Clock auf 32Mhz einstellen*/
 CLK.CTRL = CLK_SCLKSEL_RC32M_gc;
 /* auto kalibierung ein */
 DFLLRC32M.CTRL = DFLL_ENABLE_bm;

}

Autor: Florian G. (stromflo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

so hab mittlerweile auch geschafft Bytes über DMA---> SPI zu senden.
Nun soll es aber so laufen, dass die Bytes übertragen werden und 
anschließend die DMA nach 500µs neu gestartet wird.

Mein erster Ansatz war, das ganze mit DMA_CH0TRNFIF_vect zu machen.
Irgendwie haut es aber nicht hin.

Hab dann den Repeat Modus auskommentiert, aber es wurde dann nur nach 
Reset übertragen und es erfolgte auch kein Neustart der dma.

Hat einer eine Idee wie ich es schaff, dass die DMA die 256 Bytes 
überträgt, dann einen Interrupt auslöst und die DMA nach einer Wartezeit 
wieder neu startet?

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>


// Pins für SPI definieren
#define SCK  5
#define MOSI 7
#define SS 4  // Als normaler Ausgang nehmen

//Funktion für Port Konfiguration
void port_init(void);
//Funktion für USART SPI Mode Konfiguration
void spi_init(void);
//DMA Konfiguration
void dma_init(void);
//DMA Start
void start_dma(void);
//32Mhz clock
void sync_osc(void);
//Interrupt
void interrupt_init(void);


uint8_t Buffer[255]; //Buffer
uint8_t i; //Hilfsvariable

int main(void){
  //clock initialisieren
  sync_osc();
  //clock initialisieren
  port_init();
  //clock initialisieren
  spi_init();
  interrupt_init();
  //DMA initialisieren
    dma_init();


//Buffer mit Daten füllen
  for (i = 0; i < 255 ; i++) {
      Buffer[i] = i;}
        start_dma();



//Hauptschleife
  while(1){

  //USARTE1.DATA = 255;
  //while (! (USARTE1.STATUS & USART_DREIF_bm));

  }
}

//Port Initialisierung
void port_init(void){
   // CS, CLK und MOSI als Ausgänge
   PORTE.DIRSET = (1 << MOSI) | (1 << SCK) | (1 << SS);
}

void spi_init(void){
   // 100Khz SPI Frequenz 
   USARTE1.BAUDCTRLA = 159;
   USARTE1.BAUDCTRLB = 0;

   // Frameformat (MSB first), SPI Mode 0
   USARTE1.CTRLC = USART_CMODE_MSPI_gc;

   USARTE1.CTRLA = 0;

   // TX aktivieren
   USARTE1.CTRLB = USART_TXEN_bm;
}

void dma_init(void){
  //DMA aktivieren
  DMA.CTRL = DMA_CH_ENABLE_bm;
    //Modus Transaktion, increase und decrease, Burst
  DMA.CH0.ADDRCTRL = DMA_CH_SRCRELOAD_TRANSACTION_gc | DMA_CH_SRCDIR_INC_gc
   | DMA_CH_DESTRELOAD_BURST_gc | DMA_CH_DESTDIR_INC_gc;

  // Trigger Source ist USARTE1 (SPI). Triggerung wenn der Datenpuffer leer ist.
  DMA.CH0.TRIGSRC = DMA_CH_TRIGSRC_USARTE1_DRE_gc;

  //8Bit Quelle
   DMA.CH0.SRCADDR0  =(((uint32_t)(&Buffer))>>0*8) & 0xFF;
   DMA.CH0.SRCADDR1  =(((uint32_t)(&Buffer))>>1*8) & 0xFF;
   DMA.CH0.SRCADDR2  =(((uint32_t)(&Buffer))>>2*8) & 0xFF;

   //8Bit Übertragung an SPI
   DMA.CH0.DESTADDR0 = ((uint32_t) &USARTE1.DATA >>0*8)&0xFF;
   DMA.CH0.DESTADDR1 = ((uint32_t) &USARTE1.DATA >>1*8)&0xFF;
   DMA.CH0.DESTADDR2 = ((uint32_t) &USARTE1.DATA >>2*8)&0xFF;

}

//DMA Start
void start_dma(void){

   //Datenpuffer 256
   DMA.CH0.TRFCNT = 256;
     // DMA CH0 aktivieren (Takt)
   DMA.CH0.CTRLA = DMA_CH_ENABLE_bm | DMA_CH_REPEAT_bm|DMA_CH_SINGLE_bm;
   //DMA.CH0.CTRLA = 0xA4;
}

//clock initialisieren
void sync_osc(void) {
 /*Oscillator auf 32Mhz einstellen*/
 OSC.CTRL |= OSC_RC32MEN_bm;
 /*Wenn Oscillator stabil wird das Flag RC32MRDY
  * gesetzt und 32Mhz können benutzt werden*/
 while (!(OSC.STATUS & OSC_RC32MRDY_bm)) {};
 CCP = CCP_IOREG_gc;
 /*Clock auf 32Mhz einstellen*/
 CLK.CTRL = CLK_SCLKSEL_RC32M_gc;
 /* auto kalibierung ein */
 DFLLRC32M.CTRL = DFLL_ENABLE_bm;

}

void interrupt_init(void){
  // Globale Interruptfreigabe
  sei();
  //Interrupts (Highlevel,Mediumlevel und Lowlevel freigeben)
  PMIC.CTRL |= PMIC_HILVLEN_bm |PMIC_MEDLVLEN_bm|PMIC_LOLVLEN_bm;
}


ISR (DMA_CH0TRNFIF_vect){
  _delay_ms(200);
    start_dma();
}

Gruß Flo

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.