개요: 이 애플리케이션 노트는 Maxim API를 사용하여 DS1WM 1-Wire 버스 마스터를 제어하는 C 코드 예제를 제공한다. 이 글은 DS1WM이 FPGA 또는 ASIC으로 설계되었으며 호스트 CPU가 API 호출을 통해 DS1WM을 제어한다고 가정한다. DS1WM은 API를 구성하는 2개의 파일(DS1WM.c 및 DS1WM.h)을 통해 통신한다. 이 글의 주제에는 초기화, 1-Wire 리셋 및 ROM 검색 알고리즘에 대한 예제가 포함된다. 예제는 일반적인 1-Wire 기능을 사용하는 방법을 보여준다. 이 글을 읽는 독자는 1-Wire 소자, DS1WM 1-Wire 마스터 및 1-Wire 프로토콜에 대해 어느 정도 잘 알고 있다고 가정한다.
머리말
DS1WM 1-Wire 버스 마스터는 내부적으로 1-Wire 타이밍과 제어 신호를 발생시키므로 CPU 비트 뱅잉(bit-banging)이 필요 없다. 이 제어 함수는 제공되는 API 함수를 시스템 프로그래머가 사용하여 프로그램 개발에만 집중할 수 있게 해준다. DS1WM API는 ANSI C로 작성되므로 ANSI C를 지원하는 많은 마이크로프로세서 플랫폼에 이식할 수 있다. 다음 예제는 네트워크상에서 1-Wire 슬레이브 소자를 식별, 선택 및 통신하는 방법을 보여준다.
그림 1. 1-Wire 네트워크 버스의 예제 회로
그림 1의 회로 구성은 다음의 모든 예제에 사용된다. 호스트 CPU는 DS1WM을 사용하여 체인 모드 및 GPIO와 DS2431 1-Wire 1Kb EEPROM을 갖는 DS28EA00 1-Wire 디지털 온도 센서와 통신한다. 예제는 슬레이브 소자의 기능이 아닌 API를 보여준다. 16MHz 시스템 클록은 CLK 핀을 통해 1-Wire 마스터의 타이밍을 제어한다. 1-Wire 마스터의 포트 핀은 적용 가능한 마이크로프로세서 핀에 매핑할 필요가 있다. 핀 매핑은 API 파일 DS1WM.h에 들어 있다. API 헤더 파일에 있는 MaxNumberDevices 매크로는 찾을 수 있는 소자의 최대 숫자로 변경할 필요가 있다. DS1WM.c API 파일에 있는 ReadByteFromRegister 및 WriteByte2Register 함수도 마이크로프로세서 포트 핀을 적절히 토글할 수 있도록 수정할 필요가 있다. VPUP 전압은 보통 5.0V에 있으며 RPUP는 2.2kΩ보다 높지 않다.
개요
DS1WM 및 API는 Maxim 지원을 통해 요청한 경우 무료로 제공된다. 초기화 및 DS1WM 코드의 1-Wire 리셋 제어는 아래에 설명된다. 예제는 DS1WM의 ROM 검색 가속기를 사용하여 각 소자에 대한 고유의 등록 번호(ROM ID)를 검색하는 방법을 보여준다. 각 1-Wire 슬레이브 소자는 저장된 등록 번호를 이용해 제품군 코드별로 식별한 다음 Match ROM 함수를 사용하여 액세스할 수 있다. 제품군 코드 테이블은 애플리케이션 노트 155, "1-Wire® 소프트웨어 리소스 가이드 소자 설명"에서 확인할 수 있다. DS28EA00 예제는 온도 변환 수행 방법을 보여준다. 두 번째 예제는 오버드라이브 속도에서 DS2431의 스크래치패드 메모리를 쓰고 읽는 두 가지 방법을 보여준다.
기본 버스 마스터 동작
마이크로프로세서는 리셋 핀을 토글하여 DS1WM을 초기화한다. API 인터페이스는 모든 1-Wire 통신을 수행한다. 예제 동작은 DS1WM API의 함수를 호출하면서 설명한다. 인터럽트를 구현하는 마이크로프로세서 코드의 차이로 인해 이후의 예제는 인터럽트에 따른 통신 대신 폴링을 사용한다.
표 1의 1-Wire 동작은 다음의 코드 예제에 사용된다.
표 1. 1-Wire 동작
동작*
설명
OWReset
1-Wire 리셋 자극을 전송하고 버스에 존재하는 1-Wire 슬레이브 소자의 펄스를 검사한다.
DS1WM의 1-Wire 통신 속도를 오버드라이브로 설정한다. 이 함수는 DS1WM의 통신 속도만 변경하므로 정상 속도에서 오버드라이브 속도로 전환할 경우 1-Wire 슬레이브 소자에게 스위칭을 명령해야 한다. 1-Wire 슬레이브는 표준 속도 1-Wire 리셋을 만나면 언제나 표준 속도로 되돌아간다.
OverdriveDisable
DS1WM의 1-Wire 통신 속도를 표준으로 설정한다. 이 함수는 DS1WM의 통신 속도만 변경하므로 슬레이브 소자가 오버드라이브를 종료하려면 표준 속도 1-Wire 리셋이 필요하다.
MatchROM
Match ROM 명령과 함께 선택된 64비트 ROM ID를 발생시켜 소자를 선택한다.
SetClockFrequency
DS1WM의 클록 주파수를 설정한다.
InterruptEnableRegisterWrite
단일 바이트 데이터를 DS1WM 인터럽트 인에이블 레지스터에 쓴다.
InterruptRegisterRead
DS1WM 인터럽트 레지스터로부터 단일 바이트 데이터를 읽는다.
ReceiveBufferRead
DS1WM 수신 버퍼 레지스터로부터 단일 바이트 데이터를 읽는다.
*이 표는 예제에 사용되는 루틴을 포함하고 있다. 모든 설명을 보려면 DS1WM.c 파일을 참조한다.
초기화
호스트는 적절한 1-Wire 버스 타이밍에 DS1WM을 초기화하는 것으로 시작한다. 호스트가 값 16(주파수를 나타냄)을 SetClockFrequency 루틴에 전달하면, 이 루틴은 Clock Divisor 레지스터에 0x90h를 쓴다(DS1WM 데이터 시트참조). Interrupt Enable 레지스터는 0x00h로 설정되어 INTR 핀에 인터럽트가 발생되는 것을 방지한다. 파워 업 시 수신 버퍼는 무효 값을 가질 수 있는데, 이는 임의 1-Wire 명령을 전송하기 전에 수신 버퍼를 비울 수 있게 도와준다. 인터럽트 레지스터 및 수신 버퍼는 임의 비트를 삭제할 수 있도록 시동 시 한 번 읽혀진다.
//----------------------------------------------------------------------------------------------------
//Start of initialization example
SetClockFrequency(16); //Set clock frequency to 16MHz (power-on default)
InterruptEnableRegisterWrite(0x00); //Clear interrupts
//Flush receive buffer
InterruptRegisterData = InterruptRegisterRead();
ReceiveBufferRead();
//End of initialization example
//----------------------------------------------------------------------------------------------------
1-Wire 리셋 (OWReset API 함수)
초기화 후 호스트는 1-Wire 버스상에 소자가 존재하는지 여부를 결정해야 한다. 이를 수행하기 위해 호스트는 OWReset 함수를 호출한다. 이 함수는 존재 검출 펄스가 감지되면 1을 리턴하고, 소자가 검출되지 않거나 오류가 발생될 경우 0을 리턴한다. 0이 리턴되면 ErrorStatus 변수를 오류 조건에 대해 검사해 보아야 한다. 1-Wire 리셋은 자체 리셋을 포함하고 있는 OWSearch 함수를 호출한 경우를 제외하면 모든 1-Wire 명령 (Match ROM, Skip ROM, Read ROM 등) 전에 발생해야 한다. 소프트웨어 설계자는 오류 조건에 의해 트리거될 수 있는 적절한 오류 처리 코드를 추가해야 한다. ErrorStatus 값은 다음 오류 - 존재 검출 발생하지 않음, 부품 발견되지 않음, 1-Wire 단락 존재, 1-Wire가 로우 상태에 빠짐 - 중 하나가 발생했다는 것을 의미할 수 있다.
Result = OWReset();
if(!Result){
switch(ErrorStatus){
case -1: //DS1WM did not recognize 1-Wire reset (PD=0)
//To do: add your error code here
break;
case -2: //No device found (PDR=1)
//To do: add your error code here
break;
case -7: //1-Wire IO is shorted (OW_SHORT=1)
//To do: add your error code here
break;
case -8: //1-Wire IO is shorted (OW_LOW=1)
//To do: add your error code here
break;
}
}
ROM 검색 가속기를 사용하여 ROM ID 찾기
버스상의 각 1-Wire 소자는 식별되어야 한다. 모든 1-Wire 소자에 저장된 고유의 64비트 ROM ID가 개별 소자를 선택하는 데 사용된다. 이 ID는 제품 코드를 기준으로 소자 유형을 식별한다. 예제 코드의 복잡성을 줄이기 위해 8비트 제품군 코드가 DS28EA00과 DS2431을 구분하는 데 사용된다.
참고:1-Wire 라인에 1개 이상의 소자 유형(동일한 제품 코드를 갖는)이 연결되어 있는 경우 다음의 방법으로는 한 소자와 다른 소자를 구별할 수 없다. 버스에 존재하는 여러 개의 1-Wire 소자를 구별하는 방법이 없을 때 특정 1-Wire 소자에 함수 명령을 전달할 수 있는 방법은 없다. 2개 이상 유사한 소자가 사용될 경우 의도된 소자에 적절히 액세스하기 위해서는 룩 업 테이블을 구현해야 한다.
OWSearch 함수는 호출될 경우 버스상의 모든 1-Wire 소자를 식별한다. 이 함수는 통과된 어레이에 8바이트 ROM ID를 놓는다. OWReset 함수는 이미 OWSearch 함수의 일부이므로 OWReset 함수를 호출할 필요는 없다. OWSearch 함수는 검색 알고리즘의 반복 과정으로 인해 이러한 예외를 갖는다. 특별히 OWSearch 함수는 발견된 1-Wire 소자의 번호를 리턴하고 각각의 64비트 ROM ID를 ROMCodes라고 하는 2차원 어레이에 놓는다.
아래의 예제는 1회 호출되는 OWSearch만을 보여주며, 이후에 1-Wire 버스에 추가되는 다음의 모든 소자는 이 코드에 의해 식별되지 않는다. 성공적일 경우 OWSearch는 발견되는 소자의 번호를 리턴한다. 검색이 성공적이지 않을 경우에는 ErrorStatus 변수가 OWReset에 대한 오류 조건이 포함된 오류 값을 리턴한다. 성공적인 검색 후 ROMCodes 어레이는 통과되고 각 소자에 대한 어레이 인덱스가 저장된다. 이 소자 인덱싱은 발견되는 각 소자에 대한 제품 코드를 비교하여 수행된다. 이후에 이 어레이 인덱스는 발견된 특정 1-Wire 소자와 통신하기 위해 호출할 수 있다. 기본적으로 이것은 간단한 링크된 리스트를 생성한다(참고: 이는 포인터를 사용하여 구현할 수 있었다.)
//----------------------------------------------------------------------------------------------------
//Start of DS1WM search ROM accelerator example
//Devices on the 1-Wire IO are:
//DS28EA00 Family Code = 42h (6900000004E8C842)
//DS2431 Famliy Code = 2Dh (5A0000000FDE052D)
//Find all devices on 1-Wire line and populate ROMCodes array
Result = OWSearch(ROMCodes); //Returns number of devices found if successful
//Set number of 1-Wire devices found
if(Result)
NumberOfDevices = Result;
if(!Result){
switch(ErrorStatus){
case -1: //DS1WM did not recognize 1-Wire Reset (PD=0)
//To do: add your error code here
break;
case -2: //No device found (PDR=1)
//To do: add your error code here
break;
case -7: //1-Wire IO is shorted (OW_SHORT=1)
//To do: add your error code here
break;
case -8: //1-Wire IO is shorted (OW_LOW=1)
//To do: add your error code here
break;
case -9: //Invalid CRC for device
//To do: add your error code here
break;
case -10: //ROMCodes array too small (Edit MaxNumberDevices in DS1WM.h)
//To do: add your error code here
break;
}
}
//Note: This function is intended to be used when there is only one device with the same
//Family Code present on the line
for(i=0;i<NumberOfDevices;i++){
if(ROMCodes[i][0] == 0x42){
DS28EA00 = i; //Save off array index for DS28EA00
continue;
}
if(ROMCodes[i][0] == 0x2D){
DS2431 = i; //Save off array index for DS2431
continue;
}
}
DS1WM API 함수를 사용하여 DS28EA00 제어하기
이 예제는 앞서 발견된 ROM ID를 사용하여 DS28EA00과 통신한다. OWReset에 이어 Match ROM 명령이 발생된다. ROM 코드 어레이는 액세스할 소자의 인덱스와 함께 Match ROM 함수에 전달된다. 1-Wire 버스상의 소자는 Match ROM 명령 0x55h 다음에 64비트 ROM 시퀀스가 이어지기 때문에 버스 마스터는 멀티드롭 버스상에 존재하는 특정 DS28EA00을 어드레스싱할 수 있다. 64비트 ROM 시퀀스에 정확히 일치하는 DS28EA00만 다음 세트의 명령에 응답하며 나머지 모든 슬레이브 소자는 리셋 펄스를 기다린다.
OWWriteByte 및 OWReadByte API 함수는 메모리 명령(Write/Copy/Read Scratchpad)을 발생시키는 데 사용된다. DS1WM은 먼저 Write Scratchpad 명령(0x4Eh)을 전송하고 이어 온도 하이, 온도 로우 및 구성 레지스터를 프로그래밍하는 값을 전송함으로써 온도 알람과 분해능을 구성한다. 완료되면 다른 OWReset이 Match ROM 명령, ROM ID 및 스크래치패드 컨텐츠를 레지스터 메모리에 복사하는 Copy Scratchpad 명령(0x48h)과 함께 발생되어 온도 분해능 구성을 완료한다. CPU 호스트가 복사 시간을 허용할 수 있도록 10ms의 적절한 지연을 추가해야 한다. 마이크로프로세서 지연 루틴의 차이로 인해 API에는 주석이 달린 수도 코드만 포함된다.
복사 이후에 다시 한 번 OWReset이 Match ROM, ROM ID, 온도 변환 명령(0x44h)과 함께 발생된다. 온도 변환이 발생할 시간을 주기 위해 100ms의 지연 시간이 필요하다. 마지막으로 OWReset이 Match ROM, ROM ID 및 온도 데이터를 포함하는 2바이트를 읽는 Read Scratchpad 명령(0xBEh)과 함께 발생된다. 항상 소자를 선택할 필요가 있을 때마다 OWReset과 함께 Match ROM 명령 및 ROM ID로 DS28EA00을 선택하는 패턴이 사용된다는 점에 주의한다. Skip ROM 명령은 라인에 단일 소자가 있을 때(ROM 검색 불필요)만 사용해야 한다.
//----------------------------------------------------------------------------------------------------
//Start of DS28EA00 example
Result = OWReset();
if(!Result){
switch(ErrorStatus){
case -1: //DS1WM did not recognize 1-Wire reset(PD=0)
//To do: add your error code here
break;
case -2: //No device found(PDR=1)
//To do: add your error code here
break;
case -7: //1-Wire IO is shorted(OW_SHORT=1)
//To do: add your error code here
break;
case -8: //1-Wire IO is shorted(OW_LOW=1)
//To do: add your error code here
break;
}
}
//Set temperature resolution
Result = MatchROM(ROMCodes,DS28EA00); //Select device
Result = OWWriteByte(0x4E); //Issue Write Scratchpad command
Result = OWWriteByte(0x00); //TH register data
Result = OWWriteByte(0x00); //TL degister data
Result = OWWriteByte(0x1F); //Config. reg. data (set 9-bit temp. resolution)
OWReset(); //Error code removed for conciseness
MatchROM(ROMCodes,DS28EA00); //Select device
OWWriteByte(0x48); //Issue Copy Scratchpad command
//To do: add microprocessor-specific code delay to allow copy to complete
//Delay(10MS);
//Psuedo code
OWReset(); //1-Wire reset
MatchROM(ROMCodes,DS28EA00); //Select device
OWWriteByte(0x44); //Issue Convert Temperature command
//To do: add microprocessor-specific code delay to allow temperature conversion to complete
//Delay(100MS);
//Psuedo code
//Read temperature results from scratchpad
OWReset(); //1-Wire reset
MatchROM(ROMCodes,DS28EA00); //Select device
OWWriteByte(0xBE); //Issue Read Scratchpad command
TempLSB = OWReadByte(); //Read byte
TempMSB = OWReadByte(); //Read byte
//End of DS28EA00 example
//----------------------------------------------------------------------------------------------------
DS1WM API 함수를 사용하여 오버드라이브에서 DS2431 제어하기
이 예제는 앞서 발견된 ROM ID를 사용하여 DS2431과 통신한다. OWReset이 Overdrive Skip ROM 명령(0x3Ch)과 함께 발생되면 모든 오버드라이브 지원 1-Wire 소자는 오버드라이브 모드에 놓인다. DS1WM 오버드라이브 타이밍을 활성화하기 위해 OverdriveEnable 함수가 호출된다. 이제 1-Wire 함수는 오버드라이브 속도에서 동작한다. 애플리케이션 노트 126, "소프트웨어를 통한 1-Wire® 통신"에서는 표준 및 오버드라이브 모드에서의 1-Wire 타이밍에 대해 자세히 설명하고 있다.
타깃 어드레스 TA1 및 TA2 변수 사용하기
첫 번째 예제 방법에서 사용자 변수 TA1 및 TA2는 DS2431의 원하는 메모리 어드레스로 설정된다. OWReset이 Match ROM, DS2431 ROM ID, Write Scratchpad 명령(0x0Fh), 타깃 어드레스 1 & 2 및 64비트 DS2431 스크래치패드에 쓰여지는 8바이트 데이터와 함께 발생된다. CRC16을 다시 읽고 검사할 것을 권장한다. 애플리케이션 노트 27, "Maxim iButton® 제품에서 CRC의 이해와 사용"에는 CRC16이 자세히 설명되어 있다.
OWWriteBytes 및 OWReadBytes
두 번째 예제 방법에서는 두 개의 새로운 API 함수인 OWWriteBytes 및 OWReadBytes가 사용된다. 이들 두 API 함수는 스크래치패드에 많은 데이터 양을 쓰고 읽는 것을 간소화한다.
스크래치패드 쓰기 (write scratchpad) 방법은 다음과 같다. 타깃 어드레스 1 & 2를 설정한다. WriteBytes에 데이터를 쓴다. OWReset를 발생시킨다. Match ROM, DS2431 ROM ID, Write Scratchpad 명령(0x0Fh)을 전송한다. 타깃 어드레스 1 & 2를 전송한다. OWWriteBytes 함수를 사용하여 WriteBytes에 저장된 모든 10바이트를 쓴다. 원할 경우 CRC16을 다시 읽어 CRC16을 검사한다.
스크래치패드 읽기 (read scratchpad) 방법은 다음과 같다. OWReset을 발생시킨다. Match ROM, DS2431 ROM ID를 전송한다. Read Scratchpad 명령(0xAAh)을 발생시킨다. OWReadBytes 함수를 사용하여 모든 13바이트(TA1, TA2, ES, CRC16 및 8바이트 데이터)를 읽고 ReadBytes에 저장한다.
오버드라이브 모드를 종료하려면 API 함수 OverdriveDisable과 함께 표준 OWReset을 호출한다. 이렇게 하면 모든 소자가 표준 속도로 되돌아간다.
//----------------------------------------------------------------------------------------------------
//Start of DS2431 example
Result = OWReset(); //Error code removed for conciseness
Result = OWWriteByte(0x3C); //Overdrive Skip ROM (all devices are now in overdrive)
OverdriveEnable(); //Enable Overdrive Mode
//Write scratchpad with data
//First method
TA1 = 0x00;
TA2 = 0x00;
Result = OWReset(); //1-Wire reset
Result = MatchROM(ROMCodes,DS2431); //Select device
Result = OWWriteByte(0x0F); //Issue Write Scratchpad command
Result = OWWriteByte(TA1); //Send target address 1 (TA1)
Result = OWWriteByte(TA2); //Send target address 2 (TA2)
//Write 8 Bytes of Data
Result = OWWriteByte(0x11); //Send Data Byte for all
Result = OWWriteByte(0x22);
Result = OWWriteByte(0x33);
Result = OWWriteByte(0x44);
Result = OWWriteByte(0x55);
Result = OWWriteByte(0x66);
Result = OWWriteByte(0x77);
Result = OWWriteByte(0x88);
//It is recommended that the CRC16 be read back and verified
//CRC16 code was left out for conciseness
Result = OWReset(); //1-Wire Reset
Result = MatchROM(ROMCodes,DS2431); //Select device
Result = OWWriteByte(0xAA); //Issue Read Scratchpad command
Result = OWReadByte(); //Read TA1
if(Result != TA1){
//To do: Add your error code here
}
Result = OWReadByte(); //Read TA2
if(Result != TA2){
//To do: Add your error code here
}
ES = OWReadByte(); //Read ES
//To do: add your error code after reads
Result = OWReadByte(); //Read Data Byte (0x11)
Result = OWReadByte(); //Read Data Byte (0x22)
Result = OWReadByte(); //Read Data Byte (0x33)
Result = OWReadByte(); //Read Data Byte (0x44)
Result = OWReadByte(); //Read Data Byte (0x55)
Result = OWReadByte(); //Read Data Byte (0x66)
Result = OWReadByte(); //Read Data Byte (0x77)
Result = OWReadByte(); //Read Data Byte (0x88)
//It is recommended that the CRC16 be read back and verified
//CRC16 code was left out for conciseness
//Second method
TA1 = 0x00;
TA2 = 0x00;
WriteBytes[0] = TA1;
WriteBytes[1] = TA2;
for(i=2;i<10;i++){
WriteBytes[i] = i;
}
Result = OWReset(); //1-Wire reset
Result = MatchROM(ROMCodes,DS2431); //Select device
Result = OWWriteByte(0x0F); //Issue Write Scratchpad command
//Write 10 bytes of data (TA1, TA2 & 8 bytes of data)
OWWriteBytes(WriteBytes,10); //Write data bytes
//It is recommended that the CRC16 be read back and verified
//CRC16 code was left out for conciseness
Result = OWReset(); //1-Wire reset
Result = MatchROM(ROMCodes,DS2431); //Select device
Result = OWWriteByte(0xAA); //Issue Read Scratchpad command
//Read 13 bytes of data (TA1, TA2, ES, CRC16 & 8 bytes of data)
OWReadBytes(ReadBytes,13); //Read data bytes
//It is recommended that the CRC16 be read back and verified
//CRC16 code was left out for conciseness
//Exit overdrive
OverdriveDisable();
Result = OWReset(); //Std. reset issued (all devices are now in standard speed)
//End of DS2431 example
//----------------------------------------------------------------------------------------------------
결론
이 애플리케이션 노트에서는 호스트 CPU에서 1-Wire 타이밍을 발생시키는 오버헤드 없이 API 함수를 사용하여 DS1WM을 제어하는 예제를 제공하였다. 이제 사용자는 버스에 존재하는 다중 1-Wire 소자를 선택하고 액세스하는 일반 API 함수에 익숙해졌을 것이다. DS28EA00 및 DS2431의 제어 및 액세스는 버스상의 예제 소자로 사용되었으며, 오버드라이브 및 단일/다중바이트 읽기 및 쓰기 예도 제시되었다.