Forum: Mikrocontroller und Digitale Elektronik Verständnisprobleme mit SPI, STM32, Interrupt, wie Senden/Empfangen?


von Alex (Gast)


Angehängte Dateien:

Lesenswert?

Hi

Ich lese mich seit gestern in die SPI Kommunikation ein und verwendet 
das STM32F407 discovery board dazu.
Macht es Sinn, SPI über Interrupts laufen zu lassen? Oder kommt es auf 
die Situation drauf an? Normalerweise möchte ich blockende Schleifen 
nämlich vermeiden.

Allerdings sehe ich viele Tutorials, in denen der Interrupt nicht 
verwendet wird mit dem Argument, dass 8bits bei z.B. 8MHz SPI_Clock in 
Nullkommanichts gesendet wurden und Interrupts overkill seien.

Wie ist die richtige Vorgehensweise? Interrupt ja oder nein? Aktueller 
Stand bei mir ist, dass ich die Zahl 100 vom STM32 senden und mittels 
Logic Analyzer auch die Datenbits richtig lesen kann.

Ist die von mir implementierte Vorgehensweise richtig, oder wie sollte 
man SPI idealerweise implementieren?

PS: Ich weiß, dass meine SPIInit() Funktion mehr als unschön ist, und 
man das wesentlich überschaulicher/eleganter schreiben kann. Allerdings 
hat mir diese Schreibweise mehr als einmal beim Debugging geholfen, 
weshalb ich zunächst einmal diese Schreibweise fortführe.

Vielen Dank für eure Hilfe.
Gruß,
1
#if !defined(__SOFT_FP__) && defined(__ARM_FP)
2
  #warning "FPU is not initialized, but the project is compiling for an FPU. Please initialize the FPU before use."
3
#endif
4
5
#include "stm32f4xx.h"
6
7
void funcSPIInit();
8
void funcIntInit();
9
10
uint8_t TXvariable = 100;
11
//char testvar[] = "Alex";
12
13
int main(void)
14
{
15
  funcIntInit();
16
  funcSPIInit();
17
18
  for(;;)
19
  {
20
    while(SPI1->SR & SPI_SR_BSY)
21
    {
22
23
    }
24
    for(int i = 0; i<10000; i++)
25
    {
26
      for(int k = 0; k<10000; k++)
27
      {
28
        SPI1->CR2 |= (1<<SPI_CR2_TXEIE_Pos);      // TX buffer empty interrupt request enabled
29
        SPI1->CR2 |= (1<<SPI_CR2_RXNEIE_Pos);      // RX buffer full interrupt request enabled
30
      }
31
    }
32
  }
33
}
34
35
void funcIntInit()
36
{
37
  // Initializes the interrupt
38
  __NVIC_EnableIRQ(SPI1_IRQn);
39
}
40
41
void funcSPIInit()
42
{
43
  // Enable bus for SPI1
44
  RCC->APB2ENR |= (1<<RCC_APB2ENR_SPI1EN_Pos);  // SPI1 bus enable
45
  // Enable bus for GPIOA
46
  RCC->AHB1ENR |= (1<<RCC_AHB1ENR_GPIOAEN_Pos);  // GPIOA bus enable
47
  // Set GPIO to AF5
48
  GPIOA->MODER |= (2 << GPIO_MODER_MODER4_Pos);  // PA4 to AF
49
  GPIOA->AFR[0] |= (0x5<<GPIO_AFRL_AFSEL4_Pos);  // PA4 to AF5 [0101]: SPI1_NSS
50
  GPIOA->OTYPER &= ~(1<<GPIO_OTYPER_OT4_Pos);    // PA4 to Push pull output
51
  GPIOA->PUPDR &= ~(0x3UL << GPIO_PUPDR_PUPD4_Pos);  // PA4 no pull up_down resistor
52
  GPIOA->OSPEEDR &= ~(0x3UL << GPIO_OSPEEDR_OSPEED4_Pos);  // PA4 low speed
53
  GPIOA->MODER |= (2 << GPIO_MODER_MODER5_Pos);  // PA5 to AF
54
  GPIOA->AFR[0] |= (0x5<<GPIO_AFRL_AFSEL5_Pos);  // PA5 to AF5 [0101]: SPI1_SCK
55
  GPIOA->OTYPER &= ~(1<<GPIO_OTYPER_OT5_Pos);    // PA5 to Push pull output
56
  GPIOA->PUPDR &= ~(0x3UL << GPIO_PUPDR_PUPD5_Pos);  // PA5 no pull up_down resistor
57
  GPIOA->OSPEEDR &= ~(0x3UL << GPIO_OSPEEDR_OSPEED5_Pos);  // PA5 low speed
58
  GPIOA->MODER |= (2 << GPIO_MODER_MODER6_Pos);  // PA6 to AF
59
  GPIOA->AFR[0] |= (0x5<<GPIO_AFRL_AFSEL6_Pos);  // PA6 to AF5 [0101]: SPI1_MISO
60
  GPIOA->OTYPER &= ~(1<<GPIO_OTYPER_OT6_Pos);    // PA6 to Push pull output
61
  GPIOA->PUPDR &= ~(0x3UL << GPIO_PUPDR_PUPD6_Pos);  // PA6 no pull up_down resistor
62
  GPIOA->OSPEEDR &= ~(0x3UL << GPIO_OSPEEDR_OSPEED6_Pos);  // PA6 low speed
63
  GPIOA->MODER |= (2 << GPIO_MODER_MODER7_Pos);  // PA7 to AF
64
  GPIOA->AFR[0] |= (0x5<<GPIO_AFRL_AFSEL7_Pos);  // PA7 to AF5 [0101]: SPI1_MOSI
65
  GPIOA->OTYPER &= ~(1<<GPIO_OTYPER_OT7_Pos);    // PA7 to Push pull output
66
  GPIOA->PUPDR &= ~(0x3UL << GPIO_PUPDR_PUPD7_Pos);  // PA7 no pull up_down resistor
67
  GPIOA->OSPEEDR &= ~(0x3UL << GPIO_OSPEEDR_OSPEED7_Pos);  // PA7 low speed
68
69
  // Configure SPI
70
  SPI1->CR1 &= ~(0x7UL << SPI_CR1_BR_Pos);    // Sets BR to 111. SPI runs with 16MHz/2=8MHz
71
  SPI1->CR1 |= (1<<SPI_CR1_CPHA_Pos);        // CPHA: 2nd clock transition
72
  SPI1->CR1 |= (1<<SPI_CR1_CPOL_Pos);        // CPOL: 1 when idle
73
  SPI1->CR1 &= ~(1<<SPI_CR1_DFF_Pos);        // 8bit
74
  SPI1->CR1 &= ~(1<<SPI_CR1_LSBFIRST_Pos);    // MSB first
75
  SPI1->CR1 &= ~(1<<SPI_CR1_SSM_Pos);        // Software slave management disabled
76
  SPI1->CR2 |= (1<<SPI_CR2_SSOE_Pos);        // SSOE enable
77
  SPI1->CR2 &= ~(1<<SPI_CR2_FRF_Pos);        // Motorola Mode
78
  SPI1->CR1 |= (1<<SPI_CR1_MSTR_Pos);        // Master configuration
79
  SPI1->CR1 &= ~(1<<SPI_CR1_BIDIMODE_Pos);    // Full duplex
80
  SPI1->CR1 &= ~(1<<SPI_CR1_RXONLY_Pos);      // Transmit and Receive
81
  SPI1->CR1 |= (1<<SPI_CR1_SPE_Pos);        // Peripheral enabled
82
}
83
84
void SPI1_IRQHandler()
85
{
86
    //Todo
87
  SPI1->DR = TXvariable;
88
  SPI1->CR2 &= ~(1<<SPI_CR2_TXEIE_Pos);      // TX buffer empty interrupt request disabled
89
90
}

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

SPI ist durchaus so schnell einstellbar, dass IRQ Betrieb keinen 
wirklichen Sinn ergibt.
Wenn du ein "fire and forget" mit dem SPI machen willst und nicht warten 
willst -> DMA.
Das gibt am Ende nur ein "DMA hat fertig" IRQ.

Ansonsten empfehle ich dir für Pins eine Initfunktion zu schreiben, dann 
musste das nicht imemr per hand machen (was auch fehlerträchtig ist)

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.