TouchGFX 는 C++ 입니다. 임베디드는 C언어를 메인으로 사용하는 곳이 많기 때문에 TouchGFX (C++) 에서 기존 코드인 C언어의 함수를 콜해야 하는 경우가 많습니다. 

 

쉽게 알 수 있지만 한번 남겨 봅니다. 

C 언어에서 C++ 사용할 수 있게 설정 ]

#ifndef _API_CONSOLE_H_
#define _API_CONSOLE_H_

#ifdef __cplusplus
extern "C" {
#endif

extern tstate API_Display_SetBrightness(u32 u32_brightness);

#ifdef __cplusplus
}
#endif


#endif

TouchGFX C++]

extern "C" {
#include "api_data.h"
}

 

C Function Call]

void Menu_Display1View::setupScreen()
{
    Menu_Display1ViewBase::setupScreen();
    
    API_Display_SetBrightness(50);
}

 

API_Display_SetBrightness 처럼 바로 Call 하여 사용할 수 있습니다. 

 

 

Wildcard 정의 ] 

Use wildcard buffer Check 하여 Wildcard 넣습니다.

 

 

 

 

Wildcard naming]

 

 Wildcard 넣고 Code generation 합니다.

Wildcard ViewBase.hpp 정의 되어 있습니다.

Buffer 네이밍은 nameBuffer, Buffer size NAME_SIZE 정의 됩니다.

 

 

Tickhandler 정의]

 

handleTickEvent virtual 상위 클래스에 정의되어 있어서 상속 받아 정의 해야 합니다.

1 tick 마다 호출 되는 periodic 함수 입니다.

아래처럼 .hpp 정의 합니다.

 

.cpp Unicode::snprintf 등을 이용하여 버퍼에 내용을 넣습니다.

마지막에 invalidate() 화면을 업데이트 시켜줘야 화면이 나옵니다. (중요)

 

 

컴파일 실행하면 value 계속 올라가면서 display 되는 것을 있습니다.

 

 

 

UART 란 ]

Universal Asynchronous Receiver/Transmitter 로 굳이 해석하자면 범용 비동기식 수신기/송신기이다. 

 

 

HW 연결 예시 ]

  • 3 line 이 필요 (TX, RX, GND)
  • TX 는 상대의 RX 에, RX 는 상대의 TX 에 연결하며, GND 레벨을 맞추기 위해 GND 끼리 연결

HW 연결 예시

 

 

Signal ]

Signal 은 Start bit, Data bit, Parity bit, Stop bit 로 구성되어 있습니다. 

1 byte 를 보내는 예시는 아래와 같습니다. 

다만 여기에서 패리티 비트는 사용하지 않는 경우도 많습니다. 

 

 

UART signal 예시

 

 

설정 ]

아래는 Teraterm 의 설정 예시입니다. 포트 번호, 속도, 데이터, 패리티비트, 스탑비트, 흐름제어를 선택할 수 있습니다. 

속도는 bps 라서 만약 115200 을 선택한다면 115200 / 8 = 14400 byte/sec 

이는 약 14 kbytes/sec 입니다. 여기에서 start bit, stop bit 는 연속으로 보낼경우 큰 영향을 끼치지 않지만, Parity bit 를 넣는다면 / 9 를 해주어야 합니다. 

 

 

 

[ 사용 환경 ]

IAR compiler 8.50.1

디버거 : I-Jet

MCU : ADuCM355

 

[ 이슈 ]

Interrupt Vector Table 위치를 옮기는 icf 파일 변경하는 구현 중 이상이 생겼었습니다. Compile 은 잘되는데, flash download 시  "The flash loader program reported an error" 팝업이 뜨면서 writing 이 안되는 문제. 

 

[ 결론 ]

Option -> Debugger -> Download -> "Use Flash loader(s)" 비활성화 (Uncheck) 

 

이후 download 잘되고, Download된 이후에 다시 Use Flash loader 를 체크해도 재 다운로드 잘됩니다. 

 

정확한 이유는 모르겠는데, Interrupt Vector Table 위치를 옮기는 icf 파일 변경하는 구현 중 이상이 생겼었습니다. 

 

구글링등으로 보아 J-Link 사용시 가끔씩 internal flash 설정이 잘못되면 뜨는것으로 예상됩니다.

<Uncheck "Use flash loader(s) >

 

[ Reference ]

https://ez.analog.com/analog-microcontrollers/ultra-low-power-microcontrollers/f/q-a/19447/error-the-flash-loader-program-reported-an-error

 

Error "The flash loader program reported an error" - Q&A - Ultra Low Power Microcontrollers - EngineerZone

 

ez.analog.com

 

[ 사용 환경 ]

IAR compiler 8.50.1

디버거 : I-Jet

MCU : ADuCM355

 

 

아래 Project option -> Debugger -> Download -> Verify downlaod 옵션 on 합니다.

 

 

 

 

Compile 잘되지만 Writing 시에 아래와 같이 에러와 워닝이 생깁니다.

 

 

디버그 로그는 아래와 같이 메모리를 잘못설정한것으로 나옵니다.

 

하지만 이게 Analog device 사에서 제공한 기본 프로젝트 입니다. 그래도 도움을 받아 .icf 파일을 수정하였습니다.

Warning 하나는 없어졌지만 빨간색 error 그대로 남아 있습니다.

물론 Option 에서 Verifiy download uncheck 하면 오류는 사라집니다. 다만, 브레이크 포인트를 제대로 사용할 수가 없습니다.

 

IAR 사에 문의하니 IDE 프로브의 버전이 맞지 않는 경우에도 위의 에러가 생길수도 있다고 답변을 받았습니다.

또한 에러가 나는 번지인 0x0000001 확인하라고 하였습니다.

 

우연히 Analog device 사의 데모 보드를 사용하면서 프로브(디버거) I-Jet 에서 J-Link 변경하였습니다.

위의 에러와 워닝이 모두 사라졌습니다. 브레이크 포인트도 사라졌습니다.

 

제가 사용한 환경에서는 J-Link 사용을 추천드립니다.

MISRA 보면 #, ## 매크로에서 2번쓰지 말라는 규칙이 있다. 그런지 궁금해서 찾아봤다.

 

 

Rule 요구사항과 Justification 영문은 이렇다.

There shall be at most one occurrence of the # or ## operators in a single macro definition

 

Because the evaluation order of # and ## are not specified, the results of using them both in the same macro could be unpredictable. Therefore macros should contain at most once instance of either # or ##.

 

 

해석해보니

"# ## 연산 순서가 지정되어 있지 않기 때문에 동일한 매크로에서 둘다 사용하는 경우에 결과를 정확히 예측할 없기 때문에 # 또는 ## 한번만 포함해야 한다 " 뜻이다.

 

 

[ 오류가 예상되는 예시 ]

#define NonCompliant(a, b)  # a ## b
int main() {
  std::cout << NonCompliant(Hello, World);
}

 

 

코드에서 컴파일러가 2가지 경우를 내보낼 있다.

  1. ## 먼저 연산할 경우 : HelloWorld
  1. # 먼저 연산할 경우 : *Hello "World *

나올 있다.

 

 

[ 규칙을 지킨 예시 ]

 

#define Stringfy(a) #a
#define Compliant(a, b)  Stringfy(a##b)

int main(){
  std::cout << Compliant(Hello, World);
}

 

이 경우에 정확히 HelloWorld 가 프린트 된다

 

[ Reference ]

 

MISRA C 2012, Rule 20.11

MISRA C 2004, Rule 19.12

typedef struct RTC_SR1 {
  union {
    struct {
      uint16_t reserved0  :  7;
      uint16_t WPNDCR0    :  1;  /**< Pending status of posted writes to RTC Control 0 Register */
      uint16_t WPNDSR0    :  1;  /**< Pending status of posted clearances of interrupt sources in RTC Status 0 Register */
      uint16_t WPNDCNT0   :  1;  /**< Pending status of posted writes to RTC Count 0 Register */
      uint16_t WPNDCNT1   :  1;  /**< Pending status of posted writes to RTC Count 1 Register */
      uint16_t WPNDALM0   :  1;  /**< Pending status of posted writes to RTC ALARM 0 Register */
      uint16_t WPNDALM1   :  1;  /**< Pending status of posted writes to RTC ALARM 1 Register */
      uint16_t WPNDTRM    :  1;  /**< Pending status of posted writes to RTC Trim Register */
      uint16_t reserved14 :  2;
    };
    uint16_t VALUE16;
  };
} RTC_SR1;

 

위의 코드는 4 byte 짜리 구조체를 선언하였습니다. 4 byte 구조체에서 8 번째 1 bit, 9번째 1 bit 를 사용하기 위해서는 위와 같이 union 으로 4 byte 를 공용해서 사용하면 사용이 매우 수월해지네요. 

 

RTC_SR1.WPNDCR0 = 0  과 같이 사용이 가능합니다. 

*TouchGFX SPI LCD 사용시 반만 Display 되는 경우 *

 

TouchGFX 사용시 Serial 방식을 사용할 경우 FrameBuffer 를 한줄씩 보내는 코드입니다.

 

void TouchGFXHAL::copyFrameBufferBlockToLCD(const Rect& rect)
{
    __IO uint16_t* ptr;
    uint32_t height;

    // This can be accelerated using regular DMA hardware
    for (height = 0; height < rect.height ; height++)
    {
        ptr = getClientFrameBuffer() + rect.x + (height + rect.y)  * BSP_LCD_GetXSize();
        LCD_IO_WriteMultipleData((uint16_t*)ptr, rect.width);
    }
}

 

 

 

TouchGFX 의 공식 Support 홈페이지에 있는 코드인데 32bit 임베디드 시스템을 사용할 경우 생각대로 동작 안할 수 있습니다.

support.touchgfx.com/docs/development/touchgfx-hal-development/scenarios/scenarios-fmc

예를 들면,

 

 

 

#define FRAME_BUF_ADDR   0xD0000000
#define WIDTH            320
#define COLOR_DEPTH      3

__IO uint16_t* ptr;
ptr = FRAME_BUF_ADDR;
ptr = ptr + (WIDTH * COLOR_DEPTH);

 

 

0xD0000000 + (320 * 3) = 0xD00003C0 을 예상합니다.

하지만, 0xD00000780 이 나옵니다.

 

 

 

바로 __IO uint16_t* ptr; 때문입니다. 
아래와 같이 __IO uint8_t * ptr 로 수정해 줍니다. 

 

 

void TouchGFXHAL::copyFrameBufferBlockToLCD(const Rect& rect)
{
    __IO uint8_t* ptr;
    uint32_t height;

    // This can be accelerated using regular DMA hardware
    for (height = 0; height < rect.height ; height++)
    {
        ptr = getClientFrameBuffer() + rect.x + (height + rect.y)  * BSP_LCD_GetXSize();
        LCD_IO_WriteMultipleData((uint8_t*)ptr, rect.width);
    }
}

 

 

0xD0000000 + (320 * 3) = 0xD00003C0 이 나옵니다.

+ Recent posts