Forum: Mikrocontroller und Digitale Elektronik STM32F103 USART DMA EMV-Problem?


von 4toTakoe (Gast)



Lesenswert?

Mahlzeit,

Habe hier ein Problem mit einem STM32F103 und USART per DMA (Olimex P103 
Dev-Board). Das Teil werkelt als Modbus-Master um Daten aus einem 
Energier-Meter zu klauen.

Es läuft alles sehr zufriedenstellend (auf dem Schreibtisch). Nun ist 
das Olimex-Board neben dem Energie-Meter und einer Bohrmaschine zum 
Probelauf aufgebaut. Immer wenn die Bohrmaschine ein oder ausgeschaltet 
wird, scheint der DMA-Stream abzureißen und die Daten werden nicht mehr 
verarbeitet (auf dem Controller).

Ich kann das Problem nur auf EMV-Einstrahlungen bzw. eventuell falsche 
Konfiguration des DMA eingrenzen. Mich wundert, dass auf dem 
Schreibtisch alles gut funktioniert.

Anbei mal ein paar Oszi-Bilder vom USART-Rx (blau) und RS485 / Modbus 
(gelb). Irgendwie scheint der USART-Rx im Moment der EMV-Einstrahlung 
wild herumzuflattern. Hab an Rx schon 1k Pullup gehängt. Brachte etwas 
Besserung, aber das Problem tritt dennoch auf.

Nach 1-2s rumzappeln des Rx sieht wieder alles normal aus, aber der 
DMA-stream bzw. der DMA-Interrupt wird nicht mehr ausgelöst...sprich die 
Daten gehen verschollen.

Weiß jemand weiter?

Hier der Code der DMA/USART init und der interrupts:
1
  // hardware clock source
2
#define MODBUS_DE_RCC      RCC_APB2Periph_GPIOC
3
#define MODBUS_RE_RCC      RCC_APB2Periph_GPIOC
4
#define MODBUS_RXTX_RCC      RCC_APB2Periph_GPIOB
5
#define MODBUS_UART_PeriphCC  RCC_APB1PeriphClockCmd  /* USART2 & USART3 @ APB1ENR, USART1 @ APB2ENR */
6
#define MODBUS_UART_RCC      RCC_APB1Periph_USART3  /* USART2 & USART3 @ APB1ENR, USART1 @ APB2ENR */
7
#define MODBUS_UART        USART3          /* mind DMA request mapping! */
8
#define MODBUS_UART_PIN_REMAP  0
9
#define MODBUS_UART_IRQ      USART3_IRQn
10
#define MODBUS_UART_BAUDRATE  38400
11
12
#if MODBUS_UART_PIN_REMAP
13
#define MODBUS_UART_REMAP_CMD  GPIO_PartialRemap_USART3
14
#endif
15
16
  // hardware pins
17
#define MODBUS_RX_PIN    GPIO_Pin_11
18
#define MODBUS_RX_PORT    GPIOB
19
#define MODBUS_TX_PIN    GPIO_Pin_10
20
#define MODBUS_TX_PORT    GPIOB
21
#define MODBUS_DE_PIN    GPIO_Pin_0
22
#define MODBUS_DE_PORT    GPIOC
23
#define MODBUS_RE_PIN    GPIO_Pin_1
24
#define MODBUS_RE_PORT    GPIOC
25
26
  // DMA options
27
#define MODBUS_RX_DMA_CHANNEL  DMA1_Channel3
28
#define MODBUS_TX_DMA_CHANNEL  DMA1_Channel2
29
#define MODBUS_RX_DMA_CLRFLAG  DMA1_IT_TC3
30
#define MODBUS_TX_DMA_CLRFLAG  DMA1_IT_TC2
31
#define MODBUS_RX_DMA_IRQ    DMA1_Channel3_IRQn
32
#define MODBUS_TX_DMA_IRQ    DMA1_Channel2_IRQn
33
#define MODBUS_USART_DMA_RX_IRQHandler  DMA1_Channel3_IRQHandler
34
#define MODBUS_USART_DMA_TX_IRQHandler  DMA1_Channel2_IRQHandler
35
36
  // interrupt options
37
#define MODBUS_RX_INTERRUPT_PRIORITY    2
38
#define MODBUS_RX_INTERRUPT_SUBPRIORITY    0
39
#define MODBUS_TX_INTERRUPT_PRIORITY    1
40
#define MODBUS_TX_INTERRUPT_SUBPRIORITY    0
41
42
/**
43
  * @brief  Init RS485 hardware interface with DMA
44
  * @retval None
45
  */
46
void Modbus_Init(void)
47
{
48
  GPIO_InitTypeDef GPIO_InitStructure;
49
  NVIC_InitTypeDef NVIC_InitStructure;
50
  DMA_InitTypeDef DMA_InitStructure;
51
  USART_InitTypeDef USART_InitStructure;
52
  
53
  RCC_APB2PeriphClockCmd(MODBUS_DE_RCC | MODBUS_RE_RCC | MODBUS_RXTX_RCC | RCC_APB2Periph_AFIO, ENABLE);
54
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
55
  MODBUS_UART_PeriphCC(MODBUS_UART_RCC, ENABLE);
56
57
  /* DE Pin */
58
  GPIO_InitStructure.GPIO_Pin = MODBUS_DE_PIN;
59
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
60
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
61
  GPIO_Init(MODBUS_DE_PORT, &GPIO_InitStructure);  
62
  /* RE Pin */
63
  GPIO_InitStructure.GPIO_Pin = MODBUS_RE_PIN;
64
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
65
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
66
  GPIO_Init(MODBUS_RE_PORT, &GPIO_InitStructure);
67
68
#if MODBUS_UART_PIN_REMAP
69
  /* Enable the USART Pins Software Remapping */
70
  GPIO_PinRemapConfig(MODBUS_UART_REMAP_CMD, ENABLE);
71
#endif
72
73
  /* TX Pin */
74
  GPIO_InitStructure.GPIO_Pin = MODBUS_TX_PIN;
75
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
76
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
77
  GPIO_Init(MODBUS_TX_PORT, &GPIO_InitStructure);
78
  /* RX Pin */
79
  GPIO_InitStructure.GPIO_Pin = MODBUS_RX_PIN;
80
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
81
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
82
  GPIO_Init(MODBUS_RX_PORT, &GPIO_InitStructure);
83
84
    /* USART */
85
  USART_InitStructure.USART_BaudRate = MODBUS_UART_BAUDRATE;
86
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
87
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
88
  USART_InitStructure.USART_Parity = USART_Parity_No;
89
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
90
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
91
92
  USART_Init(MODBUS_UART, &USART_InitStructure);
93
  USART_DMACmd(MODBUS_UART, USART_DMAReq_Tx, ENABLE);
94
  USART_DMACmd(MODBUS_UART, USART_DMAReq_Rx, ENABLE);
95
  USART_Cmd(MODBUS_UART, ENABLE);
96
97
  /* DMA Channel x (USART RX) */
98
  NVIC_InitStructure.NVIC_IRQChannel = MODBUS_RX_DMA_IRQ;
99
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
100
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
101
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
102
  NVIC_Init(&NVIC_InitStructure);
103
104
  /* DMA Channel x (USART TX)*/
105
  NVIC_InitStructure.NVIC_IRQChannel = MODBUS_TX_DMA_IRQ;
106
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
107
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
108
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
109
  NVIC_Init(&NVIC_InitStructure);
110
111
  /* DMA Channel for MODBUS_UART TX */
112
  DMA_DeInit(MODBUS_TX_DMA_CHANNEL);
113
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(MODBUS_UART->DR);
114
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)usart_transmit_array;
115
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
116
  DMA_InitStructure.DMA_BufferSize = MODBUS_TRANSMIT_MAX_LENGTH;
117
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
118
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
119
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
120
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
121
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
122
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
123
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
124
  DMA_Init(MODBUS_TX_DMA_CHANNEL, &DMA_InitStructure);
125
126
  /* Enable DMA Stream Transfer Complete interrupt */
127
  DMA_ITConfig(MODBUS_TX_DMA_CHANNEL, DMA_IT_TC, ENABLE);
128
  DMA_Cmd(MODBUS_TX_DMA_CHANNEL, ENABLE);
129
130
  /* DMA Channel for MODBUS_UART RX */
131
  DMA_DeInit(MODBUS_RX_DMA_CHANNEL);
132
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(MODBUS_UART->DR);
133
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)usart_receive_array;
134
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
135
  DMA_InitStructure.DMA_BufferSize = MODBUS_RECEIVE_MAX_LENGTH;
136
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
137
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
138
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
139
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
140
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
141
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
142
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
143
  DMA_Init(MODBUS_RX_DMA_CHANNEL, &DMA_InitStructure);
144
145
  /* Enable DMA Stream Transfer Complete interrupt */
146
  DMA_ITConfig(MODBUS_RX_DMA_CHANNEL, DMA_IT_TC, ENABLE);
147
  DMA_Cmd(MODBUS_RX_DMA_CHANNEL, ENABLE);
148
}
149
150
/**
151
  * @brief  basic interrupt handler for USART DMA access
152
  * @retval None
153
  */
154
void MODBUS_USART_DMA_RX_IRQHandler(void)
155
{
156
  /* DMA Transfer Complete interrupt */
157
  if (DMA_GetITStatus(MODBUS_RX_DMA_CLRFLAG))
158
  {
159
    /* Clear DMA Transfer Complete interrupt pending bit */
160
    DMA_ClearITPendingBit(MODBUS_RX_DMA_CLRFLAG);
161
162
    /* do something here */
163
    bGotDirisResponse = 1;
164
  }
165
}

von 4toTakoe (Gast)


Lesenswert?

ahh...lol. Problem erkannt.

4toTakoe schrieb:
> DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

Muss natürlich heißen:
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

Shice Copy&Paste. Jetzt bekomme ich die Daten auch weggepuffert. Sehr 
schön.

Das komische Oszillieren bleibt allerdings....und die Daten sehen 
dementsprechend verwirrt aus (unplausibel).

Da bleibt mir wohl nix anderes über, als CRC check zu machen.

Somit - Case Closed. Schön das wir drüber geredet haben :)

von Jim M. (turboj)


Lesenswert?

4toTakoe schrieb:
> Anbei mal ein paar Oszi-Bilder vom USART-Rx (blau) und RS485 / Modbus
> (gelb).

Der RS485 scheint nicht vorgespannt zu sein, was bei Einstreuungen gar 
lustige Fehlerbilder liefert -  weil beide Rs485 Leitungen High-Z sind 
und als Antennen arbeiten.

Spendiere dem Bus mal einen Pullup (1k..10k) auf der einen und einen 
Pulldown auf der anderen Busleitung.

von 4toTakoe (Gast)


Lesenswert?

Jim M. schrieb:
> Spendiere dem Bus mal einen Pullup (1k..10k) auf der einen und einen
> Pulldown auf der anderen Busleitung.

Hab ich auch schon versucht...die Störung bzw. das komische Oszillieren 
tritt aber nur auf der UART auf, nicht auf dem RS485.

Die UART-Leitung zwischen Controller und Bus-transceiver ist ca. 4cm 
lang...also nicht sooo lang.

Naja...mal sehen was mir noch einfällt.

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.