Forum: Mikrocontroller und Digitale Elektronik STM32f3 8bit SPI DMA Problem


von Alex R. (edge0xc)


Lesenswert?

Hallo Leute,
ich habe ein sehr merkwürdiges Problem mit meinem SPI Code. Er läuft mit 
16bit perfekt und ohne probleme. da ich ein modul habe, das 8bit SPI 
braucht, wollte ich das ganze mal umstellen. für die ersten tests habe 
ich einfach MISO und MOSI gebürckt. leider wird der DMA TC Interrupt 
nicht mehr ausgelöst. könnt ihr mal drüberschauen? ich habe eigentlich 
nur die datengröße von 16 auf 8 bit gesenkt.

LG
1
#define BUFFER_SIZE              1
2
uint8_t SPIBufferRX=0;
3
uint8_t SPIBufferTX=0b11111111;
4
5
6
/**
7
 * @brief  Init SPI2 module for DMA transfers
8
 * @param  none
9
 * @retval  none
10
 */
11
void init_SPI_DMA(void){
12
  GPIO_InitTypeDef GPIO_InitStructure;
13
  NVIC_InitTypeDef NVIC_InitStructure;
14
  SPI_InitTypeDef SPI_InitStructure;
15
  DMA_InitTypeDef DMA_InitStructure;
16
17
  // Enable clocks
18
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
19
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
20
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
21
22
  // GPIO settings
23
  GPIO_StructInit(&GPIO_InitStructure);
24
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
25
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
26
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
27
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
28
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
29
  GPIO_Init(GPIOA, &GPIO_InitStructure);
30
31
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_5);
32
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_5);
33
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_5);
34
35
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
36
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
37
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
38
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
39
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
40
  GPIO_Init(GPIOA, &GPIO_InitStructure);
41
42
  GPIO_SetBits(GPIOA, GPIO_Pin_4);        // Set SS pin
43
44
  // Init SPI
45
  SPI_StructInit(&SPI_InitStructure);
46
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
47
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
48
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
49
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
50
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
51
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
52
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;
53
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//MSB
54
  SPI_InitStructure.SPI_CRCPolynomial = 0;
55
  SPI_Init(SPI1, &SPI_InitStructure);
56
57
  // DMA Channel 4 - SPI RX
58
  DMA_StructInit(&DMA_InitStructure);                                //SPI2 Tx DMA is DMA1/Stream4/Channel0
59
  DMA_InitStructure.DMA_PeripheralBaseAddr  = (uint32_t)&(SPI1->DR);             //Set the SPI2 Tx
60
  DMA_InitStructure.DMA_MemoryBaseAddr  = (uint32_t)&SPIBufferRX;                //Set the memory location
61
  DMA_InitStructure.DMA_DIR  = DMA_DIR_PeripheralSRC;                       //Sending data from memory to the peripheral's Tx register
62
  DMA_InitStructure.DMA_BufferSize  = BUFFER_SIZE;                              //Define the number of bytes to send
63
  DMA_InitStructure.DMA_PeripheralInc  = DMA_PeripheralInc_Disable;             //Don't increment the peripheral 'memory'
64
  DMA_InitStructure.DMA_MemoryInc  = DMA_MemoryInc_Disable;                        //Increment the memory location
65
  DMA_InitStructure.DMA_PeripheralDataSize  = DMA_PeripheralDataSize_Byte;    //Byte size memory transfers
66
  DMA_InitStructure.DMA_MemoryDataSize  = DMA_MemoryDataSize_Byte;           //Byte size memory transfers
67
  DMA_InitStructure.DMA_Mode  = DMA_Mode_Normal;                                   //Normal mode (not circular)
68
  DMA_InitStructure.DMA_Priority  = DMA_Priority_High; //Priority is high to avoid saturating the FIFO since we are in direct mode
69
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
70
  DMA_Init(DMA1_Channel2, &DMA_InitStructure);
71
  DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE);
72
73
  // DMA Channel 5 - SPI TX                             //SPI2 Tx DMA is DMA1/Stream4/Channel0
74
  DMA_InitStructure.DMA_PeripheralBaseAddr  = (uint32_t)&(SPI1->DR);             //Set the SPI2 Tx
75
  DMA_InitStructure.DMA_MemoryBaseAddr  = (uint32_t)&SPIBufferTX;                 //Set the memory location
76
  DMA_InitStructure.DMA_DIR  = DMA_DIR_PeripheralDST;                      //Sending data from memory to the peripheral's Tx register
77
  DMA_InitStructure.DMA_BufferSize  = BUFFER_SIZE;                              //Define the number of bytes to send
78
  DMA_InitStructure.DMA_PeripheralInc  = DMA_PeripheralInc_Disable;             //Don't increment the peripheral 'memory'
79
  DMA_InitStructure.DMA_MemoryInc  = DMA_MemoryInc_Disable;                        //Increment the memory location
80
  DMA_InitStructure.DMA_PeripheralDataSize  = DMA_PeripheralDataSize_Byte;    //Byte size memory transfers
81
  DMA_InitStructure.DMA_MemoryDataSize  = DMA_MemoryDataSize_Byte;           //Byte size memory transfers
82
  DMA_InitStructure.DMA_Mode  = DMA_Mode_Normal;                                 //Normal mode (not circular)
83
  DMA_InitStructure.DMA_Priority  = DMA_Priority_High;                           //Priority is high to avoid saturating the FIFO since we are in direct mode
84
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
85
  DMA_Init(DMA1_Channel3, &DMA_InitStructure);
86
  DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE);
87
88
  DMA_ClearITPendingBit(DMA1_IT_TC2);
89
  DMA_ClearITPendingBit(DMA1_IT_TC3);
90
91
  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel3_IRQn;
92
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
93
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
94
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
95
  NVIC_Init(&NVIC_InitStructure);
96
97
98
  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_IRQn;
99
  NVIC_Init(&NVIC_InitStructure);
100
101
  SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);
102
  SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);
103
  SPI_Cmd(SPI1, ENABLE);
104
}
105
106
/**
107
 * @brief  Start new SPI transfer
108
 * @param  none
109
 * @retval  none
110
 */
111
void SPI_DMA_start(void){
112
  // Prevent errors
113
  //while((DMA_GetCmdStatus(DMA1_Stream4) == ENABLE) || (DMA_GetCmdStatus(DMA1_Stream3) == ENABLE)){
114
    // DMA transfer still running
115
  //}
116
117
  DMA_SetCurrDataCounter(DMA1_Channel2, BUFFER_SIZE); //nur notwendig bei mehr als 1 transfer
118
  DMA_SetCurrDataCounter(DMA1_Channel3, BUFFER_SIZE);
119
120
  // Chip Select Low
121
  GPIO_WriteBit(GPIOA, GPIO_Pin_4, RESET);
122
123
  DMA_Cmd(DMA1_Channel2, ENABLE);
124
  DMA_Cmd(DMA1_Channel3, ENABLE);
125
126
}
127
128
/**
129
 * @brief  DMA RX complete interrupt
130
 * @param  none
131
 * @retval  none
132
 */
133
void DMA1_Channel2_IRQHandler(void){
134
135
  if(DMA_GetITStatus( DMA1_IT_TC2))  {      // Test on DMA Stream Transfer Complete interrupt
136
    DMA_ClearITPendingBit( DMA1_IT_TC2);    // Clear DMA Stream Transfer Complete interrupt pending bit
137
    GPIO_WriteBit(GPIOA, GPIO_Pin_4, SET);          // Chip Select Low
138
    //USART_puts(USART1, "DMA fertig\n");
139
    DMA_Cmd(DMA1_Channel2, DISABLE);
140
    DMA_Cmd(DMA1_Channel3, DISABLE);
141
    // ToDo
142
  }
143
}
144
145
/**
146
 * @brief  DMA TX Complete interrupt
147
 * @param  none
148
 * @retval  none
149
 */
150
151
void DMA1_Channel3_IRQHandler(void){
152
153
  if(DMA_GetITStatus( DMA1_IT_TC3))  {      // Test on DMA Stream Transfer Complete interrupt
154
    //DMA_ClearITPendingBit(DMA1_Stream4, DMA_IT_TCIF4);    // Clear DMA Stream Transfer Complete interrupt pending bit
155
    DMA_ClearITPendingBit(DMA1_IT_TC3);
156
157
  }
158
}

von SPI (Gast)


Lesenswert?

Hallo,

der STM32F3 hat eine blöde Eigenschaft in der SPI-Hardware. Wenn das 
SPI-Peripheral im 8Bit Modus läuft und per DMA 'gefüttert' wird, ist 
Vorsicht geboten.

Vgl. STM32F3 Reference Manual RM0316 --> Packing with DMA, Seiten 731 u. 
732.

Das Problem ist, dass du für 8Bit Übertragungen per DMA das FRXTH Bit im 
SPI Modul (SPIx_CR2) noch setzten mußt (siehe Beschreibung der beiden 
Bits).

Gruß Bernd

von Alex R. (edge0xc)


Lesenswert?

Perfekt, vielen Dank, genau das wars :)

LG

von Phantomix X. (phantomix)


Lesenswert?

SPI schrieb:
> Das Problem ist, dass du für 8Bit Übertragungen per DMA das FRXTH Bit im
> SPI Modul (SPIx_CR2) noch setzten mußt (siehe Beschreibung der beiden
> Bits).


Hallo und danke für den Hinweis.


Das FRXTH-Bit ist auch für DMA-lose Übertragungen relevant.
FRXTH = 1 -> Das RXNE-Flag im Statusregister wird bereits nach 8 Bit 
gesetzt (wünschenswert, wenn man den SPI byteweise abhandeln will)
FRXTH = 0 (default) -> Das RXNE-Flag im Statusregister wird erst nach 16 
Bit gesetzt.

Desweiteren für 8 Bit-Übertragung (ohne DMA) sei dieser Code-Schnipsel 
interessant:
1
    #if defined(__STM32F30x_H)
2
        //Only write low byte of the 16bit DR register!
3
        //A 16 bit write would lead to an undesired push of an additional 0x00 to the FIFO
4
        *( (volatile uint8_t*) &periph_ptr->spi_device->DR) = txbyte;
5
    #else
6
        periph_ptr->spi_device->DR = txbyte;
7
    #endif
Schreibt man DR direkt, werden 16 bit in den Fifo gepusht, was zu einer 
abwechselnden Ausgabe von <Datenbyte0> <0x00> <Datenbyte1> <0x00> ... 
führt

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.