Forum: Mikrocontroller und Digitale Elektronik DMX-Empfang mit STM32F767


von Sebastian (moonwalker2828)


Angehängte Dateien:

Lesenswert?

Moin zusammen,
ich bin schon lange stiller Leser dieses tollen Forums, habe nun ein 
Problem, das zu lösen ich alleine gerade nicht im Stande bin.

Ich habe durch glückliche Umstände ein Board erhalten, auf dem ein 
STM32F767 nebst Peripherie zum DMX512-Empfang vorhanden ist.
Ich habe schon diverse Dinge mit dem Board umsetzen können, scheitere 
aber an dem DMX-empfang und sehe glaube ich den Wald vor lauter Bäumen 
nicht.
DMX kommt über UARt 5 rein, ich würde gerne den Wert an DMX-Adresse XY 
auf UART1 ausgeben lassen.

Hier mal, was ich derzeit versuche - gekürzt ,Datei dazu im Anhang.:
1
/* Private define ------------------------------------------------------------*/
2
/* USER CODE BEGIN PD */
3
#define DMX_FRAME_SIZE 513
4
#define DMX_BREAK_TIME_US  88
5
#define DMX_MARK_AFTER_BREAK_TIME_US 8
6
#define DMX_BIT_TIME_US 4
7
#define MIN_INTER_FRAME_TIME 176
8
/* USER CODE END PD */
9
10
/* Private macro -------------------------------------------------------------*/
11
/* USER CODE BEGIN PM */
12
13
/* USER CODE END PM */
14
15
/* Private variables ---------------------------------------------------------*/
16
17
18
19
TIM_HandleTypeDef htim2;
20
21
UART_HandleTypeDef huart5;
22
UART_HandleTypeDef huart1;
23
24
/* USER CODE BEGIN PV */
25
26
//receive Buffer
27
uint8_t dmx_data[DMX_FRAME_SIZE];
28
char buffer[50];
29
uint32_t last_frame_time = 0;
30
// DMX512 receive state
31
enum {
32
    DMX_STATE_BREAK,
33
    DMX_STATE_START,
34
    DMX_STATE_DATA,
35
    DMX_STATE_IDLE
36
} dmx_state = DMX_STATE_IDLE;
37
38
// DMX512 receive address
39
#define DMX_ADDRESS 1
40
41
// DMX512 receive flag
42
volatile uint8_t dmx_received = 0;
43
/* USER CODE END PV */
44
45
/* Private function prototypes -----------------------------------------------*/
46
void SystemClock_Config(void);
47
static void MX_GPIO_Init(void);
48
static void MX_UART5_Init(void);
49
static void MX_USART1_UART_Init(void);
50
static void MX_TIM2_Init(void);
51
static void MX_RTC_Init(void);
52
/* USER CODE BEGIN PFP */
53
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
54
/* USER CODE END PFP */
55
56
/* Private user code ---------------------------------------------------------*/
57
/* USER CODE BEGIN 0 */
58
59
/* USER CODE END 0 */
60
61
/**
62
  * @brief  The application entry point.
63
  * @retval int
64
  */
65
int main(void)
66
{
67
  /* USER CODE BEGIN 1 */
68
69
  /* USER CODE END 1 */
70
71
  /* MCU Configuration--------------------------------------------------------*/
72
73
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
74
  HAL_Init();
75
76
  /* USER CODE BEGIN Init */
77
78
  /* USER CODE END Init */
79
80
  /* Configure the system clock */
81
  SystemClock_Config();
82
83
  /* USER CODE BEGIN SysInit */
84
85
  /* USER CODE END SysInit */
86
87
  /* Initialize all configured peripherals */
88
  MX_GPIO_Init();
89
  MX_UART5_Init();
90
  MX_USART1_UART_Init();
91
  MX_TIM2_Init();
92
  MX_RTC_Init();
93
  /* USER CODE BEGIN 2 */
94
  HAL_UART_Transmit(&huart1, "MAINBOARD_DMX_TEST_V_0_3\r\n",28  ,1000);
95
96
    HAL_GPIO_WritePin(GPIOE, GPIO_PIN_11, GPIO_PIN_RESET);    // /D/E_IN_TX  (U2 Driver disable)
97
    
98
    HAL_GPIO_WritePin(GPIOE, GPIO_PIN_12, GPIO_PIN_RESET);    // RE_IN_RX    (U2 Receiver enable)
99
    
100
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_10, GPIO_PIN_SET);    // Source: DMX-Cable
101
    
102
103
104
    // Start DMX512 reception
105
        HAL_UART_Receive_IT(&huart5, dmx_data, DMX_FRAME_SIZE);
106
107
108
  /* USER CODE END 2 */
109
110
  /* Infinite loop */
111
  /* USER CODE BEGIN WHILE */
112
  while (1)
113
  {
114
    // Check if DMX512 data has been received
115
            if (dmx_received)
116
            {
117
                // Reset DMX512 receive flag
118
                dmx_received = 0;
119
120
                // Check DMX512 address
121
                if (dmx_data[DMX_ADDRESS] != 0)
122
                {
123
                    // Display DMX512 value on UART1
124
                    char buf[20];
125
                    sprintf(buf, "DMX value: %d\r\n", dmx_data[DMX_ADDRESS]);
126
                    HAL_UART_Transmit(&huart1, (uint8_t *)buf, strlen(buf), HAL_MAX_DELAY);
127
                }
128
            }
129
130
131
    /* USER CODE END WHILE */
132
133
134
135
136
137
138
139
140
    /* USER CODE BEGIN 3 */
141
  }
142
  /* USER CODE END 3 */
143
}
144
145
/**
146
  * @brief System Clock Configuration
147
  * @retval None
148
  */
149
void SystemClock_Config(void)
150
{
151
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
152
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
153
154
  /** Configure LSE Drive Capability
155
  */
156
  HAL_PWR_EnableBkUpAccess();
157
  __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
158
159
  /** Configure the main internal regulator output voltage
160
  */
161
  __HAL_RCC_PWR_CLK_ENABLE();
162
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
163
164
  /** Initializes the RCC Oscillators according to the specified parameters
165
  * in the RCC_OscInitTypeDef structure.
166
  */
167
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE|RCC_OSCILLATORTYPE_LSE;
168
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
169
  RCC_OscInitStruct.LSEState = RCC_LSE_ON;
170
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
171
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
172
  RCC_OscInitStruct.PLL.PLLM = 25;
173
  RCC_OscInitStruct.PLL.PLLN = 432;
174
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
175
  RCC_OscInitStruct.PLL.PLLQ = 9;  //9
176
  RCC_OscInitStruct.PLL.PLLR = 7;  //7
177
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
178
  {
179
    Error_Handler();
180
  }
181
182
  /** Activate the Over-Drive mode
183
  */
184
  if (HAL_PWREx_EnableOverDrive() != HAL_OK)
185
  {
186
    Error_Handler();
187
  }
188
189
  /** Initializes the CPU, AHB and APB buses clocks
190
  */
191
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
192
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
193
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
194
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
195
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
196
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
197
198
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7) != HAL_OK)
199
  {
200
    Error_Handler();
201
  }
202
}
203
204
205
206
/**
207
  * @brief TIM2 Initialization Function
208
  * @param None
209
  * @retval None
210
  */
211
static void MX_TIM2_Init(void)
212
{
213
214
  /* USER CODE BEGIN TIM2_Init 0 */
215
216
  /* USER CODE END TIM2_Init 0 */
217
218
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
219
  TIM_SlaveConfigTypeDef sSlaveConfig = {0};
220
  TIM_MasterConfigTypeDef sMasterConfig = {0};
221
222
  /* USER CODE BEGIN TIM2_Init 1 */
223
224
  /* USER CODE END TIM2_Init 1 */
225
  htim2.Instance = TIM2;
226
  htim2.Init.Prescaler = 0;
227
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
228
  htim2.Init.Period = 0xFFFFFFFF;
229
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
230
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
231
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
232
  {
233
    Error_Handler();
234
  }
235
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_ETRMODE2;
236
  sClockSourceConfig.ClockPolarity = TIM_CLOCKPOLARITY_NONINVERTED;
237
  sClockSourceConfig.ClockPrescaler = TIM_CLOCKPRESCALER_DIV1;
238
  sClockSourceConfig.ClockFilter = 0;
239
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
240
  {
241
    Error_Handler();
242
  }
243
  sSlaveConfig.SlaveMode = TIM_SLAVEMODE_DISABLE;
244
  sSlaveConfig.InputTrigger = TIM_TS_ITR0;
245
  if (HAL_TIM_SlaveConfigSynchro(&htim2, &sSlaveConfig) != HAL_OK)
246
  {
247
    Error_Handler();
248
  }
249
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
250
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
251
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
252
  {
253
    Error_Handler();
254
  }
255
  /* USER CODE BEGIN TIM2_Init 2 */
256
257
  /* USER CODE END TIM2_Init 2 */
258
259
}
260
261
/**
262
  * @brief UART5 Initialization Function
263
  * @param None
264
  * @retval None
265
  */
266
static void MX_UART5_Init(void)
267
{
268
269
  /* USER CODE BEGIN UART5_Init 0 */
270
271
  /* USER CODE END UART5_Init 0 */
272
273
  /* USER CODE BEGIN UART5_Init 1 */
274
275
  /* USER CODE END UART5_Init 1 */
276
  huart5.Instance = UART5;
277
  huart5.Init.BaudRate = 250000;
278
  huart5.Init.WordLength = UART_WORDLENGTH_8B;
279
  huart5.Init.StopBits = UART_STOPBITS_2;
280
  huart5.Init.Parity = UART_PARITY_NONE;
281
  huart5.Init.Mode = UART_MODE_RX;
282
  huart5.Init.HwFlowCtl = UART_HWCONTROL_NONE;
283
  huart5.Init.OverSampling = UART_OVERSAMPLING_16;
284
  huart5.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
285
  huart5.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_RXOVERRUNDISABLE_INIT;//UART_ADVFEATURE_RXOVERRUNDISABLE_INIT
286
  if (HAL_UART_Init(&huart5) != HAL_OK)
287
  {
288
    Error_Handler();
289
  }
290
  /* USER CODE BEGIN UART5_Init 2 */
291
  huart5.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_RXOVERRUNDISABLE_INIT;//UART_ADVFEATURE_RXOVERRUNDISABLE_INIT
292
  // Enable UART5 interrupts
293
     HAL_NVIC_SetPriority(UART5_IRQn, 0, 0);
294
     HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
295
     HAL_NVIC_EnableIRQ(UART5_IRQn);
296
  /* USER CODE END UART5_Init 2 */
297
298
}
299
300
301
302
303
304
305
/* USER CODE BEGIN 4 */
306
307
// DMX512 UART5 receive interrupt handler-Ansatz mit Timer zur MAB-detection
308
void UART5_IRQHandlerX(void)
309
{
310
  //HAL_UART_Transmit(&huart1, "U5IRQ\r\n", 9, 100);
311
    uint32_t isrflags = READ_REG(huart5.Instance->ISR);
312
    uint32_t cr1its = READ_REG(huart5.Instance->CR1);
313
314
    // Check for DMX512 break and mark-after-break conditions
315
    if ((isrflags & USART_ISR_FE) != RESET)
316
    {
317
        // DMX512 break detected
318
        dmx_state = DMX_STATE_START;
319
        // Debug message
320
                        char* message = "DMX512 break detected\r\n";
321
                        HAL_UART_Transmit(&huart1, (uint8_t*)message, strlen(message), HAL_MAX_DELAY);
322
323
        // Start timer to measure time since break
324
        __HAL_TIM_SET_COUNTER(&htim2, 0);
325
        HAL_TIM_Base_Start_IT(&htim2);
326
    }
327
    else if ((isrflags & USART_ISR_RXNE) != RESET && (dmx_state == DMX_STATE_BREAK))//Change DMX_STATE_START to DMX_STATE_BREAK for check
328
    {
329
        // DMX512 mark-after-break detected
330
      // Debug message
331
                      char* message = "DMX512 mark-after-break detected\r\n";
332
                      HAL_UART_Transmit(&huart1, (uint8_t*)message, strlen(message), HAL_MAX_DELAY);
333
        dmx_state = DMX_STATE_DATA;
334
        HAL_TIM_Base_Stop_IT(&htim2);
335
        uint32_t time_since_break = __HAL_TIM_GET_COUNTER(&htim2);
336
        uint32_t bit_time = (SystemCoreClock / 250000) / 8;  // calculate bit time for 250 kbps baud rate
337
        uint32_t data_offset = (time_since_break - bit_time) / bit_time;
338
339
        // Check that the data offset is within range
340
        if (data_offset >= 0 && data_offset < DMX_FRAME_SIZE)
341
        {
342
          HAL_UART_Transmit(&huart1, "Offset in Range\r\n", 17, 100);
343
            // Start receiving DMX512 data bytes
344
            HAL_UART_Receive_IT(&huart5, &dmx_data[data_offset], DMX_FRAME_SIZE - data_offset);
345
            // Wait for the data to be received
346
                        while (HAL_UART_GetState(&huart5) != HAL_UART_STATE_READY &&
347
                               HAL_UART_GetState(&huart5) != HAL_UART_STATE_BUSY_RX) {}
348
                        // Debug messages
349
                                   char* message1 = "HAL_UART_Receive_IT() called\r\n";
350
                                   HAL_UART_Transmit(&huart1, (uint8_t*)message1, strlen(message1), HAL_MAX_DELAY);
351
                                   char* message2 = "Data offset: %d\r\n";
352
                                   sprintf(buffer, message2, data_offset);
353
                                   HAL_UART_Transmit(&huart1, (uint8_t*)buffer, strlen(buffer), HAL_MAX_DELAY);
354
355
        }
356
        else
357
        {
358
          HAL_UART_Transmit(&huart1, "Offset NOT in Range\r\n", 21, 100);
359
            // Invalid data offset, restart reception
360
            dmx_state = DMX_STATE_BREAK;
361
            HAL_UART_AbortReceive_IT(&huart5);
362
        }
363
    }
364
    else if ((isrflags & USART_ISR_IDLE) != RESET)
365
    {
366
        // DMX512 frame received
367
        dmx_received = 1;
368
        dmx_state = DMX_STATE_IDLE;
369
        __HAL_UART_CLEAR_IDLEFLAG(&huart5);
370
371
        // Debug message
372
        char* message = "DMX512 frame received\r\n";
373
        HAL_UART_Transmit(&huart1, (uint8_t*)message, strlen(message), HAL_MAX_DELAY);
374
        // Wait for minimum inter-frame time (176 microseconds)
375
                uint32_t frame_time = __HAL_TIM_GET_COUNTER(&htim2);
376
                uint32_t inter_frame_time = frame_time - last_frame_time;
377
                if (inter_frame_time < MIN_INTER_FRAME_TIME)
378
                {
379
                    HAL_Delay(MIN_INTER_FRAME_TIME - inter_frame_time);
380
                }
381
                last_frame_time = frame_time;
382
383
                // Reset timer for next frame
384
                __HAL_TIM_SET_COUNTER(&htim2, 0);
385
    }
386
}
387
388
// UART5 error interrupt handler
389
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
390
{
391
    // Error handling, restart reception
392
    dmx_state = DMX_STATE_BREAK;
393
    HAL_UART_AbortReceive_IT(&huart5);
394
    HAL_UART_Receive_IT(&huart5, dmx_data, DMX_FRAME_SIZE);
395
}
396
// UART5 receive complete interrupt handler
397
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
398
{
399
    // Error handling, restart reception
400
    dmx_state = DMX_STATE_BREAK;
401
    HAL_UART_AbortReceive_IT(&huart5);
402
    HAL_UART_Receive_IT(&huart5, dmx_data, DMX_FRAME_SIZE);
403
}
404
405
406
// TIM2 update interrupt handler
407
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
408
{
409
    if (htim->Instance == TIM2)
410
    {
411
        // Stop timer and reset DMX512 state
412
        HAL_TIM_Base_Stop_IT(&htim2);
413
        dmx_state = DMX_STATE_BREAK;
414
        HAL_UART_AbortReceive_IT(&huart5);
415
    }
416
}
417
/* USER CODE END 4 */
418
419
/**
420
  * @brief  This function is executed in case of error occurrence.
421
  * @retval None
422
  */

Ich bekomme auf uart 1 angezeigt,  "DMX512 frame received" und "Break 
detected", aber komme nie in den Status "Mark-after-break" detected.

Was kann ich tun, um hier weiter zu kommen?

Ich sitze nun schon fast zwei Tage an diesem Problem und habe - wie man 
am code sieht- schon diverse Dinge versucht....

Danke für eure Hilfe!

: Bearbeitet durch User
von Sebastian (moonwalker2828)


Lesenswert?

Tut mir leid, dass der Code so umfangreich aussieht.

Ich wäre auch mit einem grundsätzlichen Hinweis wie man einen 
dmx-empfang ohne separaten timerpin auf dem stm32 angeht, sehr 
glücklich.

Kann mir irgendjemand einen Hinweis geben?
Langsam verzweifle ich an dem Problem, nicht zu Letzt, weil mir der 
Gesamtüberblick ein wenig fehlt.

von Harry L. (mysth)


Lesenswert?

Also erstmal gehört längerer Quelltext in den Anhang und nicht in den 
Text!

Damit du mal ein Gefühl für den Umgang mit UART in der HAL bekommst, 
schau dir mal meine UART-Routinen an!
Die sollten sich auch für DMX nutzen lassen.

Beitrag "[STM32/HAL] simples U(S)ART-Library"

von Harald A. (embedded)


Lesenswert?

Sebastian schrieb:
> Ich wäre auch mit einem grundsätzlichen Hinweis wie man einen
> dmx-empfang ohne separaten timerpin auf dem stm32 angeht, sehr
> glücklich.
>
Es gibt hier Forum so ein paar Trigger, die heftigste Reaktionen 
auslösen können, z.B. einen Mikrocontroller nutzen obwohl NE555 reicht, 
DCF, bleifreies Lot und leider auch DMX. Das nur zur Warnung vorab. Such 
dir aus den Antworten das Beste heraus.
Früher habe ich DMX-Empfänger gebaut und hatte natürlich auch immer das 
leidliche Thema mit der Break-Erkennung. Grundsätzlich geht es ohne 
separaten Timerpin. Man wartet auf einen UART-Framing-Error (ggf. kann 
man bei diesem STM gar einen INT auslösen? Der Framing-Error wird durch 
den Break ausgelöst, das das Stopbit nicht an der erwarteten Stelle 
steht. Der Inhalt des empfangenen Datenbytes muss „0“ sein. Fehler 
löschen und auf das nächste Byte warten. Ist das ebenfalls „0“ (diesmal 
ohne Framing-Error) hat man ausreichend genau den Beginn des Frames 
erkannt.
Manchmal habe ich noch in der Interrupt-Routine, wo der Framing-Error 
behandelt wurde, zusätzlich noch geschaut, ob der RX-Pin immer noch auf 
Low ist. Das ist aber optional und nicht unbedingt erforderlich.

: Bearbeitet durch User
von Sebastian (moonwalker2828)


Lesenswert?

Vielen Dank,
Deinen Code schaue ich mir morgen früh am PC an.
Eine normale uart -kommunikation zwischen PC und stm, oder auch stm zu 
stm habe ich bereits erfolgreich implementiert. Ich scheitere 
tatsächlich an den speziellen Gegebenheiten bei DMX: Break von 88us, 
Mark after Break 8u
- und der Tatsache, dass nicht notwendigerweise immer alle 513 Pakete 
auch vom Sender gesendet werden.

Bezüglich des Quellcodes im Anhang gelobe ich Besserung!

von Harald A. (embedded)


Lesenswert?

Auf die detaillierte Auswertung der Zeit des MAB kannst Du meiner 
Meinung nach verzichten.

von Sebastian (moonwalker2828)


Lesenswert?

@ Harald A.

Vielen Dank. Ja, ich weiss, dass DMX hier ein Triggerthema ist -warum 
auch immer.
Deinen Ansatz finde ich interessant, das muss ich mir Mal in Ruhe mit 
den verfügbaren Ressourcen ansehen.

Ich hab zumindest das Gefühl, bei diesem Problem viel über den stm zu 
lernen - und das ist bei so einem Hobbyprojekt ja auch immer sehr 
befriedigend - auch wenn es dann gerne auch mal Erfolge geben darf. 
Aber, dass der Anfang nicht einfach würde, wusste ich.

von Harald A. (embedded)


Lesenswert?

Es gibt auch einen INT für LIN Break, das Konzept ist sehr ähnlich 
(Eingang für min. 11 Bitzeiten Low). Müsste man schauen, ob sich für 
diesen Betriebsmodus auch 250kbit konfigurieren lässt, das ist für LIN 
untypisch.

: Bearbeitet durch User
von Sebastian (moonwalker2828)


Lesenswert?

Harald A. schrieb:
> Es gibt auch einen INT für LIN Break, das Konzept ist sehr ähnlich
> (Eingang für min. 11 Bitzeiten Low). Müsste man schauen, ob sich für
> diesen Betriebsmodus auch 250kbit konfigurieren lässt, das ist für LIN
> untypisch.

Puuh, klingt auch nach einer Überlegung, mit lin habe ich noch gar 
nichts gemacht bisher.

Danke für deine tolle Unterstützung!
Wie gesagt, ich lerne sehr viel.

von Sebastian (moonwalker2828)


Lesenswert?

Harald A. schrieb:
 Grundsätzlich geht es ohne
> separaten Timerpin. Man wartet auf einen UART-Framing-Error (ggf. kann
> man bei diesem STM gar einen INT auslösen? Der Framing-Error wird durch
> den Break ausgelöst, das das Stopbit nicht an der erwarteten Stelle
> steht. Der Inhalt des empfangenen Datenbytes muss „0“ sein. Fehler
> löschen und auf das nächste Byte warten. Ist das ebenfalls „0“ (diesmal
> ohne Framing-Error) hat man ausreichend genau den Beginn des Frames
> erkannt.

Vielen Dank :)

Den Teil habe ich gerade implementieren können und er scheint zu 
funktionieren.
Vielleicht magst Du ja einmal draufschauen, so sieht meine IRQ-Routine 
derzeit aus:
1
void UART5_IRQHandlerX(void){
2
  uint32_t isrflags = READ_REG(huart5.Instance->ISR);
3
  uint32_t cr1its = READ_REG(huart5.Instance->CR1);
4
  //uint32_t URDR = READ_REG(huart5.Instance->RDR);
5
6
  //Debug-message
7
   char* message = "IRQ_CALLED\r\n";
8
   HAL_UART_Transmit(&huart1, (uint8_t*)message, strlen(message), HAL_MAX_DELAY);
9
   char buf3[64];
10
            //   snprintf(buf3, 64, "UART5 ISR flags: 0x%08X, CR1: 0x%08X\r\n", isrflags, cr1its);
11
           //    HAL_UART_Transmit(&huart1, (uint8_t*)buf3, strlen(buf3), HAL_MAX_DELAY);
12
13
  if ((isrflags & USART_ISR_FE)!=RESET){    //IF Frameerror detected
14
    message="Frame-error detected\r\n";
15
    HAL_UART_Transmit(&huart1, (uint8_t*)message, strlen(message), HAL_MAX_DELAY);
16
17
            snprintf(buf3, 64, "UART5 ISR flags: 0x%08X, CR1: 0x%08X\r\n", isrflags, cr1its);
18
            HAL_UART_Transmit(&huart1, (uint8_t*)buf3, strlen(buf3), HAL_MAX_DELAY);
19
20
21
22
23
    if(READ_REG(huart5.Instance->RDR)==RESET){
24
    message="DATA0\r\n";
25
    HAL_UART_Transmit(&huart1, (uint8_t*)message, strlen(message), HAL_MAX_DELAY);
26
    dmx_stat=DMX_BRAKE;
27
    }
28
    WRITE_REG(huart5.Instance->ICR, USART_ICR_FECF);    //Schreibe 1 in Frame-error-clear-reg -> Lösche FE
29
30
  }
31
32
  if((dmx_stat==DMX_BRAKE)&&(READ_REG(huart5.Instance->RDR)==RESET)&&(isrflags & USART_ISR_FE)==RESET){  //Framebeginn detektiert
33
    message="Start_of_Frame\r\n";
34
        HAL_UART_Transmit(&huart1, (uint8_t*)message, strlen(message), HAL_MAX_DELAY);
35
    dmx_stat=DMX_IDLE;  //ist natürlich Quatsch, müsste DM_START sein
36
    //DMX-Startpaket muss null sein, sonst RDM o.ä.
37
    //Danach folgen die Datenpakete
38
    // einlesen in ein Array
39
  }
40
}

Nun muss ich mir den Rest noch überlegen....also,
1. Check ob das als nächstes folgende Byte 0 ist ( Startbyte)
2. einlesen der folgenden Bytes in ein Array (sollten dann ja die Daten 
sein
3. Abbruchbedingungen: a) alle 513 Frames übertragen -> State wieder auf 
Idle

b) weniger als 513 Frames übertragen, aber Frameerror -> sollte auf 
Brake hindeuten.

So weit richtig? Verbesserungsvorschläge / Anmerkungen?

Danke nochmal für die tolle Hilfe :)

von Harald A. (embedded)


Lesenswert?

Na ja, es sind ja manchmal auch weniger als 512 Bytes, das ist nach Norm 
zulässig.
Vlt. so:

Init:
Framing-Interrupt aufsetzen
Erstes Bytes im Empfangsbuffer auf 0xFF setzen

Zur Laufzeit:
- Per Interrupt warten auf Framing Error
- Im Interrupt DMA für den Empfang von 513 Bytes aufsetzen
- Gleichzeitig schauen, ob der vorherige Empfang das 1.Byte auf 0 
gebracht hat
- Auswerten, ob überhaupt x Bytes per DMA empfangen wurden
- Daten für gültig/ungültig erklären
- 1. Byte wieder auf 0xFF setzen, damit es wieder überschrieben wird

Anmerkungen:
- Erst nach dem Empfang des nächsten Framing-Errors weiß man, ob die 
Daten gültig sind. Ist aber nur eine kleine Verzögerung
- man kann dieses Konzept auf zwei alternierende Buffer ausweiten, wenn 
man das braucht. Schließlich werden die Daten sofort nach Gültigstellung 
sofort wieder überschrieben. In normalen Anwendungen aber auch kein 
Problem.

von Sebastian (moonwalker2828)


Lesenswert?

Hallo Harald,

Danke für deinen Input, ich war nun ein paar Tage nicht mehr an der 
Baustelle dran.
Leider komme ich nicht wirklich vorwärts. Den DMA-Code habe ich nicht 
zum Laufen bekommen, das sind für mich ohne Hilfe gerade leider zu viele 
Unbekannte auf einmal.

Ich bin nun noch einmal einen Schritt zurück gegangen und habe folgendes 
gebaut:
1
void UART5_IRQHandlerX(void)
2
{
3
  char* message = "IRQ\r\n";
4
  //HAL_UART_Transmit(&huart1, (uint8_t*)message, strlen(message), HAL_MAX_DELAY);
5
   uint16_t rx;
6
   uint32_t isrflags = READ_REG(huart5.Instance->ISR);
7
8
   if ((isrflags & USART_ISR_ORE) != RESET) // Data Overrun?
9
   {
10
     rx=huart5.Instance->RDR;    //Zeichen lesen
11
    WRITE_REG(huart5.Instance->ICR,USART_ICR_ORECF);    //Overrun errorflag löschen
12
      dmx_stat=DMX_BREAK;        //Warte auf Reset / Break
13
       message = "BREAK0";
14
        //HAL_UART_Transmit(&huart1, (uint8_t*)message, strlen(message), HAL_MAX_DELAY);
15
   }
16
   else
17
   {
18
      if ((isrflags & USART_ISR_FE)!=RESET)//Break oder Frameerror?
19
      {
20
        rx=huart5.Instance->RDR;    //Zeichen lesen
21
        WRITE_REG(huart5.Instance->ICR,USART_ICR_FECF);    //Frameerror errorflag löschen
22
         if (rx == 0)
23
         {
24
           dmx_stat=DMX_START; // FE WAS a BREAK -> Warte auf Start Byte!
25
         } else {
26
           dmx_stat=DMX_BREAK; // Warte einfach auf Reset (BREAK)
27
         }
28
      }
29
      else
30
      {
31
         if ((isrflags & USART_ISR_RXNE)!=RESET) // Empfangsinterrupt?
32
         {
33
            rx = huart5.Instance->RDR;; // Lese das Zeichen
34
            switch (dmx_stat)
35
            {
36
            case DMX_START:
37
               if (rx == 0)
38
               {
39
                 dmx_stat=DMX_DATA;    //Wechsle in Datenempfangsstatus
40
                 DMXInDataCounter=0;        //Datenzähler auf 0
41
               } else {
42
                 dmx_stat=DMX_BREAK; // Warte einfach auf Reset
43
               }
44
               break;
45
            case  DMX_DATA: // Daten ablegen
46
              dmx_data0[DMXInDataCounter]= huart5.Instance->RDR;
47
48
              char buf3[64];
49
              snprintf(buf3, 64, "data packageNo: 0x%08X, contains: 0x%08X\r\n", DMXInDataCounter, dmx_data0[DMXInDataCounter]);
50
                        HAL_UART_Transmit(&huart1, (uint8_t*)buf3, strlen(buf3), HAL_MAX_DELAY);
51
52
53
              char* message = "DMX512 Writing Data\r\n";
54
                             // HAL_UART_Transmit(&huart1, (uint8_t*)message, strlen(message), HAL_MAX_DELAY);
55
              DMXInDataCounter++;
56
               HAL_UART_AbortReceive_IT(&huart5);
57
58
               HAL_UART_Receive_IT(&huart5, dmx_data0, DMX_FRAME_SIZE);
59
60
               if (DMXInDataCounter >= DMX_FRAME_SIZE)
61
               {
62
                 char* message = "reached_MAX\r\n";
63
                                               HAL_UART_Transmit(&huart1, (uint8_t*)message, strlen(message), HAL_MAX_DELAY);
64
                dmx_stat=DMX_BREAK; // ALL CHANNELS RECEIVED
65
                 HAL_UART_AbortReceive_IT(&huart5);
66
                 HAL_UART_Receive_IT(&huart5, dmx_data0, DMX_FRAME_SIZE);
67
               }
68
               break;
69
            default :
70
               break;
71
            }
72
         }
73
         else
74
         {
75
           
76
           //WRITE_REG(huart5.Instance->ICR,0x00000000);
77
78
            WRITE_REG(huart5.Instance->ICR,USART_ICR_ORECF);
79
            WRITE_REG(huart5.Instance->ICR,USART_ICR_IDLECF);
80
            WRITE_REG(huart5.Instance->ICR,USART_ICR_FECF);
81
82
         }
83
      }
84
   }
85
}

Damit kann ich das erste Byte sicher, folgende Bytes teilweise 
empfangen.

So weit ich meiner UART1 trauen kann, empfange ich das package 0x00 mit 
den richtigen Daten, die am Pult eingestellt sind, alle folgenden mit 
Inhalt 0, obwohl das Pult andere Werte sendet und das Signal auch super 
sauber aussieht (Oszi).
Bei Package 0x22 bricht das Ganze ab und startet wieder mit Package 0x00 
- was eigentlich auch nicht zu dem passt, was das Pult ausgibt.

Hast Du eine Idee, oder einen Ansatz für mich?

Danke...ich will auch nicht nerven, aber mir gehen gerade die Ideen aus.

von Harald A. (embedded)


Lesenswert?

Tja, da jetzt im einzelnen durchzusteigen ist aus der Ferne schwierig. 
Ich würde empfehlen zunächst einmal ein DMA Beispiel aus der Google 
Suche ins Laufen zu bringen, muss ja nicht DMX sein, vlt. erstmal eine 
„normale“ Baudrate. Du baust ja auch ganz offensichtlich auf dem Code 
Generator von STM auf (Name gerade vergessen). Hier gibt es Beispiele:

https://deepbluembedded.com/how-to-receive-uart-serial-data-with-stm32-dma-interrupt-polling/

von Harald A. (embedded)


Lesenswert?

Weiterhin fällt mir auf, dass Du ein print im Interrupt ausführst. Du 
hast von Int zu Int nur 44usec. Weiß nicht, ob das hinkommt. Weiterhin 
könntest Du einzelne Portpins setzen, die Du dann mit einem Logic 
Analyzer parallel zum DMX Datenstrom auswertest. Für Sigrok gibt es 
bestimmt einen DMX-Decoder, die LA Hardware kostet fast nichts.

von J. S. (engineer) Benutzerseite


Lesenswert?

Das Protokoll hast du verstanden und richtig implementiert? Auch die 
Pausen-Zeiten? So ohne weiteres arbeitet da eine Standard-UART nicht 
richtig drauf. Ich habe den DMX in einem kleinen Core im FPGA. Da ist 
das wesentlich handlicher.

von Harald A. (embedded)


Lesenswert?

Jürgen S. schrieb:
> Das Protokoll hast du verstanden und richtig implementiert? Auch die
> Pausen-Zeiten? So ohne weiteres arbeitet da eine Standard-UART nicht
> richtig drauf. Ich habe den DMX in einem kleinen Core im FPGA. Da ist
> das wesentlich handlicher.

Das würde mich jetzt mal interessieren, warum eine Standard UART da 
nicht funktionieren sollte (habe es selber schon mehrfach auf 
verschiedenen Controllern umgesetzt. Einzig mit einer Fujitsu MB90F387 
gab es Probleme, da die Startbit-Erkennung nicht Flanken- sondern 
Level-getriggert war und somit aus dem Framing-Error nicht sauber 
rauskam.
Und was meinst Du mit Pausenzeiten? Mark-after-Break?

: Bearbeitet durch User
von C-hater (c-hater)


Lesenswert?

Harald A. schrieb:

> Einzig mit einer Fujitsu MB90F387
> gab es Probleme, da die Startbit-Erkennung nicht Flanken- sondern
> Level-getriggert war und somit aus dem Framing-Error nicht sauber
> rauskam.

Das gleiche Problem existiert z.B. bei der TMS320Fxxx-Reihe von TI.

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.