Ubuntu에서 HEIC 이미지를 jpg로 변환

HEIC 이미지는 아이폰에서 고효율로 설정하여 사진을 찍게되면 생성되는 파일입니다. 내보내기를 할때 호환성 모드로 하면 자동으로 png나 jpg로 변환되긴 하는데, 파일을 직접 전송해서 사용하는 경우 HEIC 확장자의 이미지로 보내지게 됩니다.

Ubuntu에서는 아직 HEIC 이미지를 지원하지 않아서, 이를 보기 위해선 jpg로 변환해서 봐야 합니다. 변경할 수 있는 툴은 다음과 같이 설치가 가능합니다.

$ sudo apt install libheif-examples

다음으로 HEIC 이미지가 있는 디렉토리로 이용하여

$ heif-convert IMG_6326.HEIC IMG_6326.HEIC.jpg

와 같이 변경할 수 있습니다.

변경해야 할 이미지가 여러장이라면, 간단한 쉘 스크립트를 사용하면 됩니다.

$ find *.HEIC | xargs -n1 -I {} /bin/bash -c 'heif-convert {} {}.jpg'

이렇게 하면 현재 디렉토리 내에 있는 HEIC 파일을 전부 읽어들여, jpg 이미지로 변경할 수 있습니다.

끝!.

STM32F746G-DISCO with TouchGFX 프로젝트 생성

보드를 구입한 본래의 목적이었던 TouchGFX를 사용하기 위해서 프로젝트 생성. 여러가지 유투브나 문서를 찾아봤지만, 한번에 매끄럽게 되는건 없는듯하다. ST에서 TouchGFX를 인수하였다곤 하지만 하나의 개발도구로 합치는데는 꽤 시간이 걸릴듯 한데… 뭐 그거야 나중 일이고.. 일단은 프로젝트를 생성하고 개발하기 위한 준비단계까지는 되어야 하니….

프로젝트 생성은 예전 데모와 마찬가지로 File > New > STM32 Project 로 시작한다. 보드도 역시 현재 보유한 32F746GDISCOVERY를 선택하고 다음으로 진행.

프로젝트 이름을 입력하고, 개발 언어는 C++로 선택. Finish를 선택하여 생성 시작. 이후 나오는 다이얼로그창에선 모두 Yes로 답하면 됨.

예전 데모와 같이 디바이스 설정을 위한 화면이 나타나면… 이제부터 설정 시작. (앞선 포스팅에선 편하다고 했었는데, 편하긴 개뿔… 좀더 한방에 되면 얼마나 좋아….)


(1) System Core > CORTEX_M7

(2) Connectivity > ETH

(3) Connectivity > QUADSPI

(4) Multimedia > LTDC

(5) TouchGFX 관련

이건 먼저, Additional Software를 클릭하고, 다음의 화면과 같이 TouchGFX를 선택.

그러면, 좌측에 Additional Software 탭과, TouchGFX 관련 설정 항목이 생성됨. Graphics Application를 체크하고 다음과 같이 설정.

(6) Middleware > FREERTOS

스택크기만 4096으로 변경.


이제 Project > Generate Code (Alt+K)를 실행하여 코드 생성. 생성이 완료되면, 프로젝트 창이 다음과 같이 되어야 함.

이제 TouchGFX의 ApplicationTemplate.touchgfx.part를 더블클릭하여 TouchGFX 디자이너를 실행한다. 만약 기존에 설치가 안되어있을 경우, 홈디렉토리 아래의 다음 주소를 가보면, 설치 파일이 존재한다.

C:\Users\bkahn\STM32Cube\Repository\Packs\STMicroelectronics\X-CUBE-TOUCHGFX\4.13.0\Utilities\PC_Software\TouchGFXDesigner

설치를 완료하고 다시 저 파일을 더블클릭하면…

와 같이 디자이너가 실행되고, UI를 디자인할 수 있음. 일단은 Blank UI를 선택한다. 다음과 같이 빈 UI 화면이 나오고 왼쪽의 위젯 화면에서 원하는 컴포넌트를 가져다 붙이면 됨.

테스트용도이니 대충 디자인하고… (이 툴 또한 익숙해져야 하는 것이기에….)

다 되었으면, 오른쪽 상단의 Generate Code를 클릭한다. 아래쪽 상태바에 Generate Done이 뜨면, 다시 CubeIDE로 이동한다. 프로젝트에서 오른쪽 버튼을 누르고 Refresh (F5)를 클릭하면, 파일이 추가됨을 볼 수 있다.

이제 몇가지 코드를 추가 및 수정 필요.

(2-1) STM32F746NGHX_FLASH.ld를 수정

그래픽 등 리소스가 제법 큰 크기를 차지하므로, FLASH 영역에는 다 들어가지 못함. 따라서 보드에 부착된 외장 플래시에 저장해야 하는데, 이를 위해 저 파일을 수정해야 함. 다른 부분만 표시하면…

...
/* Memories definition */
MEMORY
{
  RAM     (xrw)  : ORIGIN = 0x20000000,  LENGTH = 320K
  FLASH   (rx)   : ORIGIN = 0x8000000,   LENGTH = 1024K
  QUADSPI (r)    : ORIGIN = 0x90000000,  LENGTH = 16M
}

...

.ARM.attributes 0 : { *(.ARM.attributes) }

  ExtFlashSection :
	{
		*(ExtFlashSection ExtFlashSection.*)
		*(.gnu.linkonce.r.*)
        . = ALIGN(0x4);
	} >QUADSPI

  FontFlashSection :
	{
		*(FontFlashSection FontFlashSection.*)
		*(.gnu.linkonce.r.*)
        . = ALIGN(0x4);
	} >QUADSPI

  TextFlashSection :
	{
		*(TextFlashSection TextFlashSection.*)
		*(.gnu.linkonce.r.*)
        . = ALIGN(0x4);
	} >QUADSPI

...

(2-2) Drivers에 BSP와 Components 추가.

해당 파일은 TouchGFX 디자이너에서 빈프로젝트를 생성하면 얻을 수 있음. 추가한 다음 C++ 빌드 옵션에 해당 디렉토리 추가.

총 4개의 디렉토리를 추가해야 함.

(2-3) main.c 파일 수정

Core > Src > main.c 를 열고 다음과 같이 추가.

...

/* USER CODE BEGIN Includes */
#include <stm32746g_discovery_qspi.h>
/* USER CODE END Includes */

...

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define REFRESH_COUNT        1835

#define SDRAM_TIMEOUT                            ((uint32_t)0xFFFF)
#define SDRAM_MODEREG_BURST_LENGTH_1             ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_LENGTH_2             ((uint16_t)0x0001)
#define SDRAM_MODEREG_BURST_LENGTH_4             ((uint16_t)0x0002)
#define SDRAM_MODEREG_BURST_LENGTH_8             ((uint16_t)0x0004)
#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL      ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED     ((uint16_t)0x0008)
#define SDRAM_MODEREG_CAS_LATENCY_2              ((uint16_t)0x0020)
#define SDRAM_MODEREG_CAS_LATENCY_3              ((uint16_t)0x0030)
#define SDRAM_MODEREG_OPERATING_MODE_STANDARD    ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE     ((uint16_t)0x0200)
/* USER CODE END PD */

...

/* USER CODE BEGIN PV */
static FMC_SDRAM_CommandTypeDef Command;
/* USER CODE END PV */



static void MX_QUADSPI_Init(void)
{
...
  /* USER CODE BEGIN QUADSPI_Init 2 */
  BSP_QSPI_Init();

  BSP_QSPI_MemoryMappedMode();
  HAL_NVIC_DisableIRQ(QUADSPI_IRQn);
  /* USER CODE END QUADSPI_Init 2 */
}


static void MX_FMC_Init(void)
{
...
  /* USER CODE BEGIN FMC_Init 2 */
  __IO uint32_t tmpmrd = 0;

      /* Step 1: Configure a clock configuration enable command */
      Command.CommandMode            = FMC_SDRAM_CMD_CLK_ENABLE;
      Command.CommandTarget          =  FMC_SDRAM_CMD_TARGET_BANK1;
      Command.AutoRefreshNumber      = 1;
      Command.ModeRegisterDefinition = 0;

      /* Send the command */
      HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT);

      /* Step 2: Insert 100 us minimum delay */
      /* Inserted delay is equal to 1 ms due to systick time base unit (ms) */
      HAL_Delay(1);

      /* Step 3: Configure a PALL (precharge all) command */
      Command.CommandMode            = FMC_SDRAM_CMD_PALL;
      Command.CommandTarget          = FMC_SDRAM_CMD_TARGET_BANK1;
      Command.AutoRefreshNumber      = 1;
      Command.ModeRegisterDefinition = 0;

      /* Send the command */
      HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT);

      /* Step 4: Configure an Auto Refresh command */
      Command.CommandMode            = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
      Command.CommandTarget          = FMC_SDRAM_CMD_TARGET_BANK1;
      Command.AutoRefreshNumber      = 8;
      Command.ModeRegisterDefinition = 0;

      /* Send the command */
      HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT);

      /* Step 5: Program the external memory mode register */
      tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 | \
               SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL    | \
               SDRAM_MODEREG_CAS_LATENCY_3            | \
               SDRAM_MODEREG_OPERATING_MODE_STANDARD  | \
               SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;

      Command.CommandMode            = FMC_SDRAM_CMD_LOAD_MODE;
      Command.CommandTarget          = FMC_SDRAM_CMD_TARGET_BANK1;
      Command.AutoRefreshNumber      = 1;
      Command.ModeRegisterDefinition = tmpmrd;

      /* Send the command */
      HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT);

      /* Step 6: Set the refresh rate counter */
      /* Set the device refresh rate */
      HAL_SDRAM_ProgramRefreshRate(&hsdram1, REFRESH_COUNT);

      //Deactivate speculative/cache access to first FMC Bank to save FMC bandwidth
      FMC_Bank1->BTCR[0] = 0x000030D2;

  /* USER CODE END FMC_Init 2 */
}


void StartDefaultTask(void const * argument)
{
...
  /* USER CODE BEGIN 5 */
  MX_TouchGFX_Process();
...
}

이제 저장하고 프로젝트 빌드 Project -> Build Project. 에러없이 빌드가 완료되면 다음과 같이 각 메모리 영역의 사용량 등이 나옴.

Run > Run을 눌러 보드에 다운로드하고 실행.

이때, Debugger 항목에서 External Loader를 체크하고, 현재보드에 연결된 외장 FLASH 모델을 선택. Apply하고 확인을 눌러 계속 진행.

다운로드가 완료되고 자동으로 보드가 리셋이 되면서 아까 디자인 했던 그대로 화면이 나오는 것을 확인할 수 있음.

이렇게 일단은 셋업을 해놓고 하나씩 붙여나가면 될듯. 끝!