Forum: Mikrocontroller und Digitale Elektronik spi bei xmega


von stromflo (Gast)


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.
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
#define SPI_MOSI    5     // PE5 (Pin 41) = SPI MOSI
5
#define SPI_SCK     7     // PE7 (Pin 43) = SPI SCK
6
7
void sync_osc(void);
8
void outputs_Init(void);
9
void spi_init(void);
10
void spi_send (unsigned char Byte);
11
12
13
int main(void){
14
    sync_osc();
15
    outputs_Init();
16
    spi_init();
17
18
19
  while(1){
20
    spi_send(100);
21
22
}
23
24
}
25
26
void sync_osc(void) {
27
 /*Oscillator auf 32Mhz einstellen*/
28
 OSC.CTRL |= OSC_RC32MEN_bm;
29
 /*Wenn Oscillator stabil wird das Flag RC32MRDY
30
  * gesetzt und 32Mhz können benutzt werden*/
31
 while (!(OSC.STATUS & OSC_RC32MRDY_bm)) {};
32
 CCP = CCP_IOREG_gc;
33
 /*Clock auf 32Mhz einstellen*/
34
 CLK.CTRL = CLK_SCLKSEL_RC32M_gc;
35
}
36
37
//Ausgänge konfigurieren
38
void outputs_Init(void)
39
{
40
  PORTE.DIRSET  = (1 << SPI_MOSI) | (1 << SPI_SCK);
41
}
42
43
void spi_init(void)
44
{
45
  //16Mhz SPI Speed
46
  SPIE.CTRL =  SPI_MODE_0_gc | SPI_PRESCALER_DIV16_gc | (1<< SPI_CLK2X_bp) |(1<< SPI_MASTER_bp); // 8Mhz
47
  SPIE.CTRL = (1<< SPI_ENABLE_bp);
48
  SPIE.INTCTRL = SPI_INTLVL_OFF_gc;
49
  SPIE.STATUS = 0;
50
51
}
52
53
void spi_send (unsigned char Byte)
54
{
55
  SPIE.DATA = Byte;   //Sendet ein Byte
56
  while(!(SPIE.STATUS & (1<<SPI_IF_bp))){} //Wartet bis Byte gesendet wurde
57
58
}

Gruß Flo

von Christoph (Gast)


Lesenswert?

1
  SPIE.CTRL =  SPI_MODE_0_gc | SPI_PRESCALER_DIV16_gc | (1<< SPI_CLK2X_bp) |(1<< SPI_MASTER_bp); // 8Mhz
2
  SPIE.CTRL = (1<< SPI_ENABLE_bp);

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

von stromflo (Gast)


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?
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
#define SPI_MOSI    5     // PE5 (Pin 41) = SPI MOSI
5
#define SPI_SCK     7     // PE7 (Pin 43) = SPI SCK
6
#define SPI_SS     4
7
8
void sync_osc(void);
9
void outputs_Init(void);
10
void spi_init(void);
11
void spi_send (unsigned char Byte);
12
13
14
int main(void){
15
    sync_osc();
16
    outputs_Init();
17
    spi_init();
18
19
20
  while(1){
21
    spi_send(100);
22
23
}
24
25
}
26
27
void sync_osc(void) {
28
 /*Oscillator auf 32Mhz einstellen*/
29
 OSC.CTRL |= OSC_RC32MEN_bm;
30
 /*Wenn Oscillator stabil wird das Flag RC32MRDY
31
  * gesetzt und 32Mhz können benutzt werden*/
32
 while (!(OSC.STATUS & OSC_RC32MRDY_bm)) {};
33
 CCP = CCP_IOREG_gc;
34
 /*Clock auf 32Mhz einstellen*/
35
 CLK.CTRL = CLK_SCLKSEL_RC32M_gc;
36
 /* auto kalibierung ein */
37
 DFLLRC32M.CTRL = DFLL_ENABLE_bm;
38
39
}
40
41
//Ausgänge konfigurieren
42
void outputs_Init(void)
43
{
44
  PORTE.DIRSET  = (1 << SPI_MOSI) | (1 << SPI_SCK)|(1<<SPI_SS);
45
}
46
47
void spi_init(void)
48
{
49
  SPIE.CTRL =  SPI_MODE_0_gc | SPI_PRESCALER_DIV4_gc | (1<< SPI_ENABLE_bp)|(1<< SPI_CLK2X_bp) |(1<< SPI_MASTER_bp); // 8Mhz
50
  SPIE.INTCTRL = SPI_INTLVL_OFF_gc;
51
  SPIE.STATUS = 0;
52
53
}
54
55
void spi_send (unsigned char Byte)
56
{
57
  SPIE.DATA = Byte;   //Sendet ein Byte
58
   while(!(SPIE.STATUS & (1<<SPI_IF_bp))){} //Wartet bis Byte gesendet wurde
59
}

von stromflo (Gast)


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....

1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
#define SCK  5  //RxD
5
#define MOSI 7  //TxD
6
#define SS 4  // Als normaler Ausgang nehmen
7
8
void port_init(void);
9
void spi_init(void);
10
void dma_init(void);
11
void start_dma(void);
12
void sync_osc(void);
13
14
volatile uint8_t Buffer[255];
15
uint8_t i;
16
17
int main(void){
18
  sync_osc();
19
  port_init();
20
  spi_init();
21
  dma_init();
22
23
24
  for (i = 0; i < 255 ; i++) {
25
      Buffer[i] = i;}
26
27
     start_dma();
28
29
  while(1){
30
31
32
  }
33
}
34
35
void port_init(void){
36
   // CS, CLK und MOSI als Ausgänge
37
   PORTE.DIRSET = (1 << MOSI) | (1 << SCK) | (1 << SS);
38
}
39
40
void spi_init(void){
41
   //Baudrate vorgeben 100khz
42
   USARTE1.BAUDCTRLA = 159;
43
   USARTE1.BAUDCTRLB = 0;
44
45
   // MSB zuerst, SPI Modus
46
   USARTE1.CTRLC = USART_CMODE_MSPI_gc;
47
   //CTRLA auf 0 setzen
48
   USARTE1.CTRLA = 0;
49
   // Aktivieren TX, da nur geschrieben werden soll
50
   USARTE1.CTRLB = USART_TXEN_bm;
51
52
}
53
54
void dma_init(void){
55
56
   DMA.CH0.ADDRCTRL =   DMA_CH_SRCRELOAD_NONE_gc | DMA_CH_SRCDIR_FIXED_gc
57
   | DMA_CH_DESTRELOAD_NONE_gc | DMA_CH_DESTDIR_FIXED_gc;
58
59
    // Triggerung wenn Puffer leer ist
60
    DMA.CH0.TRIGSRC = DMA_CH_TRIGSRC_USARTE1_DRE_gc;
61
62
    DMA.CH0.DESTADDR0 = ((uint32_t) &USARTE1.DATA >>0*8)&0xFF;
63
    DMA.CH0.DESTADDR1 = ((uint32_t) &USARTE1.DATA >>1*8)&0xFF;
64
    DMA.CH0.DESTADDR2 = ((uint32_t) &USARTE1.DATA >>2*8)&0xFF;
65
}
66
67
void start_dma(void){
68
69
  //Datenpuffer 256
70
  DMA.CH0.TRFCNT = 256;
71
72
   DMA.CH0.SRCADDR0  =(((uint32_t)(&Buffer))>>0*8) & 0xFF;
73
   DMA.CH0.SRCADDR1  =(((uint32_t)(&Buffer))>>1*8) & 0xFF;
74
   DMA.CH0.SRCADDR2  =(((uint32_t)(&Buffer))>>2*8) & 0xFF;
75
      DMA.CH0.CTRLA = DMA_CH_ENABLE_bm | DMA_CH_SINGLE_bm;
76
77
}
78
79
void sync_osc(void) {
80
 /*Oscillator auf 32Mhz einstellen*/
81
 OSC.CTRL |= OSC_RC32MEN_bm;
82
 /*Wenn Oscillator stabil wird das Flag RC32MRDY
83
  * gesetzt und 32Mhz können benutzt werden*/
84
 while (!(OSC.STATUS & OSC_RC32MRDY_bm)) {};
85
 CCP = CCP_IOREG_gc;
86
 /*Clock auf 32Mhz einstellen*/
87
 CLK.CTRL = CLK_SCLKSEL_RC32M_gc;
88
 /* auto kalibierung ein */
89
 DFLLRC32M.CTRL = DFLL_ENABLE_bm;
90
91
}

von Florian G. (stromflo)


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?

1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <avr/interrupt.h>
4
5
6
// Pins für SPI definieren
7
#define SCK  5
8
#define MOSI 7
9
#define SS 4  // Als normaler Ausgang nehmen
10
11
//Funktion für Port Konfiguration
12
void port_init(void);
13
//Funktion für USART SPI Mode Konfiguration
14
void spi_init(void);
15
//DMA Konfiguration
16
void dma_init(void);
17
//DMA Start
18
void start_dma(void);
19
//32Mhz clock
20
void sync_osc(void);
21
//Interrupt
22
void interrupt_init(void);
23
24
25
uint8_t Buffer[255]; //Buffer
26
uint8_t i; //Hilfsvariable
27
28
int main(void){
29
  //clock initialisieren
30
  sync_osc();
31
  //clock initialisieren
32
  port_init();
33
  //clock initialisieren
34
  spi_init();
35
  interrupt_init();
36
  //DMA initialisieren
37
    dma_init();
38
39
40
//Buffer mit Daten füllen
41
  for (i = 0; i < 255 ; i++) {
42
      Buffer[i] = i;}
43
        start_dma();
44
45
46
47
//Hauptschleife
48
  while(1){
49
50
  //USARTE1.DATA = 255;
51
  //while (! (USARTE1.STATUS & USART_DREIF_bm));
52
53
  }
54
}
55
56
//Port Initialisierung
57
void port_init(void){
58
   // CS, CLK und MOSI als Ausgänge
59
   PORTE.DIRSET = (1 << MOSI) | (1 << SCK) | (1 << SS);
60
}
61
62
void spi_init(void){
63
   // 100Khz SPI Frequenz 
64
   USARTE1.BAUDCTRLA = 159;
65
   USARTE1.BAUDCTRLB = 0;
66
67
   // Frameformat (MSB first), SPI Mode 0
68
   USARTE1.CTRLC = USART_CMODE_MSPI_gc;
69
70
   USARTE1.CTRLA = 0;
71
72
   // TX aktivieren
73
   USARTE1.CTRLB = USART_TXEN_bm;
74
}
75
76
void dma_init(void){
77
  //DMA aktivieren
78
  DMA.CTRL = DMA_CH_ENABLE_bm;
79
    //Modus Transaktion, increase und decrease, Burst
80
  DMA.CH0.ADDRCTRL = DMA_CH_SRCRELOAD_TRANSACTION_gc | DMA_CH_SRCDIR_INC_gc
81
   | DMA_CH_DESTRELOAD_BURST_gc | DMA_CH_DESTDIR_INC_gc;
82
83
  // Trigger Source ist USARTE1 (SPI). Triggerung wenn der Datenpuffer leer ist.
84
  DMA.CH0.TRIGSRC = DMA_CH_TRIGSRC_USARTE1_DRE_gc;
85
86
  //8Bit Quelle
87
   DMA.CH0.SRCADDR0  =(((uint32_t)(&Buffer))>>0*8) & 0xFF;
88
   DMA.CH0.SRCADDR1  =(((uint32_t)(&Buffer))>>1*8) & 0xFF;
89
   DMA.CH0.SRCADDR2  =(((uint32_t)(&Buffer))>>2*8) & 0xFF;
90
91
   //8Bit Übertragung an SPI
92
   DMA.CH0.DESTADDR0 = ((uint32_t) &USARTE1.DATA >>0*8)&0xFF;
93
   DMA.CH0.DESTADDR1 = ((uint32_t) &USARTE1.DATA >>1*8)&0xFF;
94
   DMA.CH0.DESTADDR2 = ((uint32_t) &USARTE1.DATA >>2*8)&0xFF;
95
96
}
97
98
//DMA Start
99
void start_dma(void){
100
101
   //Datenpuffer 256
102
   DMA.CH0.TRFCNT = 256;
103
     // DMA CH0 aktivieren (Takt)
104
   DMA.CH0.CTRLA = DMA_CH_ENABLE_bm | DMA_CH_REPEAT_bm|DMA_CH_SINGLE_bm;
105
   //DMA.CH0.CTRLA = 0xA4;
106
}
107
108
//clock initialisieren
109
void sync_osc(void) {
110
 /*Oscillator auf 32Mhz einstellen*/
111
 OSC.CTRL |= OSC_RC32MEN_bm;
112
 /*Wenn Oscillator stabil wird das Flag RC32MRDY
113
  * gesetzt und 32Mhz können benutzt werden*/
114
 while (!(OSC.STATUS & OSC_RC32MRDY_bm)) {};
115
 CCP = CCP_IOREG_gc;
116
 /*Clock auf 32Mhz einstellen*/
117
 CLK.CTRL = CLK_SCLKSEL_RC32M_gc;
118
 /* auto kalibierung ein */
119
 DFLLRC32M.CTRL = DFLL_ENABLE_bm;
120
121
}
122
123
void interrupt_init(void){
124
  // Globale Interruptfreigabe
125
  sei();
126
  //Interrupts (Highlevel,Mediumlevel und Lowlevel freigeben)
127
  PMIC.CTRL |= PMIC_HILVLEN_bm |PMIC_MEDLVLEN_bm|PMIC_LOLVLEN_bm;
128
}
129
130
131
ISR (DMA_CH0TRNFIF_vect){
132
  _delay_ms(200);
133
    start_dma();
134
}

Gruß Flo

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.