‘리니어 PSM용 린두이노’

대부분의 PSM 디자인은 ‘셋 앤 폴겟(set and forget; 한번 설정 후 신경 쓰지 않아도 되는)’ 방식이다. LT파워플레이(powerPlay)를 사용함으로써 PSM(Power System Management) 디바이스를 간편하게 셋업 및 디버깅할 수 있다.

또 벌크 프로그래밍 솔루션을 결합적으로 사용하면 펌웨어가 필요하지 않다. 그런데 많은 대규모 시스템은 BMC(board management controller)를 필요로 한다. 그렇다면 펌웨어는 PSM을 위해서 무엇을 할 수 있을 것인가?

PSM 펌웨어의 토대는 PM버스(Bus)이다. PM버스의 토대는 SM버스다. SM버스의 토대는 I2C다. PSM 펌웨어를 사용해서 부가가치를 높이는 BMC를 작성하기 위해서는 이들 각 프로토콜에 대한 어느 정도의 지식을 필요로 한다. 아니면 이미 작성돼 있는 라이브러리를 사용함으로써 프로그래머가 상세한 것까지 이해할 필요 없이 편리하게 코드를 작성할 수 있다.

린두이노(Linduino) 라이브러리는 이들 각각의 프로토콜 층을 취급하고 있으며 API(application programming interface)를 제공하므로 PSM 펌웨어를 수월하게 작성할 수 있다. 린두이노 PSM은 BMC를 대체하기보다 통상적인 BMC 펌웨어와 호환 가능한 일련의 라이브러리 및 예제들이다.

또 린두이노와 LTC 데모 회로를 학습 툴로 활용할 수 있다. 많은 BMC 디자인은 이미 SM버스 API를 갖추고 있으므로 PM버스가 어떻게 작동하는지 빠르게 살펴보면 될 것이다.

엔지니어들이 린두이노 코드 조각을 기존의 애플리케이션으로 복사/붙여넣기 해서 사용하는 것을 흔히 볼 수 있다. 하지만 또 린두이노 층들 중의 하나를 구현하고 ▲장치 및 레일 인식 ▲명령 API ▲결함 로그 디코딩 ▲인-시스템 프로그래밍(in-system programming) 등을 포함하는 전체적인 라이브러리를 재사용하는 것도 가능하다.

이 글에서는 린두이노 라이브러리, PSM 프로그래밍, 데모 회로를 사용한 린두이노 PSM의 셋업 및 사용, PSM 디버깅에 대해 살펴보려고 한다. 프로토콜에 관한 상세한 정보와 일반적인 프로그래밍에 관해서는 리니어의 애플리케이션 노트 135(AN135) ‘LTC3880 용의 견고한 PM버스 소프트웨어 작성 및 I2C/SM버스/PM버스 표준’에서 볼 수 있다.

◇ 린두이노 PSM 하드웨어

린두이노 PSM 하드웨어는 린두이노(DC2026)와 I2C 핀들을 데모 보드나 제품 보드의 PMBus/SMBus/I2CBus로 연결하기 위한 쉴드 보드(DC2294)로 이뤄진다.

학습을 극대화하기 위해서는 DC2026(Linduino), DC2294(쉴드 보드), DC1962(파워 스틱), 토탈 페이즈(Phase) 비글 보드(I2C 스니퍼)를 사용하는 것에서부터 시작할 수 있다. 이들 하드웨어를 사용해서 컨트롤러(LTC388X)와 매니저(LTC297X)를 프로그래밍하고 디버깅 및 학습할 수 있다.

[그림1] 평가 하드웨어

[그림 1]은 권장 평가 하드웨어를 연결한 모습이다. 이 하드웨어를 실행하려면 2개 USB 케이블을 사용해서 린두이노와 비글 보드를 컴퓨터로 연결한다. 비글 USB를 연결하지 않았을 때는 PM버스 트래픽이 DC1962로 간섭을 일으키는 것을 막기 위해서 비글의 리본 케이블을 DC2294로부터 분리시키도록 한다.

시스템 보드로 연결하는 경우에는 대부분 DC2086을 사용하는 것이 효과적일 것이다.
DC2086[그림2]은 DC2294로부터 연결을 수용할 수 있으며 12핀 리본, 14핀 리본, 4핀 케이블을 연결할 수 있다. 또 린두이노가 공급할 수 있는 것보다 더 많은 전력을 필요로 하는 시스템 보드의 경우에는 DC2086으로 외부 전원 입력을 사용할 수 있다.

 [그림2] 시스템 하드웨어

◇ 린두이노 PSM 스케치

PMBus 라이브러리가 어떻게 작동하는지 살펴보기 앞서 DC1962 스케치를 간략하게 살펴봄으로써 린두이노 PSM의 일반적인 활용 모델을 이해할 수 있을 것이다. 또 전문적인 프로그래머가 아니더라도 코드를 작성하기가 얼마나 쉬운지 알 수 있다.

이 단계들을 따라 하기 위해서는 2개의 다운로드가 필요하다. 아두이노(Arduino) 툴과 린두이노 스케치북(Linduino Sketchbook)이다.

아두이노 툴은 다양한 플랫폼을 지원한다. 이 글에서는 64비트 우분투(Ubuntu) 14 TLS상에서 아두이노 1.6.4를 사용해 실행하는 것을 가지고 설명하고 있다. 그러면 이제 시작해 보자.

Step 1: 구성하기

아두이노 소프트웨어를 처음 실행하면 리니어에서 다운로드한 린두이노 스케추북이 아니라 디폴트 스케치북을 사용한다. 이것을 린두이노 스케치북으로 변경하려면 [그림 3]에서 보는 것처럼 메뉴 바에서 파일(File) | 프리퍼런스(Preferences)를 선택한다.

[그림3] 프리퍼런스(Preferences) 대화상자 열기
 [그림4] 프리퍼런스(Preferences) 대화상자

[그림4]의 프리퍼런스(Preferences) 대화상자에서는 맨 위에 스케치불 로케이션( Sketchbook Location)을 볼 수 있다. 브로우즈(Browse) 버튼을 사용해서 <www.linear.com/linduino>에서 다운로드한 LT스케치북으로 이동한다. 그리고 디스플레이 라인 넘버(Display line numbers)와 쇼 벌보스 아웃풋 듀링 컴필레이션(Show verbose output during compilation)에 체크를 하는 것이 좋다. 후자의 설정은 명령 라인 상에 컴파일러 메시지를 스크롤하기 때문에 보기가 더 편하다.

경로를 설정한 다음에는 모든 아두이노 창을 닫고 아두이노 소프트웨어를 다시 시작해야 한다. 아두이노를 다시 시작하면 스케치북 디렉토리를 다시 스캔하고 그에 따라서 아두이노 메뉴를 빌드업 한다. 아두이노 소프트웨어를 재시작 하지 않으면 메뉴들이 LT스케치북을 반영하지 못하고 이전의 스케치북을 가리킬 것이다.

Step 2: 스케치 로드하기

[그림5]와 같이 따라 해서 ‘hello_world 스케치’를 로드 한다. 스케치를 로드 하면 [그림6]에서와 같이 이 스케치를 보여주는 창이 열린다.

[그림 5] hello_world 스케치 로드하기
[그림6] 스케치 창
[그림7] 아두이노 툴
[그림8] 아두이노 명령창
[그림 9] 스케치 메뉴

 Step 3: 컴파일하고 실행하기

[그림7]에서 보는 것처럼, 툴바 상의 체크 표시를 누르면 스케치를 컴파일한다.

오른쪽 방향 화살표는 스케치를 컴파일하고 컴파일 된 스케치를 린두이노 하드웨어로 로드 한다. 돋보기 표시는 스케치 출력을 디스플레이 한다.<주의: 아두이노 보드 타입을 ‘아두이노 우노’로 설정해야 하고 포트를 선택해야 한다. 해당 툴의 메뉴 참조>

스케치를 로드 한 다음에는 오른쪽의 돋보기 표시를 누른다. 그러면 콘솔 창이 열린다. [그림8]과 같이 하려면 라인 엔딩을 ‘케리지 리턴(Carriage return)’으로 설정하고 보 레이트(baud rate)를 115200으로 설정한다.

스케치와 상호작용하려면 상단의 상자(Send 버튼의 왼쪽) 안에 커서를 놓고 메뉴에서 원하는 번호를 입력하고 센드(Send) 버튼을 마우스로 직접 누르거나 키보드의 엔터 키인 <CR>을 누른다. 그러면 스케치가 해당 명령을 실행하고 다시 메뉴를 표시한다.

Step 4: 메뉴 항목 알아보기

[그림9]는 1을 입력해서 베이직 코맨드(Basic Commands) 창으로 전환하고 그리고 다시 1을 눌러서 리드 올 볼테지스(Read All Voltages를) 선택했을 때 어떻게 되는지 보여준다. 그러면 DC1962의 모든 레일에 대해서 측정된 VOUT 값을 읽고 프린트한다.

상단 왼쪽 모서리의 X 표시를 누르면 콘솔을 닫을 수 있다. 이렇게 닫을 때까지 스케치는 계속해서 실행된다. 콘솔을 다시 열면 이 스케치를 다시 시작한다.

이런 식으로 다른 메뉴 옵션들도 시도해 볼 수 있다. 그리고 비글 보드를 사용하는 것에 익숙해지면 트레이스(trace) 기능을 실행하고 버스 트랜잭션을 살펴볼 수 있다.

Step 5: 코드 변경하기

스케치는 2개의 입력 지점을 사용할 수 있다. setup() 함수는 일회적으로 호출되며 loop() 함수는 루프로 무한정 호출된다. 이들 함수는 아두이노 코딩 환경에 속하는 것이다. 전문적인 C 프로그래머라면 main()는 어디에 있는가 하고 의아해 할 것이다. 아두이노 라이브러리는 사전에 정의된 main()를 사용해서 setup()와 무한 루프 호출 loop()를 호출한다.

메뉴들은 스케치 내에 헬퍼(helper) 함수로 코드화 되어 있으며, loop()가 메인 메뉴를 호출한다. 각 메뉴는 케이스문을 사용해서 지원되며, 각 케이스문이 하나의 메뉴 번호를 처리한다.

프로그래머들만 알아들을 수 있는 말은 여기까지 충분하다. 애플리케이션을 변경하기 위해서는 단지 제공된 API를 사용해서 스케치 내의 케이스(case) 문을 변경하기만 하면 된다. 스케치 내에서 PM버스 명령을 발행하는 함수들(API)은 별도의 라이브러리로부터 제공되며, 코드로 하려는 일을 이해하기 쉽게 단순한 이름들로 되어 있다. 예를 들면 다음과 같다.

voltage = pmbus->readVout(0x30, false)

이것을 풀이하면 PM버스 API를 사용해서 어드레스 0x30의 출력 전압을 읽고 폴링은 하지 않은 채 이것을 볼테이지(voltage)라고 하는 이름의 변수로 집어넣으라는 뜻이다.

여기서 몇 가지 변경을 할 수 있다. 예를 들어서 출력 전력을 읽고 프린트하라는 메뉴 항목을 추가할 수 있다. 아직 스스로 직접 해 볼 준비가 된 것 같지 않으면 계속해서 내용을 읽어가면서 코드 작성에 대해 학습할 수 있다. 아니면 다음과 같이 시도해볼 수도 있다.

float readPout(uint8_t address, bool polling)

LTC3880으로 파워 스틱의 어드레스 0x30에 대해서 이 명령을 시험해 볼 수 있을 것이다. 이 명령이 어떻게 작동하는지 알아보기 위해서 파워 스틱의 채널 0으로 저항이나 전류 부하를 추가해 볼 수 있다. 그리고 스케치의 프린트가 일치하는지 확인할 수 있다.

◇ 린두이노 PSM PMB버스 라이브러리

PM버스 라이브러리는 LTSketchbook/libraries/LT_PMBUS 디렉토리의 LT스케치북 트리 안에 들어 있다. 이 라이브러리는 층으로 돼있다. 제일 먼저 TWI(Two Wire Interface)에서 시작해서 그 다음은 I2C와 SM버스이고 끝으로 PM버스다.

또 값을 L11/L16(PMBus 형식)에서 부동소수점이나 그 반대로 변환하기 위한 숫자 변환 API가 들어 있다. 더불어 그룹 컴맨드 프로툴(Group Command Protocol) 지원, 장치 및 레일 인식, 결함 로그 디코딩, 인-시스템 프로그래밍 기능까지 들어 있다.

각 층은 단순한 C++ 클래스다. 아두이노에서 직렬 및 여타 IO 기능에 클래스를 사용하는 것과 같은 식이다. 최종 환경이 C라면 걱정할 것이 없다. 여기서 단순하다는 것은 많은 메모리 오버헤드를 일으키지 않으면서 C++ 클래스를 사용할 수 있다는 것을 의미하거나 또는 클래스 랩핑(class wrapping)을 제거하고 순수한 C로서 아주 편하게 사용할 수 있다는 것을 의미한다.

C++ 랩퍼는 단지 애플리케이션 코드를 간소화하고 비전문적 프로그래머들이 더 쉽게 사용할 수 있도록 하기 위한 것이다.

다만 더 깊이 있게 이해하고자 하는 프로그래머들을 위해서 말하자면 SM버스 클래스는 계층을 이루고 있어서 애플리케이션 코드가 PEC를 온 및 오프로 전환하는 것과 무관하며 이식을 용이하게 한다.

LT_I2C.h, LT_SMBus.h, LT_PMBus.h가 API 층을 이루고 있다. 린두이노 PSM 라이브러리를 이식하려면 이들 API 중의 어느 하나를 선택하고 자체적인 라이브러리를 사용해서 자신의 플랫폼으로 구현할 수 있다.

가장 흔한 이식은 LT_SM버스베이스(BusBase) 클래스를 다시 구현하는 것이다. 이렇게만 하면 PM버스 클래스와 수학 변환이 작동하고 또 모든 다른 기능들과 예제들이 작동한다.

[그림10] LT_PMBus 클래스 다이어그램
[그림11] 인크루드 라이브러리 메뉴
[그림12] 기초적인 인클루드
[그림13] 정적 변수


◇ PM버스 라이브러리의 사용

이 라이브러리는 클래스에 관한 이러한 이해 없이도 사용할 수 있다. 몇 번의 불러오기와 정적 변수들만 사용해서 스케치를 실행할 수 있는 준비가 된다.

[그림11]에서 보듯이 스케치(Sketch) 메뉴를 사용해서 이 라이브러리를 추가할 수 있다. 가장 중요한 인크루드(include)는 [그림12]에서 보는 것들이다.

한 스케치는 최소한 2개의 정적 변수를 포함한다. [그림13]에서 보듯이 하나는 SM버스용이고 다른 하나는 PM버스용이다. SM버스 변수는 팩(Pec)이거나 노팩(NoPec)이다.

깨끗한 층(clean layer)의 좋은 점은 프로젝트 필요에 따라서 애플리케이션 코드를 SM버스 코드나 PM버스 코드로 작성할 수 있다는 것이다. PM버스 API를 사용해서 애플리케이션을 작성하면 명령 코드와 데이터 형식화에 관련된 디테일을 은폐할 수 있으며 SM버스 API를 사용해서 애플리케이션을 작성하면 모든 가능한 명령 코드를 액세스할 수 있고 원시 값들을 직접적으로 액세스할 수 있다.

두 변수를 초기화했으면 smbus→를 통해서는 전체적인 SM버스 API를 사용할 수 있으며 pmbus→를 통해서는 전체적인 PM버스 API를 사용할 수 있다. 동일한 애플리케이션으로 두 API를 다 사용할 수 있다.

LT_PM버스매스(BusMath)

LT_PMB버스매스 클래스는 L11/L16과 부동소수점 사이의 변환을 위한 고도로 최적화된 숫자 변환 라이브러리다. PM버스 코드는 부동소수점이 필요하지 않으며 일부 최종 사용자 애플리케이션은 정수만으로 작성할 수 있다.

특히 전압과 전류 값을 미리 아는 경우나 아주 소형의 마이크로컨트롤러를 사용함으로써 부동소수점 변환이 너무 느린 경우에 그렇다. 펌웨어는 이러한 변환을 필요로 하지 않더라도 오프라인 애플리케이션은 이러한 변환을 사용할 수 있다. 어쨌든 함수에 부동소수점을 사용할 때 코드를 작성하기가 훨씬 쉬워진다.

LT_I2C 라이브러리

LT_I2C 라이브러리는 LT_PM버스 라이브러리에 들어 있는 I2C 클래스와는 다르다. LT_PM버스에 들어 있는 것은 PM배시에 적합한 바이트 순서이며 대형 블록 연산을 지원한다.

또 LT_PMBus 라이브러리에 들어 있는 I2C 클래스는 와이어(Wire) 라이브러리를 기반으로 하며 다른 아두이노 보드로 이식하기가 좀 더 용이하다. 예를 들어서 아두이노 메가 2560으로 실행할 수 있다.

모든 비-PSM 스케치는 LT_I2C 라이브러리를 사용한다. PSM/PM버스 디바이스에는 LT_I2C 라이브러리를 사용하지 않는 것이 좋으며 그럴 필요도 없다.

◇ 간단한 스케치 작성하기

코드 작성을 배울 수 있는 가장 좋은 방법은 처음부터 새롭게 코드를 작성해 보는 것이다. 다음의 예는 바로 그렇게 하는 것을 설명하고 있다. 사용자가 한 단계씩 직접 해보면서 결과를 확인할 수 있다.

이 스케치 예제는 DC1962와 앞서 언급했던 여타 하드웨어들을 사용하고 있다. 이 예는 ▲프린트 볼티지(Print Voltages) ▲마진(Margin) ▲온·오프 ▲버스 프로브(Bus Probe) ▲리셋(Reset) 5가지 간단한 명령들을 사용하고 있다:

[그림14] 새로운 스케치 생성
[그림15] 공백 스케치
[그림16] Save As… 메뉴

Step 1: 빈 스케치 생성

[그림14]에서처럼 파일(File) | 뉴(New) 메뉴를 선택하면 새로운 스케치를 생성할 수 있다. 그러면 [그림15]에서와 같은 비어 있는 스케치가 열린다.

파일(File) | 세이브 에즈(Save As…) 메뉴를 사용해서 새로운 스케치에 지정할 경로를 선택한다. [그림16]에서 보듯이 폴더 명칭과 스케치 명칭이 일치하도록 해야 한다. 이 경로는 LT스케치북 아래에 있어야 한다. 파일(File) | 프리퍼런스(Preferences) 대화상자에 있는 것과 같은 경로여야 한다. 그래야 스케치북 메뉴에 표시가 된다.

Step 2: 인크루드 추가

스케치(Sketch) | 인크루드 라이브러리(Include Library) 메뉴를 사용해서 ▲유저인터페이스(UserInterface) ▲린두이노(Linduino) ▲LT_PMBUS 등 라이브러리들을 한 번에 하나씩 선택한다.

[그림17]에서는 LT_PMBUS 라이브러리를 선택하는 것을 보여준다. 인크루드 라이브러리 메뉴에 모든 라이브러리들이 표시된다. 이 파일의 맨 윗줄에 다음과 같은 인크루드 문을 추가한다:

#include <Arduino.h>

그런 다음에는 어드레스와 SM버스/PM버스 객체들에 관한 정적 변수들을 추가한다. 셋업 코드를 추가해서 변수들과 직렬 버스 객체를 초기화한다. 파일(File) | 세이브(Save) 메뉴를 사용해서 이 코드를 저장한다. 끝으로 툴바의 체크 버튼을 눌러서 코드를 컴파일한다.

그러면 이 코드는 [그림18]과 같을 것이다.

[그림 17] 인클루드
[그림18] 코드 초기화
[그림19] 프롬프트
[그림20] 사용자 입력


Step 3: 메뉴 셋업

메뉴는 선택 항목들을 프린트하고 사용자의 선택에 응답해야 한다.
프롬프트를 프린트할 print_prompt() 함수를 추가하고, 셋업 함수에서 이를 호출해서 스케치를 실행했을 때 메뉴 프롬프트를 표시하도록 한다. 이 코드는 [그림19]와 같을 것이다.

코드를 저장 및 컴파일하고 코드에 오류가 없는지 확인한다.

Step 4: 메뉴 응답 추가

콘솔로 메뉴 옵션을 입력하면 이를 읽고 응답해야 한다.
루프(loop) 함수를 사용해서 사용자 입력을 처리할 수 있다. 먼저 직렬 버스를 사용할 수 있는지 확인해야 한다. 그런 다음 정수로서 입력을 읽고 이것을 스위치 문으로 전달한다.

스위치 문 안에서는 어떤 함수를 수행하고 그런 다음 프롬프트(prompt) 함수를 호출해야 한다. 각 명령을 위한 코드는 스위치 문의 각 케이스 문을 써서 쓰여지고 그런 후에는 프롬프트를 호출한다. 이 코드 프레임워크는 [그림20]과 같을 것이다.

이 코드를 저장 및 컴파일하고 오류가 없는지 확인한다.

[그림21] 전압 읽기
[그림22] 마지닝 및 온·오프
[그림23] 오퍼레이션 명령
[그림24] 프로브 및 리셋

 Step 5: 전압 읽기

그러면 이번에는 무언가 실제적인 일을 하는 PM버스 코드를 작성해 보자.

[그림21]은 모든 전압을 읽는 코드를 보여준다. 이 코드는 <케이스1> 안에 들어 있다. 2개 변수를 사용해서 전압과 페이지를 저장한다. 전압을 저장하는 프로트(float)와 페이지를 저장하는 unit8_t이다(라인 57~58). 프린팅은 표준 Arduino Serial.print… 함수를 사용한다.

문자열을 감싸고 있는 F()는 이들 문자열을 플래시에 저장하도록 하므로 귀중한 RAM을 소모하지 않는다. 각 디바이스에 대해서 for loop가 pmbus->setPage(…)를 호출해서 페이지들을 인덱싱하고 이어서 pmbus->readVout(…)을 사용해서 전압을 읽는다. 그런 다음 이 코드는 DEC 타입을 사용해서 십진수로 전압을 프린트한다.

여기서 사용된 모든 API 함수 선언에 관해서는 LT_PM버스 라이브러리의 PM버스.h 파일이나 독시겐(Doxigen) 도큐멘테이션에서 볼 수 있다.

Step 6: 마지닝 및 온·오프

마지닝 코드는 동작이 전역적(global)이기 때문에 전압 코드보다 간단하다. 이것은 다시 말해서 하나의 명령에 모든 디바이스들이 응답할 수 있으며 페이지 레지스터가 필요하지 않다는 뜻이다. 또 아무 것도 프린트할 것이 없다.

[그림22]는 이 코드를 보여준다. <케이스 4>는 노 마진(No Margin) 메뉴 항목이다. 마지닝을 끝내기 위해서 sequenceOnGlobal()를 사용하는 것이 이상하게 생각될 것이다. 여기에 사용되는 PMBus 명령은 OPERATION(0x01) 명령이다.

[그림23]은 LTC3880 데이터 시트에서 가져온 것으로서, 마지닝을 정지하기 위한 명령이 없다는 것을 알 수 있다. 0x80 값을 사용하면 마지닝을 턴오프 시키는데 이것은 턴온을 의미한다. 바로 이 때문에 마지닝을 턴오프 하기 위해서 pmbus->sequenceOnGlobal()을 사용하는 것이다.

Step 7: 버스 프로브 및 리셋

버스를 프로브 하는 것은 SM버스 API에 속한다. 모든 디바이스가 PM버스인 것은 아니다. [그림24]에서는 프로브는 smbus->probe(0)을 호출하는 것이라는 것을 알 수 있다. 0은 프로브 하기 위해서 사용하는 명령이다. 이것은 PAGE (0x00) 명령이다. 프로브는 모든 유효한 어드레스를 테스트하고 식별된 장치 리스트를 반환한다. 읽기 명령 0x00에 ACK(응답확인)할 수 있는 모든 디바이스를 식별한다.

리셋 명령은 좀 모호한 점이 있다. LTC388X와 LTC297X 제품은 동일한 방식으로 리셋 하지 않는다. LTC388X 디바이스는 MFR_RESET (0xFD) 명령을 지원하는데 LTC297X 디바이스는 지원하지 않는다.

예를 들어서 LTC2977에서는 0xFD가 MFR_RESET이 아니라 MFR_TEMPERATURE_MIN이다. 매니저 디바이스를 리셋 하기 위한 적절한 방법은 NVM으로부터 RAM을 복구하는 것이다. 이 전송이 이뤄지면 디바이스가 리셋 되기 때문이다.

모든 디바이스를 동시에 리셋 하기 위해서는 그룹 커맨드 프로토콜(Group Command Protocol)을 사용할 수 있다. 이 명령을 사용하면 모든 동작을 하나의 트랜잭션으로 그룹화할 수 있다. 그러면 정지(STOP) 시에 PSM 디바이스들에 의해서 모든 명령들이 처리된다.

[그림24]에서 <케이스 8>은 그룹 프로토콜 트랜잭션을 어떻게 셋업 하는지 보여준다. 이 트랜잭션은 pmbus->startGroupprotocol()과 pmbus->executeGroupProtocol() 호출을 사용해서 경계를 짓는다.

Step 8: 테스트

그런 다음에는 애플리케이션을 컴파일 및 실행하고 모든 것이 잘 작동하는지 확인할 수 있다.
애플리케이션은 실행되는데 검출 데이터를 프린트하지 못한다면 무엇인가 실수를 한 것이다. 그러면 다음에서 설명하는 디버깅 기법들을 사용해서 문제를 디버깅할 수 있다. 그렇지 않고 마음이 급하다면 ▲어드레스 ▲페이지 ▲브레이크 문 등 항목들을 재확인해볼 수 있다.

◇ 디버깅

린두이노 PSM 애플리케이션이든 또는 여느 펌웨어 애플리케이션이든 ▲프린팅 ▲스파이 툴 ▲디버거 등의 방법들을 써서 디버깅을 할 수 있다.

이 글에서는 세 번째 방법에 대해서는 다루지 않도록 하겠다. 간단한 스케치에는 통상적으로 디버거가 필요하지 않기 때문이다. 디버거에 관해서 더 자세히 알고 싶으면 아두이노 웹사이트의 포럼으로 들어가서 다른 사람들은 어떤 툴들을 사용하는지 볼 수 있다.

프린팅을 사용하는 것에 관해서는 위의 예에서 보았다. 더 많은 프린트 문을 추가해서 디버깅을 할 수 있다. 그런데 반드시 문자열을 F() 매크로 안에 넣어서 RAM이 소모되지 않도록 해야 한다. 텍스트와 숫자를 프린팅 할 때는 2개의 호출로 분리시켜서 텍스트 부분은 플래시에 들어가도록 한다.

PSM 라이브러리는 이 기법을 사용하고 있다. NACK이나 PEC 에러와 같은 오류들이 명령 창에 프린트된다. 그러므로 디버그 프린팅을 추가하는 것은 통상적으로 애플리케이션 코드로 제한된다.

DEC를 사용한 프린팅은 위에서 이미 보았다. HEX와 여타 형식을 사용할 수도 있다. 형식화에 관한 추가적인 정보는 아두이노 도큐멘테이션에서 볼 수 있다.

PM버스에 사용할 수 있는 궁극적인 디버거는 스파이 툴이다. 스파이 툴이 좋은 점은 버스 상의 트래픽을 확인할 수 있기 때문이다. 또 지원이 필요한 경우에 LTC의 필드 애플리케이션 엔지니어에게 코드와 함께 트레이스를 전송할 수 있다.

이 글에서는 토털 페이즈(Total Phase)의 데이터 센터 애플리케이션이 토털 페이즈의 비글 보드와 통신하면서 생성된 데이터를 가지고 살펴보겠다. 이 데이터 센터 애플리케이션을 설치하는 것에 관해서는 토탈 페이즈 사이트에서 볼 수 있다.

출발점으로 삼을 수 있는 가장 간단한 방법은 자신이 작성한 스케치를 가지고 버스를 트레이스(trace)하는 것이다. 이를 위해서 메뉴 선택 항목 3번 리드 볼타지(read voltages)를 사용해 보자.

[그림25] 비글 트레이스
[그림26] 페이지 명령

[그림25]는 이 데이터를 보여준다. 그러면 인덱스를 사용해서 어디쯤에 있는지 확인해 가면서 이 트랜잭션이 어떤 의미인지 해독해 보자.

인덱스 #1(I1)과 인덱스 #6(I6)은 2개의 바이트 쓰기 트랜잭션이다. SM버스에서 이것은 라이트 바이트 프로토콜(Write Byte Protocol)이다. 어드레스는 0x30이다. 이것은 코드에서 볼 수 있듯이 LTC3880이다. 첫 번째 바이트는 명령으로서, 0x00이다. 이것은 페이지 명령이다.

LTC3880 데이터 시트의 [그림26]에서는 페이지 명령에 관해서 볼 수 있다. 이 표를 사용해서 비글 데이터를 빠르게 해독할 수 있다. 타입(Type) 칸을 보면 R/W 바이트라고 돼 있는 것을 볼 수 있다. 이것은 이 레지스터가 리드/라이트 바이트 프로토콜이라는 것을 의미한다. 그러므로 양방향이 지원된다.

I1과 I6으로 다시 돌아가서 보면 두 번째 바이트가 0x00 및 0x01이라는 것을 알 수 있다. 이 코드는 PAGE 레지스터를 0과 1로 설정한다. [그림21]에서 라인 63과 관련해서 보면 여기에서 바로 페이지가 설정되는 것이다. 그 다음에 오는 I2부터 I5까지는 다음과 같이 전압을 읽는다는 것을 알 수 있다.

[표1]

Write 0x8B Read 0x9A 0x0D
Write 0x20 Read 0x14  

0x8B는 READ_VOUT 명령이다. 데이터 시트의 [표1]에서 이것은 R 워드 프로토콜이고 L16 형식이라는 것을 알 수 있다. 0x20은 VOUT_MODE 명령이다. 데이터 시트의 [표1]에서 이것은 R 바이트(Byte) 명령이다.

이렇게 이뤄지도록 한 린두이노 호출은 [그림21]의 라인 64에서 볼 수 있다.

그렇다면 어떻게 단일한 함수 호출이 2개의 트랜잭션을 일으키는가? 왜 그런지 알아보기 위해서는 [그림27]에서 API 다음에 오는 코드를 살펴봐야 한다.

[그림27] 리드(Read) VOUT 코드


vout_L16 = smbus_.readWord(address, READ_VOUT);
exp = (int8_t)
(smbus_.readByte(address, VOUT_MODE) & 0x1F);
return math_.lin16_to_float(vout_L16, exp);

이 코드에서는 smbus_.readWord(address, READ_VOUT) 다음에 smbus_.readByte(address, VOUT_MODE)가 오고 모드로부터 5비트를 추출하고 이것을 exp 변수로 집어넣는다는 것을 알 수 있다. 그런 다음에 수학 변환이 지수 exp를 사용해서 L16에서 부동소수점으로 변환한다.

기본적으로 전압을 읽기 위한 코드는 제네릭(총칭) 코드로서, L16을 부동소수점으로 변환하기 위해서 사용된 지수를 읽는다. LTC388X와 LTC297X 디바이스는 서로 다른 지수를 사용한다. 그렇기 때문이 2개의 트랜잭션이 이루어지는 것이다.(※ 주의: 지수에 대한 사전 지식을 가지고서 코드를 작성할 수 있으며 좀더 빠르게 실행할 수 있다. 하지만 제네릭 코드는 버그가 더 적어 애플리케이션 작성자에게 좀더 쉽다.따라서 이러한 점들을 적절히 절충해서 자신의 코드를 작성할 수 있을 것이다)

끝으로 한 가지 흥미로운 트랜잭션을 살펴보자. 바로 리셋이다.

[그림28] 리셋 트레이스

[그림28]에서는 3개의 쓰기 트랜잭션이 이루어지고 있다는 것을 알 수 있다. S/P 칸에서는 2개의 S와 하나의 SP를 볼 수 있다. 이것은 I1은 스타트(Start)이고, I2는 리피티드 스타트(Repeated Start)이고 I3은 리피티드 스타트 다음에 스탑(Stop)이라는 의미다. 또 어드레스가 0x30, 0x32, 0x33으로 각기 다르다.

이것은 그룹 커맨드 프로토콜이다. I3가 끝났을 때, 다시 말해서 STOP일 때 모든 명령이 처리된다. 이것은 [그림24]의 라인 110~114에서 보는 코드와 상관관계다.

비글 트레이스를 직접 디코딩해보면 PSM 디바이스의 PM버스 명령에 대해서 좀더 상세히 이해할 수 있을 것이다. 그렇지 않고 코드가 제대로 작동하도록 하는 것이 목표라면 PSM 라이브러리를 사용함으로써 작업 부담을 덜 수 있을 것이다.

◇ LT파워플레이를 사용한 향상된 디버깅
머리말에서 언급했듯이 대부분의 시스템은 ‘셋 앤 포겟(set and forget)’ 모델을 따르나 일부 시스템은 BMC를 필요로 한다. 그런데 BMC를 사용하는 시스템은 실제로는 셋 앤 포겟과 펌웨어의 조합이다.

그렇다면 무엇 때문에 BMC로 하여금 전체적인 셋업 임무를 떠맡도록 할 것인가? PSM 디바이스로 베이스 셋업을 프로그램하고 BMC 펌웨어는 부가가치 기능들만 사용하는 것이 훨씬 수월하다. 이렇게 하면 또한 더욱 더 신뢰할 수 있는 시스템을 달성할 수 있다. 대부분의 펌웨어는 텔레메트리를 읽고, 마지닝을 하고 다소간의 전압 조절을 할 수 있기 때문에 시퀀싱이나 PWM 주파수 같은 주요 기능들을 제어하도록 할 필요가 없다.

LT파워플레이는 PSM 시스템을 설계하고 디버깅하고 브링업하기 위한 범용적인 툴이므로 디버깅 펌웨어가 물리 클록과 데이터 라인 상의 다른 PM버스 마스터와 충돌이 일어날 수 있다.
2개의 마스터일 때 실제적으로 어떻게 되는지 살펴보기 앞서 먼저 PM버스에서 2개의 마스터일 때 어떻게 되는지 살펴보자. PM버스는 SM버스를 기반으로 하며, SM버스는 멀티 마스터링 기능을 포함한다.

클록과 데이터 라인은 개방 드레인이다. 이것은 다시 말해서 마스터가 되었든 슬레이브가 됐든 어떤 장치가 라인을 풀다운은 할 수 있는데 풀업은 할 수 없다는 뜻이다. 어떤 마스터가 데이터 라인을 풀다운 하지 않았는데 이 데이터 라인이 로우(low)인 것을 검출했을 때는 다른 마스터가 이 데이터 라인을 로우로 풀링 한 것으로 간주하고 자신의 트랜잭션을 중지하는 것이 원칙이다. 그럼으로써 다른 마스터가 자신의 트랜잭션을 계속할 수 있게 한다.

이 기법을 비트 우위 중재(bit dominance arbitration)라고 한다. 이것은 다시 말해서 데이터 라인으로 제로를 선언하는 마스터가 항상 이긴다는 뜻이다.

린두이노와 LT파워플레이DC1613) 멀티 마스터를 사용하면 모든 것이 편하다는 것을 알 수 있다. 하지만 한 가지 중요한 고려사항이 있다.

PM버스는 PAGE 명령(0x00)을 정의하고 있는데, 이것은 데이터 라인으로의 어드레스와 같은 것이다. 페이지는 채널과 같은 것이다. 예를 들어서 LTC2977은 8개 전원을 관리할 수 있다. 다시 말해서 8개 채널을 사용하며 이들 각각을 페이지 레지스터/명령을 사용해서 어드레스를 지정할 수 있다.

실제적으로 이것은 전압 같은 어떤 값을 읽는 것을 의미한다. 그러기 위해서는 2개의 트랜잭션을 필요로 한다. 하나는 페이지고 다른 하나는 READ_VOUT다. 그런데 2개의 마스터가 동시에 동일한 슬레이브로부터 텔레메트리를 읽으려고 시도하고 한 마스터가 다른 마스터의 페이지 명령과 텔레메트리 명령 사이에 페이지 명령을 삽입하게 되면 이 마스터는 잘못된 페이지를 읽게 된다.

LT파워플레이를 실행할 때 가장 중요한 할 일이 텔레메트리를 읽는 것이다. 이렇게 해서 상태 디스플레이를 계속해서 현재적으로 유지함으로써 출력 플롯, 결함, 그 밖의 중요한 정보들을 확인할 수 있다. 펌웨어가 통상적으로 하는 일이 무엇인가? 바로 텔레메트리를 읽는 것이다.

게다가 부트 시에 펌웨어가 VID(Voltage Identification) 기능을 수행했다고 하자. 그런데 LT파워플레이가 페이지 레지스터를 변경함으로써 펌웨어가 잘못된 페이지로 전압 값을 썼다고 하면 어떻게 될 것인가? 그러면 시스템이 결함을 일으키거나, 좀더 심각한 경우에는 무엇인가를 손상시킬 수도 있다.(다만 다행히도 통상적으로 VOUT_MAX 레지스터를 사용해서 시스템 손상을 방지할 수 있다.)

이러한 PAGE 명령의 근본적인 문제는 PM버스 표준 자체에서 발생한다. LTC의 PSM 디바이스를 사용할 때만 발생되는 고유한 것이 아니다. 그러므로 사용자들이 이 문제를 해결해야 한다.
LT파워플레이와 펌웨어가 양립할 수 있게 하고 페이지 문제를 해결할 수 있는 방법은 기본적으로 두 가지가 있다. 첫 번째 방법은 단순하게 두 마스터가 동시에 통신하지 않도록 하는 것이다. 두 번째 방법은 이쪽 마스터나 저쪽 마스터로 페이지 플러스 프로토콜이나 여타의 수법들을 사용하는 것이다.

이 글에서는 페이지 플러스를 사용하는 방법은 배제하도록 하겠다. 이 방법은 그렇게 흔히 사용되지 않기 때문이다. 페이지 플러스는 하나의 트랜잭션으로 페이지와 코맨드를 포함하는 자동 트랜잭션을 가능하게 한다. 페이지 플러스는 모든 디바이스들이 지원하지는 않으며 통상적으로 특수한 경우에만 사용된다.

그러므로 이 글에서는 페이지 플러스나 여타의 난해한 수법을 사용하는 것에 관해서는 제외하도록 하겠다. 이 문제를 해결하기 위해서 다른 방법이 없는 경우라면, LTC PSM 데이터 시트에서 이에 관한 정보를 볼 수 있을 것이다. 또 아니면 현지의 LTC 필드 애플리케이션 엔지니어에게 도움을 요청할 수 있을 것이다.

좀 더 일반적인 방법은 LT파워플레이와 펌웨어가 슬레이브로 동시에 통신하지 않도록 하는 것이다. LT파워플레이는 아주 간단하게 동작을 제어할 수 있다. [그림29]에서는 텔레메트리 플롯을 보여준다. 이 화면의 툴바에서는 빨간색 정사각형 버튼을 볼 수 있다.

[그림29] LTpowerPlay 시작·정지
[그림30] LT파워플레이 정지

 이 버튼을 누르면 버스 상의 모든 텔레메트리와 모든 LT파워플레이 동작을 정지시킬 수 있다. 그러면 [그림30]에서 보는 것과 같이 녹색 화살표로 바뀐다.

하지만 펌웨어는 모든 경우에 버스를 정지시킬 메커니즘을 갖추고 있는 것은 아니다. 그러면 이러한 메커니즘을 갖춘 새로운 펌웨어를 작성하거나 또는 하드웨어 버스 스위치/MUX나 점퍼를 갖출 것을 권장한다.

LT파워플레이이든 펌웨어이든 어느 쪽의 버스 마스터이든 중지할 수 있는 수단을 갖췄으면 디버깅은 간단히 필요에 따라서 툴들 사이를 전환하기만 하면 된다.

요약하자면 ▲한 번에 한 마스터만 버스로 통신할 수 있게 한다 ▲ 페이지 플러스나 여타의 향상 기법들을 사용하려면 이에 관한 좀 더 상세한 이해를 필요로 하며 LTC 필드 애플리케이션 엔지니어에게 도움을 요청할 수 있다 등 2가지 방법을 쓸 수 있다:

새로운 디자인을 작성할 때는 첫 번째 방법을 사용하는 것이 좋다.

◇ 맺음말
린두이노 PSM 스케치북과 린두이노보드와 선택적인 DC2294 쉴드 보드를 사용함으로써 PSM 디바이스 용의 코드를 쉽게 작성할 수 있다. 이 라이브러리는 SM버스 및 PM버스 용의 단순한 API를 제공한다. LT파워플레이 디버깅에도 사용할 수 있으며 토털 페이즈의 비글 보드나 여타의 스파이 툴을 추가함으로써 버스 상의 트래픽을 살펴볼 수 있다.

이식할 코드를 작성하는 경우나 단지 PM버스가 어떻게 작동하는지 학습하려고 하는 경우나 린두이노에서부터 시작하는 것이 좋은 방법이다. 빠르게 학습 곡선을 거치고 PSM 프로그래밍의 기초적인 것들을 이해하게 됐으면 자신 있게 추가적인 툴들을 사용하면서 자신만의 코드를 작성할 수 있을 것이다.

이렇게 해서 이 글의 과정을 마치게 되었다. 원하면 LT스케이트북으로 제공되는 다른 스케치들도 시험해 볼 수 있을 것이다. 폴트 로그 디코딩(Fault Log Decoding)이나 인 시스템(In System)/플라이트 업데이트(Flight Update) 같은 좀 더 고급 스케치들을 시험해 볼 수 있을 것이다.

글 : 마이클 존스(Michael Jones) 리니어 애플리케이션 엔지니어링 총괄
자료제공 : 리니어테크놀로지(www.linear.com)

회원가입 후 이용바랍니다.
개의 댓글
0 / 400
댓글 정렬
BEST댓글
BEST 댓글 답글과 추천수를 합산하여 자동으로 노출됩니다.
댓글삭제
삭제한 댓글은 다시 복구할 수 없습니다.
그래도 삭제하시겠습니까?
댓글수정
댓글 수정은 작성 후 1분내에만 가능합니다.
/ 400
내 댓글 모음
저작권자 © 테크월드뉴스 무단전재 및 재배포 금지