2/18/2022

ESP32 의 Memory 구성-4 (External Memory-2)

1. ESP32의 SPI 기본구성  

ESP32의 External Memory는 SPI로 연결되어 있으며, SPI-Flash 와 SPI-RAM으로 구성되어있다. 

  • SPI 기본연결방식 
SPI 기본통신의 경우 아래와 같이 Data 1 bit의 Serial 통신이지만, QSPI 기능을 이용하여 4 bit 도 통신이 가능하다. 
좀 복잡하게 구성하고자 한다면, Master SPI가 CS 1개로 중간에 FPGA를 이용하여, 
FPGA Arbiter 걸쳐, 두 개의 Peripehral Device Data Line 공유 사용도 가능하다 
물론 상위 구성은 FPGA가 필요하겠지만,   
  1. CS(Chip Select): 단방향 
  2. MOSI(Master Out Slave In):  단방향
  3. MISO(Master In Slave Out):  단방향 
  4. SCLK(Serial Clock): 단방향
https://en.wikipedia.org/wiki/Serial_Peripheral_Interface


1.1. ESP32 SPI Controller 구성확인 

ESP32의 SPI Controller는 4개이지만, 2개는 Arbiter를 사용해서 조합으로 사용하고, 나머지들은 독립적으로 사용가능하다. 
재미있는 구성이며, 이전에, LoRA 때에도, 유사하게, FPGA기반으로 사용한 적이 있는데, 
이것 구성과는 좀 다르다. 

  • ESP32 SPI Controller 구성 
SPI는 총 4개의 Controller 구성되어있지만, 외부와는 3개로 연결되어 동작되며, 사용자입장에서는 3개가 존재한다고 생각하면 되겠다.  

  • 외부 SPI Controller 구조 (CS0/1/2 선택)
  1. SPI: SPI0/1의 조합으로 중간에 Arbiter 중재 혼합하여 사용 
  2. HSPI:  SPI2 연결  
  3. VSPI:  SPI3 연결  
https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf

  • 내부 SPI0/1/2/3 설정 
  1. SPI0의 경우 Buffer로 Cache 와 External Memroy 접근가능
  2. SPI1은 Master로만 설정 DMA로 연결
  3. SPI2/3은 Master or Slave 설정되며, DMA연결 

ESP32의 경우 SPI의 모드가 다양하게 제공하고 있는데, 기본으로 DIO(Dual)를 Data 2 bit이용하고 있다. 
SPI0 과 SPI1 기반으로 사용 

이전에 LoRa Gateway에서 FPGA가 Arbiter 역할을 하며, 마치 버스처럼 사용했는데, 그거하고 좀 다른구조이다. 


1.2.  ESP32의 SPI-External Memory  

  • ESP32 WROVER 의 SPI 연결사항  
  1. SPI Flash/SPI RAM: Data Bus를 모두 공유 SD0/SD1/SD2/SD3 
  2. SPI CS:  CS 독립적사용 
  3. SPI CLK: NC로 각 독립적으로 사용하는 것 같으나, 왠지 같은 PIN을 사용할 거 같음.

 DIO는 SPI0/1만 사용하고 있으며, CS0은 Flash에 GPIO17로 PSRAM에 연결 

https://www.espressif.com/sites/default/files/documentation/esp32-wrover-b_datasheet_en.pdf


상위회로도로 보면, 기본으로 ESP32 QSPI도 지원가능 


1.3.  ESP32의 QSPI 지원 

SPI 2개가 아닌 QSPI로 확장하여 사용할 경우, SPI 2,3 Controller 전부 사용해야한다.   
그러므로, SPI-External Memory 이외 SPI를 하나 더 사용하고자 하면, 
현재로는 아쉽지만, Parrellel QSPI의 기능은 포기해야 할 것으로 생각되어진다. 


Data bus를 확장하여 QIO(Quad)를 이용할 경우 4bit Data 통신도 가능하다. 
SI/SO/WP/HOLD 를 Data Bus로 이용하며 방향도 단방향이 아닌 양방향으로 전환하며, Half duplex되고, Master/Slave가 변경   


https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf



  • Parallel QSPI Master의 Format 
ESP32와 SPI Flash/PSRAM의 경우 QSPI 로 설정해서 통신 Message 형태
  1. Command: SPI Flash (XiP가능) or SPI PSRAM Command 입력 (Read/Write 등등)
  2. Address:  24bit Address
  3. Data: Data: 16bit Data 

https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf



상위에서 SPI_W0_REG 찾아 추가 

2. SPI External Memory 

현재 External Memory라고 하면 SPI Interface로 Flash 와 PSRAM이며 이는 같은 버스를 사용하고 있다. 

  • ESP32 의 PSRAM의 확장 
  1. 현재 4MB (0x3F800000 ~ 0x3FBFFFFF) 확장가능 
  2. BSS Section을 SPIRAM에 사용가능 
  3. Heap Section을 동적으로 할당가능 (CONFIG설정변경해야함)
물론 상위기능이 완벽하게 동작하면 좋겠지만, 아래와 같이 제약사항존재한다.

ESP32 SDKCONFIG 설정 
  • ESP32의 PSRAM(SPIRAM)의 제약사항
  1. PSRAM(SPIRAM)은 DMA가 사용가능하지만, 다른 Periphheral 이 사용중이라면 불가능 
  2. SPI Flash 와 SPIRAM은 같은 버스를 사용하므로, SPIRAM에서 Flash의 XiP를 disable하는 Code는 사용하지 못한다고 한다. 
  3. SPIRAM은 SRAM 보다 속도가 당연히 느리며, 중요한 Code는 가급적 SRAM에 저장

결론적으로 현재 사용하고 있는 Memroy들은 SPI-Flash(XiP) / SPI-RAM / SRAM 인데 각각의 Memroy 속도가 다르다. 


2.1 External Memory(SPI-Flash)

External Memory로 SPI Flash가 기본으로 존재하며, 이곳에 모든 기본 Data들을 저장한다.
더불어 SPI Flash 기반으로 XiP(eXecute in Place)으로 실행도 가능하다고 한다. 

  • QSPI Flash 의 XiP(eXecute in Place) 
  1. XiP 장점:  RAM이 필요 없이 Flash 기반으로 직접 실행이 가능 
  2. XiP 단점:  RAM보다 속도느리며, Write를 못함

SPI Flash도 Serial로 Command/Address/Data 로 구성되기때문에, Serial로 XiP가 가능하다고 한다. 

QSPI XiP Flash 

  • SPI Flash Mode
  1. QIO (Quad I/O): 4 Pin Data Bus를 양방향으로 Address 와 Data 모두 사용 (가장빠름)
  2. QOUT(Quad Output): 4 Pin Data bus로 단방향 추측 
  3. DIO(Dual I/O): 2pin Data Bus를 양방향으로  Address 와 Data 모두 사용 (default)
  4. DOUT(Dual Output): 2pin Data bus를 단방향 추측 
QIO로 이용하여도 Serial 양방향이므로, Half duplex로 이용해야한다. 


2.2 External Memory(SPI-RAM)

주로 SPI에 연결이 되어 있어 SPIRAM 이라고 불리며, 실제 이름은 PSRAM(Pseudo Static RAM)의 약어로 나도 처음 써보는건데, 
아래 글을 읽어보면, DRAM기반으로 Self-Refresh 설정하여 마치 SRAM처럼 사용하는 것이 PSRAM이라는 말이다. 

  • ESP32 사의 Winbond PSRAM
현재 ESP32의 경우 Flash와 PSRAM도 Winbond사 사용( Flash Id로 확인가능)

  • DRAM의 기본정보와 Self Refresh 모드 이해 (DRAM 이해 )  
일반 SoC 가 DRAM에게 Refresh의 경우 와 Self Refresh모드를 사용하는 경우(AP에서 Refresh를 진행안하는 경우)
이 부분은 RAM에대해 자세히 좀 더 알아야 하며, 추후 관심있다면 DRAM 을 보시길 

TI Chip 경우, 보통 EMIF를 통해 Memory Control(DRAM) 진행하며, 관련내용기술 (EMIFA도 있음, NAND 와 NOR를 위해서 )  


PSRAM의 사용이유를 간단히 분석해보면, 보통 AP or SoC 일 경우,
MMU or Memory Interface(EMIF)를 통해 SDRAM을 매번 AP or SoC 자동 Refesh를 해준다  
(일반적으로는 Memory interface가 TI처럼 다 MMU와 분리되어짐)

일반 AP or SoC의 경우, Uboot에서 DRAM 설정을 거의 하게되어있으며, DRAM Timing과 모드를 설정한다. 
하지만, Micom와 같이 MMU or Memory Contoller의 기능부족하거나, MMU or Memory Contoller가 없을 경우, 
SDRAM을 주기적으로 Refresh를 못하므로, 이를 Self Refresh 모드로 변경하여 사용하는 것으로 보인다.   

주의 
MMU에 Memory Contoller(Interface)가 반드시 포함되어야 하는게 아니며, 두개가 분리되어진 것이 있거나, 합쳐진 것이 존재함
일반적으로 SoC 와 AP의 경우는 거의 분리되어져 있음 (혼동하지마시길)  


3. ESP32의 Task 와 External Memory 사용 

ESP32의 경우, FreeRTOS의 모든 Task는 SRAM의 할당된 Heap(IRAM/DRAM)기반으로 동적으로 할당된 TCB와 Stack으로 운영되어진다.
그러니, SRAM영역의 Heap이 부족하면 Task도 생성을 못하고 Stack도 부족하다. 

  • SPI 의 External Memory 주의사항 
물론 개발자가 각 상위 설정변경하여 SPIRAM에서도 Task 내부의 Stack을 사용가능하도록 동작가능하게 변경할 수는 있다. 
아래에서 간단히 소개하겠지만, PSRAM(SPIRAM)에 Static로 할당하여 동작하게 하여, 이곳에 Stack을 SPIRAM으로 할당하는 방식인데, 
이렇게 사용하면, SPI Interface가 에러가 나면서 문제가 발생하는 경우가 발생한다. 

정확한 에러이유는 세부적으로 분석을 안했지만, XiP 와 PSRAM(SPIRAM)의 각 사용 중 급전환 혹은 다른영역 RAM을 갑자기 사용일 것으로 추측한다. 
혹은 SRAM의 프로그램 과 External Memory(SPI-Flash/Memory) 간의 각각 속도차이 문제도 의심 되어진다.  
또는 SPI Interface에서 SPI0/1은 PSRAM과 FLASH가 동시에 사용하지 못하는데, 
동시에 사용해야하는 경우 발생하여 에러 발생할 수도 있을 거 같다는 생각든다.
예들들면, SRAM기반의 Task와 Stack 사용중에는 External Memory를 가져와서 사용가능하나, 
SPIRAM기반으로 Stack을 사용중에 갑자기 SPI Flash를 사용하는 문제가 될 것 같다. 

현재 다양한 추측 및 원인은 많을 것 같은데, 정확한 것은 나중에 시간되면 차근차근 분석하자. 
지금 생각으로는 상위들을 제대로 분석하려면, Cache 동작부터 다 분석해야한다. 

또, 현재 상위 SPI 말고도 한개의 더 SPI2 연결하여 사용하고 있는데, 이 것도 연관성도 있을 것 같기도 하다. 
하지만, 확률적으로 떨어져 보이는데, 나의 경우 SPI2를 사용하기 때문에, SPI controller가 서로 다르기 때문이다.   

  • External Memory SPIRAM 기반으로 Task Stack 사용할 경우 문제사항 
나와 동일하게 xTaskCreateStaic 에 External Memory Stack를 사용해서 에러가 난 경우를 설명해주는데, 글을 읽어보면 결론적으로 거의 사용하지 말라는 거다.
SRAM기반의 Heap에서 Stack을 사용하라는 내용이며, 물론 그래도 하고자 하는 이들이 있다.
그래서 나도 기꺼이 테스트해가면 사용했으며, 사용할 경우는 아래와 같이 사용하도록 하자.  

  • External Memory SPIRAM 기반으로 Task 생성방법  
xTaskCreate 대신 xTaskCreateStatic을 이용하여 Task를 생성하면된다. 
만약 xTaskCreateStaic을 사용한다면 가급적 전부 모든 소스를 SPIRAM기반으로 동작하도록하면 에러가 없는 것으로 보이지만 왠지 불안하다.  
xTaskCreate기반으로도 생성가능