STM32에서 UART와의 인터럽트를 위해 항상 DMA를 사용하지 않는 이유는 무엇입니까? [닫은]


9

지난달 UART (MIDI 용)가 인터럽트없이 STM (STM32F103C8T6)과 함께 작동하는 데 많은 시간을 들이지 않고 많은 성공을 거두었습니다.

그러나 오늘 저녁 DMA를 사용하면 꽤 빨리 작동했습니다.

DMA를 읽는 것이 더 빠르고 CPU를 완화시키는 한, 항상 인터럽트를 위해 DMA를 사용하지 않는 이유는 무엇입니까? 특히 STM32에서는 상당히 문제가있는 것 같습니다.

STM32CubeMx / HAL을 사용하고 있습니다.


2
왜 안돼? 그것은 의견의 문제이거나, 어떤 가능한 기술적 이유에 대한 추측을 원하거나, 같은 방식으로 너무 광범위해서, 여기에 속하는 질문이 아닙니다. 임의의 예를 들자면, DMA는 데이터를 청구하는 데 더 많은 대기 시간을 의미합니다. 특히 여러 문자를 수집하도록 허용하지 않으면 실질적인 이점이 없기 때문입니다. 종종 괜찮을 수도 있고 때로는 그렇지 않을 수도 있습니다.
Chris Stratton

6
인터럽트 작동에 몇 주가 걸리면 잘못된 방식으로 작업에 접근했기 때문입니다. DMA 작업을 수행하는 데 시간이 오래 걸릴 수 있습니다. 실제로 더 복잡한 작업이므로 더 간단한 작업에 비해 더 복잡한 작업의 명백한 용이성은 메커니즘 자체가 아니라 각 작업에 대한 지침에 사용 된 리소스에 의해 결정됩니다.
Chris Stratton 1

5
dma가 cpu를 해제한다고 가정하지 마십시오. 때로는 cpu가 계속 진행되고 때로는 dma 엔진의 버스를 유지하기 위해 프로세서가 고정되지 않습니다. 팔 구현 으로이 작업을 수행하는 것은 쉽지 않으므로 모든 팔이 이런 식이고 모든 x86이 그런 식 또는 그 밖의 방법이라고 말할 수는 없습니다. 그렇게 간단하지 않습니다. 항상 시스템 디자인을 검사하고 약간의 해킹을해야합니다. 당신이 가지고있는 칩은 팔 코어를 매우 자유롭게 만들 수 있습니다. 이것은 dma에 대한 주석 일뿐입니다. 귀하의 질문에 관해서는, 당신이 유지할 수 없었으며 dma + int가 폴링을 할 수 없다면 완전한 해결책 일 것입니다.
old_timer

5
인터럽트는 STM32F 직렬 포트에서 매우 사소합니다. 우리 중 일부는 당신이 잘못 가고있는 곳을 알아낼 수 있도록 코드로 질문을 게시하지 않습니까? 근본적인 문제가 무엇인지 이해하지 않고 작동 할 때까지 코드를 해킹하는 것은 결코 좋은 생각이 아닙니다.
Jon

7
나의 (그렇지 않은) 겸손한 견해에서, 이것은 끔찍한 블라우스 큐브를 사용하는 데 따르는 단점 중 하나입니다. 소프트웨어를 처음부터 작성하십시오. UART의 작동 방식을 정확하게 배우고 (필요하기 때문에) 주변 장치를 훨씬 더 잘 이해할 수 있으며 장기적으로 많은 시간을 절약 할 수 있습니다.
DiBosco

답변:


24

DMA는 CPU를 덜어 주므로 동일한 코어에서 실행되는 다른 인터럽트 구동 응용 프로그램의 대기 시간을 줄일 수는 있지만 관련 비용이 있습니다.

  • 단지가 DMA 채널의 제한된 양이 그 채널이 다른 주변 기기와 상호 작용하는 방법에 대한 제한이 있습니다. 동일한 채널의 다른 주변 장치가 DMA 사용에 더 적합 할 수 있습니다.

    예를 들어 5ms마다 벌크 I2C 전송이있는 경우, 가끔 UART2에 도착하는 디버그 명령보다 DMA에 더 적합한 것으로 보입니다.

  • DMA를 설정하고 유지하는 것은 비용 자체입니다. (일반적으로 DMA 설정은 메모리 관리, 관련된 주변 장치 더 많은 수, 인터럽트 자체를 사용하는 DMA 및 DMA 외부의 처음 몇 문자를 구문 분석해야 할 가능성으로 인해 문자 별 인터럽트 기반 전송을 설정하는 것보다 복잡한 것으로 간주됩니다. 어쨌든 아래를 참조하십시오.)

  • DMA는 클럭해야 할 코어의 또 다른 도메인이므로 추가 전력을 사용할 수 있습니다 . 반면에 코어에서 지원하는 경우 DMA 전송이 진행되는 동안 CPU를 일시 중단 할 수 있습니다.

  • DMA는 주변 장치에서 주변 장치로 DMA를 사용하지 않는 한 메모리 버퍼 가 작동 해야 하므로 이와 관련된 메모리 비용이 있습니다.

    ( 문자 당 인터럽트를 사용할 때 메모리 비용 도있을 있지만, 메시지가 인터럽트 내에서 바로 해석되면 훨씬 작거나 사라질 수도 있습니다.)

  • DMA는 전송이 완료 / 반이 완료된 경우에만 CPU에 알림이 전달되므로 대기 시간 이 발생합니다 (다른 답변 참조).

  • 링 버퍼로 /에서 데이터를 스트리밍 할 때를 제외하고 는 수신 / 전송할 데이터의 양을 미리 알아야 합니다.

    • 이는 문자 별 인터럽트를 사용하여 메시지의 첫 번째 문자를 처리해야 함을 의미 할 수 있습니다. 예를 들어, XBee와 인터페이스 할 때 먼저 패킷 유형과 크기를 읽은 다음 할당 된 버퍼로 DMA 전송을 트리거합니다.

    • 다른 프로토콜의 경우 메시지 끝 구분 기호 (예 : 구분 기호로 사용되는 텍스트 기반 프로토콜) 만 사용하는 경우 전혀 불가능할 수 있습니다 '\n'. (DMA 주변 장치가 문자 일치를 지원하지 않는 한)

보시다시피 여기에서 고려해야 할 많은 절충점이 있습니다. 일부는 하드웨어 제한 (채널 수, 다른 주변 장치와의 충돌, 문자 일치)과 관련이 있으며 일부는 사용 된 프로토콜 (구분자, 알려진 길이, 메모리 버퍼)을 기반으로합니다.

일화적인 증거를 추가하기 위해, 나는 매우 다른 프로토콜로 많은 다른 주변 장치를 사용하는 취미 프로젝트에서 이러한 모든 절충점에 직면했습니다. "내가 얼마나 많은 데이터를 전송하고 얼마나 자주 데이터를 전송해야합니까?"라는 질문을 바탕으로 몇 가지 장단점이있었습니다. 이것은 본질적으로 단순한 인터럽트 구동 전송이 CPU에 미치는 영향에 대한 대략적인 추정치를 제공합니다. 따라서 동일한 DMA 채널을 사용하는 몇 초마다 UART 전송을 통해 5ms마다 앞서 언급 한 I2C 전송에 우선 순위를 두었습니다. 또 다른 UART 전송이 더 자주 발생하고 다른 한편으로 더 많은 데이터가 발생하는 경우는 더 드물게 발생하는 다른 I2C 전송보다 우선합니다. 모든 절충점입니다.

물론 DMA를 사용하는 것도 장점이 있지만 그게 당신이 요구 한 것은 아닙니다.


자세한 답변 주셔서 감사합니다. MIDI가 가장 중요한 부분이므로 DMA가 적합하다고 생각합니다 (속도는 낮지 만 31250 보드). 충분한 DMA 채널이 있으며 나중에 4 개의 USART를 사용할 때 다른 STM32를 사용할 것입니다. 5V USB 전원을 사용하기 때문에 CPU를 일시 중단 할 필요가 없으며 메인 루프에서 메시지를 처리하기 위해 메시지간에 처리해야합니다. 256 바이트 읽기 및 256 바이트 전송 버퍼가 있습니다. 필요한 경우 나중에 늘릴 수 있습니다. STM32f103c8t6에는 20KB RAM이 있으며 결국 사용할 STM에는 192KB가 있습니다.
Michel Keijzers

그리고 당신은 나에게 개선하는 방법을 아주 좋은 아이디어를 제공합니다. 지금까지 나는 항상 1 바이트를 읽고 완전한 (MIDI) 메시지가 수신되면 지속적으로 확인합니다. 그러나 첫 번째 바이트를 읽을 수 있으며 그 크기에 따라 대부분 크기가 알려져 나머지를 요청할 수 있습니다. 이것은 또 다른 작은 버퍼 비용이 들지만 괜찮습니다.
Michel Keijzers

DMA로 단일 바이트를 읽는 것은 매우 비효율적입니다. 대기 시간을 줄이고 효율성을 높이려면 크기를 알 수있을 때까지 문자 당 인터럽트를 사용하고 DMA로 전환하는 것이 좋습니다.
Jonas Schäfer

글쎄, (DMA없이) 인터럽트를 사용하는 데 많은 문제가 있었는데, 나는 1 바이트 DMA 수신을 사용할 것이라고 생각하고 그 후에 더 많은 것을 얻기 위해 DMA 요청을 얼마나 많이 예상하고 수행하는지 알고 있습니다.
Michel Keijzers

6
아마도 실수 일 것입니다 . DMA 없이 간단한 인터럽트 코드를 수정해야합니다 .
Chris Stratton

10

DMA를 사용한다는 것은 일반적으로 더 이상 모든 문자에 대한 인터럽트를 수행하지 않고 "버퍼 가득 참"문자를 수신 (또는 전송) 한 후에 만 ​​발생합니다. 이렇게하면 해당 문자 처리 대기 시간이 길어집니다. 첫 번째 문자는 버퍼의 마지막 문자가 수신 될 때까지 처리되지 않습니다.

이 대기 시간은 특히 MIDI와 같은 대기 시간에 민감한 응용 프로그램에서 나쁜 일이 될 수 있습니다. 여기에서 몇 ms는 라이브 공연에 심각한 재생 가능성 문제를 야기 할 수 있습니다.


내가하는 일은 한 번에 1 바이트 (1 바이트의 'DMA'버퍼)를 수신하고 해당 바이트의 모든 DMA 콜백 후에 수동으로 처리하는 링 버퍼에 저장하는 것입니다. 내 메인 루프에서 완전한 MIDI 메시지를 확인하고 처리하려고합니다.
Michel Keijzers

3
DMA는 일반적으로 여러 바이트를 가져 오는 데 사용되며 모두 수신되었을 때만 중단됩니다. DMA를 사용 하지 않을 때 단 1 바이트 후에 중단하는 것이 일반적 이므로 궁금합니다. DMA를 사용하는 추가 합병증의 요점은 무엇입니까?
스티브 멜니코프

5
@MichelKeijzers 그렇다면 여러분이하는 일은 순수한 인터럽트 중심 구현에서하는 것과 거의 동일합니다. 따라서이 경우 DMA를 사용하면 아무런 이점이 없으며 원래 문제는 DMA로 해결되지 않고 (ISR, 설정) 코드를 다시 작성하여 해결할 수 있습니다.
JimmyB

@JimmyB ... 감사합니다 ...하지만 아래 Jonas의 답변으로 인해 메시지가 길면 많은 바이트를 읽도록 개선 할 것입니다. 나는 첫 번째 바이트 (대부분의 경우)를받은 후에 이것을 알고 있습니다. DMA over 인터럽트를 사용하는 것이 더 유리할 것입니다.
Michel Keijzers

8

DMA는 인터럽트를 대체하지 않으며 일반적으로 함께 사용됩니다! 예를 들어, DMA를 사용하여 UART를 통해 데이터를 전송하는 경우 전송이 완료된 시점을 알려주는 인터럽트가 여전히 필요합니다.


실제로, 아마도 STM32에서 (순수 DMA가 아닌) 인터럽트 메커니즘은 직접 DMA에 비해 약간 어색합니다.
Michel Keijzers

2
@duskwuff 실제로는 아닙니다. 당신은 DMA가 완료되면 볼 폴링 할 수 있습니다, 당신은 잘 할 수 원하는 중요한 이유 중 하나 때문에 사용하는 DMA는 프로그램이 그것을 수신에 따라 행동 할 수있는 상태가 될 때까지 시리얼 포트와 귀찮게하지하는 것입니다 데이터. 또는 발신 DMA의 경우 송신 버퍼에 더 추가 할 수 있는지 폴링하기 만하면됩니다.
크리스 스트래튼

1
@MichelKeijzers : 특정 칩을 IDK로 지정하지만 일반적으로 DMA의 대안은 문자 그대로 인터럽트가 아니라 프로그래밍 된 IO입니다 (CPU 명령을 사용하여 I / O 레지스터에서 데이터를 읽거나 쓰는 경우). 인터럽트 처리기에서는 일반적으로 하나의 읽기를 수행 한 다음 첫 번째를 읽는 동안 문자가 들어온 경우, 특히 다른 인터럽트를 트리거하지 않는 경우 다른 읽기를 수행 할 수 있습니다. 또는 그러한 버퍼가있는 경우 내부 버퍼가 비워 질 때까지 읽습니다. 분명히 PIO에 더 많은 인터럽트가 필요하고 다르게 설정하십시오.
Peter Cordes

@ChrisStratton 좋은 점 ... 지금까지 전송할 수 있는지 확인하지 않았지만 확인이 아닌 확인하지 않고 무언가를 전송했습니다. 그렇지 않은 경우 나중에 다시 시도하십시오.
Michel Keijzers

@PeterCordes STM32에 DMA에 대한 충분한 인터럽트가있는 것으로 보이며 매 1 바이트마다 읽을 수 있습니다. 가장 간단한 STM32 (F103c8t6)조차도 충분한 DMA 포트 / 인터럽트를 사용할 수 있습니다.
Michel Keijzers

5

DMA를 사용하면 UART 주변 장치 사용에 대한 다른 모든 고려 사항을 넘어 몇 가지 흥미로운 질문과 과제가 발생합니다. 몇 가지 예를 들겠습니다. uC가 다른 장치와 함께 RS485 (또는 기타) 버스에 있다고 가정합니다. 버스에는 많은 메시지가 있으며, 일부는 귀하의 uC를 대상으로하며 일부는 그렇지 않습니다. 또한 이러한 버스 이웃은 모두 다른 데이터 프로토콜을 사용한다고 가정합니다. 즉, 메시지 길이가 다릅니다.

DMA를 사용할 때만 나타나는 몇 가지 질문은 다음과 같습니다.

  • 언제 중단합니까?
    • DMA는 미리 설정된 양의 데이터를 전송할 때만 인터럽트하는 것을 좋아합니다.
    • DMA 인터럽트를 트리거하기에 충분한 데이터를받지 못하면 어떻게해야합니까?
  • DMA가 중단 될 때 부분 메시지 만 수신하면 어떻게됩니까?
  • RX 버퍼는 어떻게 생겼습니까? 그것들은 선형 또는 원형입니까?
    • DMA는 주소 경계에만 따르지만 원형 버퍼 시스템의 다른 포인터를 지나치는 데 아무런 문제가 없다는 점에서 의미가없는 순환 버퍼 참가자 일 수 있습니다.

어쨌든, 그냥 생각할 음식.


고려해 주셔서 감사합니다. 현재 1 바이트를 수신하여 링 버퍼에 저장합니다. 실제로 내 메시지 (MIDI)의 길이가 다를 수 있으며 다음에 어떤 것이 있는지 알 수 없기 때문입니다. 내 메인 루프에서 메시지를 처리하기위한 완전한 메시지를 확인합니다 (완료되면 링 버퍼에서 메시지를 제거합니다). 그래서 나는 항상 충분한 데이터를 받게됩니다 (바이트를 그리워하지 않는 한, 확인해야합니다). 내 RX 버퍼는 1 바이트이지만 링 / 원형 버퍼에 복사합니다. 가득 찼는 지 확인하지 않았습니다 (추가해야 함).
Michel Keijzers

걱정마 귀하의 응용 프로그램이 잘 프로그램 될 것이라고 확신합니다. 다른 사람들이 언급했듯이 DMA는 훌륭하지만 무료는 아닙니다. 시스템을 사용하지 않고 도망 갈 수 없다면 존재하지 않는 추가 고려 사항을 시스템에 도입합니다.
pgvoorhees

글쎄요, 저는 여전히 초보자입니다.
Michel Keijzers

3

수신 측 (내가 리콜 할 때)에서 DMA는 문자 일치 또는 터미널 수에서 종료됩니다. 일부 프로토콜과 많은 대화식 응용 프로그램은이 모델에 쉽게 맞지 않으므로 실제로 문자별로 처리해야합니다. 통신 링크가 신뢰할 수없는 경우 DMA 기술은 취하기 쉬울 수 있습니다. 스트림에서 단일 문자를 잃어 버리면 DMA 상태 시스템을 쉽게 망칠 수 있습니다.


실제로 바이트 단위로 수신하고 나중에 처리하기 위해 링 버퍼에 수동으로 복사합니다.
Michel Keijzers

1

나는 지금 두 프로젝트에서 STM32CubeMx / HAL을 사용했으며, 생성 한 UART 처리 소프트웨어가 수신 측에 확실한 단점이 있음을 발견했습니다.

전송시 일반적으로 데이터 블록 또는 텍스트 줄을 보내려고합니다. 이 경우 데이터 전송 시간을 미리 알고 있으므로 DMA를 사용하는 것이 확실한 솔루션입니다. 전송이 완료되면 인터럽트가 발생하고 UART TX 완료 콜백 기능을 사용하여 전송이 완료되었음을 주 코드에 표시하고 다른 데이터 블록을 보낼 수 있습니다.

데이터 수신과 관련하여 ST가 제공하는 기능은 전송 장치가 전송을 시작하기 전에 몇 개의 문자를 줄지 알고 있다고 가정합니다. 일반적으로 이것은 알려져 있지 않습니다. 인터럽트 기능은 수신 된 데이터를 버퍼에 저장하고 사전 정의 된 수의 문자를 수신했을 때 사용 가능한 데이터가 있음을 나타냅니다. 순차적 단일 문자 전송을 설정하여 데이터를 수신하기 위해 DMA 또는 인터럽트 기능을 사용하려고하면, 각각의 설정 시간은 가장 느린 데이터 속도 (전송 속도) 이외의 다른 문자로 인해 문자가 손실됨을 의미합니다. 데이터 유실 시작은 프로세서 클럭 속도에 따라 다름) 프로세서를 과도하게로드하여 다른 처리에 대한 명령주기를 남기지 않습니다.

이 문제를 해결하기 위해 데이터를 작은 로컬 순환 버퍼에 저장하고 주 코드 (RTOS 계산 세마포어)에서 읽은 카운트를 설정하여 수신 된 데이터가 준비되었음을 나타냅니다. 그런 다음 메인 코드는 여가 시간에이 버퍼에서 데이터를 수집 할 수 있습니다. 데이터를 수집하기 전에 로컬 버퍼가 오버플로되지 않는 경우 데이터 수집에 약간의 지연이 있는지는 중요하지 않습니다.


난 정확히 똑같아 한 번에 1 바이트를 읽고 순환 버퍼에 저장하고 전체 메시지를 보려면 메인 루프를 확인하려고합니다. 그래도 조금 향상시킬 수 있습니다.
Michel Keijzers

DMA를 설정할 때마다 31,250 보드의 프로세서 / 결측 문자에 과부하가 걸리는 문제가 발생할 수 있다고 생각하십니까?
Michel Keijzers

1
한 번에 여러 문자를 전송하도록 DMA를 설정하면 문제가되지 않습니다. 115200 이상을 실행하는 4 개의 UART와 DMA를 사용하는 I2C가 문제없이 있습니다. UART 전송은 모두 ~ 20 바이트 이상입니다. 문제는 UART (80MHz, 9600baud의 L4 프로세서)에서 수신하기 위해 DMA를 사용하고있었습니다.
uɐɪ

현재 한 번에 1 바이트로 설정했지만 더 많은 바이트가 필요한지 확인하는 것보다 첫 번째 바이트를 수행하고 n을 향상시킬 수 있습니다.
Michel Keijzers
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.