CPU는 DMA나 LTDC가 여전히 이전 픽셀을 읽고 있는 동안에도 TFT 이미지 그리기를 완료할 수 있다. 캐시 가능한 write-back 메모리를 사용하는 Cortex-M7 STM32 설계에서, 최신 CPU 쓰기는 디스플레이 측 리더가 볼 수 있는 메모리가 아닌 dirty 캐시 라인에 남아 있을 수 있다. 그리기 작업의 완료와 그 결과의 게시는 별개의 이벤트이다.
드라이버는 게시 후에도 버퍼를 보호해야 한다. 캐시 범위를 clean하는 것은 CPU가 전송 또는 스캔아웃 엔진이 여전히 사용 중인 픽셀을 덮어쓸 권한을 갖는다는 것을 의미하지 않는다. 이 글은 관련 STM32F7/H7 설계에서 CPU가 생성한 버퍼에 대한 이러한 핸드오프를 검토한다. 수신-DMA 레시피, 범용 STM32 메모리 맵, 또는 하드웨어 테스트 결과를 제공하지 않는다.
렌더링, 가시성, 해제의 분리
세 가지 질문이 핸드오프를 식별한다. CPU가 의도한 픽셀 쓰기를 완료했는가? 선택된 하드웨어 리더가 해당 쓰기를 관찰할 수 있는가? 해당 리더가 버퍼 사용을 중단했는가? 한 질문에 대한 정답이 다른 질문에 대한 답이 되지는 않는다.
write-back 메모리에 있는 CPU가 작성한 소스 데이터의 경우, ST AN4839는 DMA 가시성에 필요한 캐시 유지보수를 설명하고 clean과 무효화를 구분한다. Clean은 dirty 데이터를 메모리 방향으로 다시 기록하며, 대상 시퀀스는 이를 선택된 리더가 볼 수 있도록 해야 한다. 무효화만으로는 dirty CPU 업데이트를 게시하는 대신 폐기할 수 있다.[1]
이전 이미지를 포함하는 예시적 버퍼를 고려하자. CPU는 캐시된 복사본에 마커를 그린다. 새 데이터가 관찰하는 메모리에 도달하지 않았다면 메모리 읽기 장치는 여전히 이전 이미지를 얻을 수 있다. CPU가 자체 마커를 다시 읽는 것이 장치가 이를 본다는 것을 증명하지는 않는다. 두 CPU 작업 모두 동일한 캐시를 사용할 수 있기 때문이다.
이 설명은 리더가 일관된 경로를 통해 CPU의 dirty 캐시 내용을 자동으로 얻지 않는다고 가정한다. 모든 프로세서나 인터커넥트에 이 가정을 적용하지 말고 실제 대상 아키텍처를 확인해야 한다.
유지보수를 선택하기 전에 메모리 경로 확인
정확한 MCU, 버퍼 할당, 리더부터 시작한다. 해당 DMA 엔진 또는 LTDC가 대상의 버스 구조를 통해 할당된 메모리에 접근할 수 있는지 확인한다. 그런 다음 MPU 구성 및 캐시 정책을 포함한 유효 메모리 속성을 확립한다. 버퍼 주소만으로는 두 질문 중 어느 것도 답할 수 없다.

특정 이름의 RAM 영역이 모든 STM32 DMA 엔진에서 접근 가능하다고 일반화하지 말아야 한다. 마찬가지로 framebuffer라는 링커 섹션이 캐시 정책을 확립하지는 않는다. 링커 배치를 런타임 구성 및 선택된 부품의 참조 매뉴얼과 비교해야 한다.
의도적으로 비캐시 가능한 영역은 가시성 문제를 바꿀 수 있지만, 성능 및 구성 결과를 수반하는 설계 선택이다. 소유권 규칙을 제거하지는 않는다. 전체 캐시를 비활성화하면 진단 중 증상이 바뀔 수 있지만, 그 관찰이 원인이나 적절한 양산 수정을 입증하지는 않는다.
ST의 Cortex-M7 권장 사항은 캐시 동작과 디스플레이 메모리 접근 간의 LTDC 주소 조정을 다룬다. 그 범위는 대상별로 특정되며, 캐시 유지보수 자체가 공유 메모리에 대한 접근에 영향을 미칠 수 있다.[2] 해당 지침을 범용 프레임버퍼 위치나 타이밍 처방으로 전환하지 말아야 한다.
리더가 시작하기 전에 최종 CPU 쓰기를 게시
다음 시퀀스는 통합 모델이며 이식 가능한 드라이버 코드가 아니다. 소스 버퍼에 대한 CPU의 쓰기를 완료한다. 인터럽트 콜백을 포함한 모든 생산자가 핸드오프 중에 이를 수정하지 못하도록 한다. 해당 정책과 대상 소프트웨어에서 요구하는 캐시 유지보수를 수행한다. 대상의 필수 순서 및 유지보수 시퀀스를 완료한다. 그런 다음 버퍼를 리더에 제출하거나 노출한다.
늦은 CPU 쓰기는 해당 시퀀스를 깨뜨린다. 애플리케이션이 버퍼를 clean한 후 DMA를 시작하기 전에 상태 아이콘을 수정하면, 아이콘이 게시되지 않은 채로 남을 수 있다. 캐시 작업은 프레임의 이전 버전이 아니라 해당 핸드오프에 대한 최종 데이터를 포함해야 한다.
버퍼를 volatile로 표시하는 것은 dirty 캐시 라인을 clean하지 않는다. 배리어 또한 clean 작업을 대체하지 않는다. 올바른 순서 및 완료 명령은 대상 API와 드라이버 계약에 속하며, 필수 데이터 게시를 대체하는 것이 아니라 함께 수반되어야 한다.
통제된 조사를 위해 마지막 렌더링 이벤트, 유지보수 범위, 제출 이벤트, 완료 이벤트를 기록한다. 이는 그리기 함수 전반에 유지보수 호출을 분산시키고 화면이 더 나아 보이는지 관찰하는 것보다 더 유용한 증거를 제공한다.
요청된 픽셀을 넘어서는 캐시 라인을 고려
Arm CMSIS-Core 5.6.0 M7 문서는 주소 기반 유지보수 함수에 대해 32바이트 정렬된 시작 주소와 바이트 수를 명시한다. 다른 버전의 예제를 사용하기 전에 프로젝트의 CMSIS 구현과 전제 조건을 확인해야 한다.[3]

산술 교육 사례として, 50바이트 dirty 영역이 가상 주소 0x20000013에서 시작한다고 가정하자. 32바이트 유지보수 세분성으로 시작을 내림하고 배타적 끝을 올림하면 다음과 같다:
| 수량 | 예시 값 |
|---|---|
| 요청된 시작 | 0x20000013 |
| 요청된 길이 | 50바이트 |
| 요청된 배타적 끝 | 0x20000045 |
| 정렬된 시작 | 0x20000000 |
| 정렬된 배타적 끝 | 0x20000060 |
| 커버된 유지보수 범위 | 96바이트 |
확장된 범위는 인접 바이트를 포함한다. 할당과 소유권은 이 사실을 고려해야 하며, 특히 관련 없는 객체가 캐시 라인을 공유하는 경우에는 더욱 그렇다. 이 예제는 96바이트 전체가 핸드오프까지 동일한 배타적 소유권 하에 있는 하나의 유효한 할당 내에 있다고 가정한다. Clean은 인접한 dirty 바이트를 다시 기록할 수 있으므로, 관련 없는 작성자와 캐시 라인을 공유하려면 별도의 소유권 설계가 필요하다. API 호출을 위해 범위를 정렬하는 것이 영향을 받는 모든 바이트가 호출자에게 속한다는 증거는 아니다. 원래의 50바이트 수를 여전히 전달하면서 시작을 내리면 의도된 전체 범위를 커버하지 못할 것이다. 여기서 계산된 범위는 96바이트이다.
이 산술은 비어 있지 않은 영역과 유효한 주소 계산을 가정한다. 양산 범위 처리는 오버플로, 길이 제한, 접근 가능한 할당 경계, API별 요구 사항을 확인해야 한다. 예제 주소는 특정 STM32 장치에서 접근 가능한 메모리 영역을 식별하지 않는다.
부분 이미지 업데이트에도 동일한 규율이 필요하다. 리더가 소비할 모든 CPU 작성 메모리 범위를 식별한다. Dirty 사각형은 여러 개의 분리된 행 범위에 걸칠 수 있으며, 가시적 치수만으로는 하나의 연속된 바이트 구간을 정의하지 않는다. 픽셀 형식 변환을 캐시 수정으로 반복하지 않고 확립된 할당 레이아웃을 사용해야 한다.
유효한 해제까지 게시된 버퍼를 변경하지 않도록 유지
게시는 특정 쓰기 집합의 가시성을 확립한다. 소유권은 다음에 누가 버퍼를 변경할 수 있는지를 확립한다. CPU는 clean 호출이 반환되었거나 전송이 큐에 들어갔다는 이유만으로 쓰기를 재개해서는 안 된다.

| 예시적 상태 | 허용되는 작업 | 필요한 전환 증거 |
|---|---|---|
| CPU가 쓰기 가능한 버퍼 소유 | 다음 콘텐츠 렌더링 | 렌더링 완료 |
| 게시 준비 완료 | 대상 요구 사항을 사용하여 최종 쓰기 게시 | 필수 유지보수 및 순서 완료 |
| 리더가 소스를 소유 | 변경되지 않은 콘텐츠 전송 또는 스캔아웃 | 리더별 해제 이벤트 |
| 해제됨 | Return buffer to the writable pool | Driver records ownership change |
A one-shot transfer and continuous LTDC scanout need different release definitions. For a transfer source, the relevant completion must mean that the hardware no longer reads it. For scanout, a submitted address change does not alone prove that the previous framebuffer is free. The driver must establish when the display engine has switched away under the target’s documented lifecycle.
Double buffering helps only when this lifecycle is correct. Two allocations do not prevent the renderer from selecting a buffer still in use. Record which buffer is writable, queued, active, and released, and make those states agree with the actual driver events.
Connect the GUI completion signal to actual reuse
In LVGL 9.5, lv_display_flush_ready() reports flush completion so LVGL can reuse the draw buffer. For an asynchronous transfer from that buffer, report completion only after the driver knows the reader has finished. A custom flush-wait callback offers another documented mechanism.[4]
The integration must define what the flush operation does with its input. If it copies into another owned buffer, the original and destination can have different release events. If the display engine reads the original directly, its lifetime must cover that read. Neither case should be inferred from the callback name alone.
Reporting completion immediately after starting DMA can allow the renderer to overwrite the source mid-transfer. Waiting for a CPU copy to finish can release its source while the destination remains active. Map the GUI’s completion contract onto these actual relationships and the installed library version.
Use observations to choose the next investigation
| 관찰 | 수집할 다음 증거 |
|---|---|
| CPU sees new pixels while display shows old regions | Effective cache policy, final write timing, and published range |
| Changes after publication disappear or arrive late | Writes made after clean and ownership transitions |
| Image mixes content from different updates | Reuse events and active-reader lifetime |
| Behavior changes when cache is disabled | Memory-path and publication evidence; do not declare a final fix |
| Corruption remains with stable, published, owned buffers | Other layers, including bandwidth, layout, and interface timing |
These observations are clues, not unique diagnoses. A stale-looking region can have more than one cause. A synthetic RAM/cache model can demonstrate why publication matters, but it cannot establish memory accessibility, bus timing, or interrupt behavior on a board.
You can reproduce the range calculation without a board: add 50 to 0x20000013, round the start down and the exclusive end up to 32-byte boundaries, then subtract. The result is 96 bytes. This arithmetic does not execute CMSIS or validate hardware cache maintenance.
Once visibility and ownership are documented, investigate other layers on their own evidence. RJY’s LCD pixel clock and display timing guide covers link timing. Its LCD display module interfaces guide provides interface context. Changing those layers does not publish a dirty CPU cache line.
Provide the handoff evidence for integration review
For a scoped discussion, RJY Display에 문의하십시오 with the MCU part, memory placement and MPU policy, display interface, resolution and pixel format, driver handoff sequence, and observed failure. Include exact panel and controller data and the software versions. Project-specific module or board review can then address the documented integration boundary without assuming universal compatibility.



