지난달 UART (MIDI 용)가 인터럽트없이 STM (STM32F103C8T6)과 함께 작동하는 데 많은 시간을 들이지 않고 많은 성공을 거두었습니다.
그러나 오늘 저녁 DMA를 사용하면 꽤 빨리 작동했습니다.
DMA를 읽는 것이 더 빠르고 CPU를 완화시키는 한, 항상 인터럽트를 위해 DMA를 사용하지 않는 이유는 무엇입니까? 특히 STM32에서는 상당히 문제가있는 것 같습니다.
STM32CubeMx / HAL을 사용하고 있습니다.
지난달 UART (MIDI 용)가 인터럽트없이 STM (STM32F103C8T6)과 함께 작동하는 데 많은 시간을 들이지 않고 많은 성공을 거두었습니다.
그러나 오늘 저녁 DMA를 사용하면 꽤 빨리 작동했습니다.
DMA를 읽는 것이 더 빠르고 CPU를 완화시키는 한, 항상 인터럽트를 위해 DMA를 사용하지 않는 이유는 무엇입니까? 특히 STM32에서는 상당히 문제가있는 것 같습니다.
STM32CubeMx / HAL을 사용하고 있습니다.
답변:
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를 사용하는 것도 장점이 있지만 그게 당신이 요구 한 것은 아닙니다.
DMA를 사용한다는 것은 일반적으로 더 이상 모든 문자에 대한 인터럽트를 수행하지 않고 "버퍼 가득 참"문자를 수신 (또는 전송) 한 후에 만 발생합니다. 이렇게하면 해당 문자 처리 대기 시간이 길어집니다. 첫 번째 문자는 버퍼의 마지막 문자가 수신 될 때까지 처리되지 않습니다.
이 대기 시간은 특히 MIDI와 같은 대기 시간에 민감한 응용 프로그램에서 나쁜 일이 될 수 있습니다. 여기에서 몇 ms는 라이브 공연에 심각한 재생 가능성 문제를 야기 할 수 있습니다.
DMA는 인터럽트를 대체하지 않으며 일반적으로 함께 사용됩니다! 예를 들어, DMA를 사용하여 UART를 통해 데이터를 전송하는 경우 전송이 완료된 시점을 알려주는 인터럽트가 여전히 필요합니다.
DMA를 사용하면 UART 주변 장치 사용에 대한 다른 모든 고려 사항을 넘어 몇 가지 흥미로운 질문과 과제가 발생합니다. 몇 가지 예를 들겠습니다. uC가 다른 장치와 함께 RS485 (또는 기타) 버스에 있다고 가정합니다. 버스에는 많은 메시지가 있으며, 일부는 귀하의 uC를 대상으로하며 일부는 그렇지 않습니다. 또한 이러한 버스 이웃은 모두 다른 데이터 프로토콜을 사용한다고 가정합니다. 즉, 메시지 길이가 다릅니다.
DMA를 사용할 때만 나타나는 몇 가지 질문은 다음과 같습니다.
어쨌든, 그냥 생각할 음식.
수신 측 (내가 리콜 할 때)에서 DMA는 문자 일치 또는 터미널 수에서 종료됩니다. 일부 프로토콜과 많은 대화식 응용 프로그램은이 모델에 쉽게 맞지 않으므로 실제로 문자별로 처리해야합니다. 통신 링크가 신뢰할 수없는 경우 DMA 기술은 취하기 쉬울 수 있습니다. 스트림에서 단일 문자를 잃어 버리면 DMA 상태 시스템을 쉽게 망칠 수 있습니다.
나는 지금 두 프로젝트에서 STM32CubeMx / HAL을 사용했으며, 생성 한 UART 처리 소프트웨어가 수신 측에 확실한 단점이 있음을 발견했습니다.
전송시 일반적으로 데이터 블록 또는 텍스트 줄을 보내려고합니다. 이 경우 데이터 전송 시간을 미리 알고 있으므로 DMA를 사용하는 것이 확실한 솔루션입니다. 전송이 완료되면 인터럽트가 발생하고 UART TX 완료 콜백 기능을 사용하여 전송이 완료되었음을 주 코드에 표시하고 다른 데이터 블록을 보낼 수 있습니다.
데이터 수신과 관련하여 ST가 제공하는 기능은 전송 장치가 전송을 시작하기 전에 몇 개의 문자를 줄지 알고 있다고 가정합니다. 일반적으로 이것은 알려져 있지 않습니다. 인터럽트 기능은 수신 된 데이터를 버퍼에 저장하고 사전 정의 된 수의 문자를 수신했을 때 사용 가능한 데이터가 있음을 나타냅니다. 순차적 단일 문자 전송을 설정하여 데이터를 수신하기 위해 DMA 또는 인터럽트 기능을 사용하려고하면, 각각의 설정 시간은 가장 느린 데이터 속도 (전송 속도) 이외의 다른 문자로 인해 문자가 손실됨을 의미합니다. 데이터 유실 시작은 프로세서 클럭 속도에 따라 다름) 프로세서를 과도하게로드하여 다른 처리에 대한 명령주기를 남기지 않습니다.
이 문제를 해결하기 위해 데이터를 작은 로컬 순환 버퍼에 저장하고 주 코드 (RTOS 계산 세마포어)에서 읽은 카운트를 설정하여 수신 된 데이터가 준비되었음을 나타냅니다. 그런 다음 메인 코드는 여가 시간에이 버퍼에서 데이터를 수집 할 수 있습니다. 데이터를 수집하기 전에 로컬 버퍼가 오버플로되지 않는 경우 데이터 수집에 약간의 지연이 있는지는 중요하지 않습니다.