PIC 마이크로컨트롤러에 USB 플래시드라이버인터페이싱하기 최근저비용플래시메모리드라이브와각종 USB 주변기기가출시됨에따라 USB 인터페이스는어디에서든찾아볼수있다. 그러나이들주변기기를 8비트또는 16 비트임베디드분야에사용하려고할때에는구현, 비용및전력소모가중요한문제가된다. 이글에서는최고속도의 USB 2.0 인터페이스를통해저비용 PIC 마이크로컨트롤러를플래시드라이브로연결하는방법과관련프로그래밍에대해설명하고자한다. 글 : 프레드 (Fred Dart), 매니징디렉터 / Future Technology Devices International (FTDI) www.ftdichip.com 본고에서는최고속도의 USB 2.0 인터페이스를통해저비용 PIC 마이크로컨트롤러를플래시드라이브로연결하는방법과관련프로그래밍에대해자세히설명하고자한다. PIC 마이크로컨트롤러및 Vinculum USB 인터페이스칩주변에위치한임베디드인터페이스의하드웨어설계와더불어다양한임베디드애플리케이션에서유비쿼터스 USB 플래시드라이브가착탈식스토리지로사용될수있도록하는일반적인프로그래밍에대해살펴볼예정이다. 이애플리케이션예에서 VNC1L Vinculum 컨트롤러 IC는시스템컨트롤러로써의 PIC와 USB 2.0 최고속도포트사이에인터페이스를제공한다. 이로써, 예를들어, USB 플래시메모리드라이브연결시구현시간과오버헤드를최소화할수있다. 서론 Vinculum 저비용플래시메모리드라이브와각종 USB 주변기기가출시됨에따라 USB 인터페이스는오늘날어디에서든찾아볼수있다. 그러나이들대부분은 PC 업계에집중되어있다. 또한이들주변기기를 8비트또는 16비트임베디드분야에사용하려고할때에는구현, 비용및전력소모가중요한문제가된다. 이러한문제는그러한시스템에사용되는임베디드컨트롤러도마찬가지이다. 마이크로칩의 PIC 컨트롤러제품군과같은디바이스들은다양한메모리집적도및주변기기와함께사용되지만, USB 호스트컨트롤러를포함시키기위한인터페이스, 리소스및성능이부족하다. 이컨트롤러는데이터전송을가속화하기위한쌍둥이 DMA(direct memory access) 엔진과파일시스템을위한계산을최적화하기위한 32비트수치코프로세서 (numeric co?processor) 와함께맞춤형프로세서주변에위치해있다. 이모든것은 64Kbyte의임베디드플래시프로그램메모리와 086
_ PIC 마이크로컨트롤러에 USB 플래시드라이버인터페이싱하기 그림 1. Interfacing a USB Flash Drive to a PIC Microcontroller 4Kbyte의내부데이터 SRAM을탑재한싱글칩에결합되어있다. Vinculum은특별히임베디드 USB 컨트롤러시장을겨냥해고안되었으며, 최소한의외부부품만있으면된다. Vinculum 코어의한가지핵심특징은일반 MCU 코어와비교해코드길이가매우짧아졌다는것이다. 코어의코드오버헤드를줄임으로써온칩 e- Flash 메모리에더많은기능을포함시킬수있다. 이와같은특징들은 PIC 기반의임베디드시스템에보완적역할을한다. 그림 1은이러한시스템의다이어그램을나타낸것으로, Vinculum을사용해소형 PIC MCU를 USB A 커넥터, 그리고 USB 플래시드라이브에연결했다. 개요설명이 PIC는시스템의컨트롤러로, 범용 I/O 핀 ( 핀 9, 10, 11에서 RC0, RC1, RA2) 을통해센서또는다른소스로부터데이터를받아서플래시드라이브에있는파일로의스트림에서데이터포맷변환및데이터쓰기를한다. 명령과데이터는 TXD( 핀 6) 을통해 VNC1L RXD( 핀 32) 로보내진다. VNC1L은 FAT 12/16/32 파일생성과 USB 플래시드라이브에서의데이터스토리지를담당하며, 핀 28, 29에서 USB2DM 및 USB2DP를통해드라이브와통신한다. 데이터는같은핀을통해플래시드라이브로부터읽혀지 087
고, PIC의 VNC1L TXD( 핀 31) 에서 RXD( 핀 5) 로보내져시스템펌웨어에의해사용된다. 이시스템은 PIC의펌웨어에의해제어되는데, PIC가내린명령에의해전송이제어되고, Vinculum의표준펌웨어에의해해석된다. 이는시스템을간단하게설명한것으로, 설계를완성하는데에는더복잡한것들이요구된다. 이들디바이스는전력, 클록제어를위한크리스털을필요로하며, 이들은프로그래밍작업도거쳐야한다. PIC의핀 2, 3에서 20MHz의크리스털을사용함으로써 UART 인터페이스에서최대 115200bps의높은변조속도가가능해 ( 내부 8MHz의오실레이터를이용하면최대 9600bps 정도밖에얻지못한다 ) 시스템의성능을향상시킬수있다. PIC 펌웨어에의해사용되는 PIC IO 핀 RC2 및 RC3은 VNC1Ls UART 인터페이스로 RTS/CTS 핸드세이크신호 (handshake signal) 를시뮬레이트한다. 250mA에서 5V의레귤레이트된 PSU가필요하며, USB A 커넥터에서최대 200mA를제공한다. VNC1L에전력을공급하는데에는 25mA, PIC16F688은 25mA의전력이필요하다. VNC1L 은 3.3V의공급전압을필요로하는데, 이는 3.3V LDO 레귤레이터에서제공되며, 레벨시프터를사용하지않고 PIC로연결될수있도록하는 5V의허용오차 I/O핀을가지고있다. 저전력애플리케이션을위해 VNC1L은필요없을경우 2mA의슬립모드로설정될수있다. 다시디바이스를활성화시키기위해서는 UART 인터페이스의링인디케이터 (RI) 핀을스트로브 (strobe) 한다. 여기에서처럼, 이것이 RXD 라인에연결되면, 들어오는더미명령 (dummy command) 에의해트리거링되어디바이스를활성화시킬수있다. 이디자인은또한핀 16 및 18 로부터전력을공급받는 2가지색 LED 인디케이터를포함하고있다. 이는 USB 드라이브의성공적인열거 (enumeration) 과파일시스템으로의액세스를나타내준다. VNC1L 펌웨어 ViNC1L은 VDAP(Vinculum Disk and Peripheral) 라는표준 펌웨어로프로그래밍되며, 이는 PIC로부터의명령을해석한다. 이들 VDAP 명령은 DIR, RD 및 WR 등 DOS와같은명령이다. 이명령셋은또한마이크로프로세서제어방식에가장적합한싱글바이트헥스 (hex) 명령어를지원한다. VDAP 명령은 PIC 펌웨어에포함되어있으며, USB 플래시드라이브로의액세스를제어한다. 일반적인시퀀스는파일을생성하고, 파일로의데이터읽기 / 쓰기및파일닫기에사용된다. VNC1L 및 PIC 프로그래밍개발환경이요구된다고가정하여이설계는각각의디바이스를위한 2개의프로그래밍헤더 (header) 를포함하고있다. 생산설계를위해두디바이스모두 PCB에서삽입전에미리프로그래밍될수있어헤더와점퍼 (jumper) 를제거한다. 일반동작동안 J1 및 J2 는파퓰레이트 (populate) 되어야하고, 다른점퍼들은오픈상태로있어야한다. VNC1L을프로그래밍하기위해 J1 과 J2 점퍼를제거해 VNC1L UART 입력을 PIC 출력으로부터절연시킨다. 5V PSU를차단하고 TTL-232R-3V3 케이블을 H2에연결시킨다. 이케이블의 USB 사이드를 VPROG 프로그래밍유틸리티가설치된 PC로연결시킨다. VNCL1A의 PROG# 핀을낮게당기기위해 J4를파퓰레이트한후디바이스를리셋하고프로그래밍모드로들어가게하기위해일시적으로 J3을단락시킨다. 프로그래밍이후에는점퍼설정을동작모드로재저장하는것을잊지말아야한다. PIC용프로그래밍헤더는디바이스의핀 RA0 및 RA1과 MCLR# 에연결되고, 헤더를통해 5V 프로그래밍전압 / 서플라이가공급된다. PIC 마이크로컨트롤러프로그래밍이전에 5V PSU 를차단해야한다. PICKit2와같은표준 PIC 개발환경에헤더를연결해마이크로칩의디버그및다운로딩툴을사용할수도있다. PIC가제공하는샘플 C 코드는플래시디스크가감지되고 hello.txt라는파일을열때까지기다린다. 그다음캐리지리턴 088
_ PIC 마이크로컨트롤러에 USB 플래시드라이버인터페이싱하기 (carriage return) 및라인피드 (line feed) 캐릭터와함께텍스트 Hello World 가파일로쓰여진다. 그리고나서파일을닫고, 디스크가제거될때까지기다린다. 결론 FTDI의 Vinculum VNC1L은사용하기쉬우며, 저비용마이크로컨트롤러와 USB 2.0 저 / 고속주변기기간의인터페이스프로그래밍도쉽게할수있다. DOS와같은명령셋을통해마이크로컨트롤러환경내에서데이터전송루틴을쓰고, 디버깅을쉽게할수있다. 단순한레이아웃또한임베디드시스템을위한저비용 USB 호스트구현이가능하도록해준다. 이로써저비용, 유비쿼터스 USB 플래시드라이브를시스템을위한데이터스토리지미디어로사용할수있을뿐만아니라필드에서소프트웨어업그레이드제공이가능하다. 이글의주제에서약간벗어나긴하지만, VNC1L 디바이스는또한매스스토리지디바이스외에다른많은 USB 주변기기를연결하는데도사용될수있다. Vinculum IC는또한 USB 인터페이스의전력예산의 10% 정도만추가하면되며, 시스템전력예산에는이보다훨씬적게든다. USB2.0 호스트컨트롤러는휴대용디바이스에쉽고간단하게추가될수있다. VDAP 펌웨어와완전한명령셋이기술된문서는 FTDI의 Vinculum 웹사이트 (http:www.vinculum.com) 에서다운로드할수있다. 소스코드 Code for logging data directly to a USB Flash disk using a PIC16F688 and the VNC1L. Commands received through UART. The PIC only handles Tx and Rx automatically for the UART, so handshaking must be implemented in code. Author: FTDI Code written for PIC16F688 using SourceBoost C compiler (www.sourceboost.com) Pin definitions for PIC16F688 on VPIC board PIC16F688 Pin Number Designation Function 1 VDD Power 2 RA5 OSC_IN 3 RA4 OSC_OUT 4 MCLR# MCLR# 5 RC5 Rx (UART) 6 RC4 Tx (UART) 7 RC3 CTS# (connects to RTS# on TTL cable) 8 RC2 RTS# (connects to CTS# on TTL cable) 9 RC1 Analogue/Digital Input 10 RC0 Analogue/Digital Input 11 RA2 Analogue/Digital Input (Stop button) 12 RA1 Analogue/Digital Input 089
(Start button) 13 RA Analogue/Digital Input (Use this one for analog input) 14 GND Ground #include <BoostCPic16.h> #include <boostc.h> char RX_FIFO_COUNT = 0x00; Reset RX FIFO count char RX_FIFO_HEAD_PTR = &SERIAL_RX_FIFO[0x00]; Initialise head pointer char RX_FIFO_TAIL_PTR = &SERIAL_RX_FIFO[0x00]; Initialise tail pointer char RX_FIFO_START = RX_FIFO_TAIL_PTR; Set lowest address of RX_FIFO char RX_FIFO_END = RX_FIFO_START + RX_FIFO_SIZE; Set highest address of RX_FIFO #pragma DATA 0x2007, _HS_OSC & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _IESO_OFF & char RX_STATUS = 0x00; Reset RX status char RX_FIFO_OVERRUN = 0x01; _FCMEN_OFF; #pragma CLOCK_FREQ 20000000; char RX_FIFO_UPPER_LIMIT = 0x03 (RX_FIFO_SIZE / 0x04); Buffer limit for handshaking char RX_FIFO_LOWER_LIMIT = (RX_FIFO_SIZE / 0x04); Buffer limit for handshaking Constants and variables for serial port Define serial port flags char _RTS = 0x04 RTS# is RC2 (Port C bit 2) char _CTS = 0x08; CTS# is RC3 (Port C bit 3) Define states for state machine char FLOW_NONE = 0x00; char FLOW_RTS_CTS = 0x01; enum Enum states char FLOW_CONTROL_ENABLED = 0x00; Initialise VNC1L_Idle, Idle state FLOW_ CONTROL_ENABLED to off VNC1L_DiskAvailable, VNC1L_CreateFile, Define serial port Rx buffer variables char SERIAL_RX_FIFO[0x20]; buffer for RX FIFO USE MULTIPLE OF 0x04! Allocate VNC1L_WriteFile, VNC1L_EndFile, VNC1L_WaitForRemove char RX_FIFO_SIZE = sizeof(serial_rx_fifo); Initialise ; FIFO size variable char VNC1L_State = VNC1L_Idle; Initialise state to idle 090
_ PIC 마이크로컨트롤러에 USB 플래시드라이버인터페이싱하기 char Synchronised = 0x01; portc &= ~_RTS; Set RTS# active (low) char GotDisk = 0x01; Routines for serial port Initialise serial port (Baud rate, handshaking, interrupt enable, enable receiver) Reset Rx FIFO void serial_init(long BaudRate, char Handshaking) / / Set up serial port pie1.rcie = 0x00; Disable interrupts void serial_resetrxfifo() intcon.gie = 0x00; intcon.peie = 0x00; pie1.rcie = 0x00; Disable interrupts intcon.gie = 0x00; intcon.peie = 0x00; RX_FIFO_COUNT = 0x00; Reset FIFO count to 0 baudctl = 0x00; ansel &= 0x3F; trisc = 0xDB; Digital IO on RC2, RC3 Set RC4 (Tx) & RC2 (RTS#) as RX_STATUS = 0x00; Reset FIFO status output,rc5 (Rx) & RC3 (CTS#) as input RX_FIFO_HEAD_PTR = (&SERIAL_RX_FIFO[0x00]); TRISC bits 1 for input, 0 for Set FIFO head pointer to address of first byte of SERIAL_RX_FIFO output RX_FIFO_TAIL_PTR = (&SERIAL_RX_FIFO[0x00]); Set FIFO tail pointer to address of first byte of SERIAL_RX_FIFO this stage portc = _RTS; Set RTS# high (inactive) at pie1.rcie = 0x01; Enable interrupts for Rx byte txsta = 0x04; Enable UART module and set intcon.gie = 0x01; 8,n,1 - Set BRGH to 1 intcon.peie = 0x01; rcsta.spen = 0x01; Enable serial port if (FLOW_CONTROL_ENABLED == 0x01) If using flow control switch (BaudRate) Set Baud rate 091
intcon.gie = 0x01; case 9600: spbrg = 0x81; intcon.peie = 0x01; rcsta.cren = 0x01; Enable receiver case 19200: spbrg = 0x40; case 57600: spbrg = 0x15; Send a byte directly from the transmit register case 115200: spbrg = 0x0A; void serial_sendbyte(char TX_BYTE) default: if (FLOW_CONTROL_ENABLED == 0x01) spbrg = 0x81; Default to 9600 if not a valid achievable Baud rate spbrgh = 0x00; CTS# to become active (low) while (portc & _CTS); Wait for while (!txsta.trmt); Wait for TSR to be empty txreg = TX_BYTE; Move byte to send into if (Handshaking == FLOW_RTS_CTS) TXREG txsta.txen = 1; Start transmission portc &= ~_RTS; required, set RTS# active (low) If handshaking is while (!txsta.trmt); Wait for TSR to be empty - indicates sending is complete FLOW_CONTROL_ENABLED = 0x01; Set flow control enabled flag serial_resetrxfifo(); pir1.rcif = 0x00; pie1.rcie = 0x01; Reset Rx FIFO Clear Rx interrupt flag Enable interrupts for Rx byte Read a byte directly from the receive character register void serial_receivebyte(char RX_BYTE) 092
_ PIC 마이크로컨트롤러에 USB 플래시드라이버인터페이싱하기 If using flow control RX_BYTE = rcreg; pir1.rcif = 0x00; Clear Rx interrupt flag portc = _RTS; Set RTS# inactive (high) Add a byte from the receive character register to the receive FIFO buffer intcon.gie = 0x00; Disable interrupts intcon.peie = 0x00; RX_FIFO_HEAD_PTR++ = rcreg; Add received byte to RX_FIFO and then increment head pointer void serial_addtorxfifo() RX_FIFO_COUNT++; Increment byte count if (RX_FIFO_COUNT >= RX_FIFO_SIZE) If Rx FIFO if (RX_FIFO_HEAD_PTR >= RX_FIFO_END) If head is full pointer is greater than allocated FIFO end address RX_STATUS = RX_STATUS RX_FIFO_HEAD_PTR = RX_FIFO_START; / / RX_FIFO_OVERRUN; Set overrun flag Wrap-around buffer to start address again (circuluar FIFO) if (FLOW_CONTROL_ENABLED == 0x01)/ / If using flow control if ((RX_FIFO_COUNT < RX_FIFO_UPPER_LIMIT) && portc = _RTS; Set RTS# (FLOW_CONTROL_ENABLED == 0x01)) If Rx FIFO is not full inactive (high) portc &= ~_RTS; Set RTS# active (low) return; intcon.gie = 0x01; Re-enable interrupts if (RX_FIFO_COUNT >= RX_FIFO_UPPER_LIMIT) intcon.peie = 0x01; Keep some space in the FIFO for bytes already being sent if (FLOW_CONTROL_ENABLED == 0x01)/ / 093
Read a byte out of the receive FIFO buffer portc &= ~_RTS; Set RTS# active (low) void serial_readfromrxfifo(char RX_FIFO_BYTE) if (RX_FIFO_COUNT == 0) If FIFO is empty VNC1L VDAP commands go here return; Exit - no data to read intcon.gie = 0x00; Disable interrupts intcon.peie = 0x00; Echo command using E - same for short command set or RX_FIFO_BYTE = RX_FIFO_TAIL_PTR++; Read a byte from the FIFO at position given by RX_FIFO_TAIL_PTR and then increment tail pointer long command set RX_FIFO_COUNT--; Decrement byte count if (RX_FIFO_TAIL_PTR >= RX_FIFO_END) pointer is greater than allocated FIFO end address If tail void VNC1L_Big_E() serial_sendbyte('e'); Send 'E' serial_sendbyte(0x0d); Send carriage RX_FIFO_TAIL_PTR = RX_FIFO_START; Wrap-around buffer to start address again (circuluar FIFO) return intcon.gie = 0x01; Re-enable interrupts intcon.peie = 0x01; Echo command using e - same for short command set or long command set if ((RX_FIFO_COUNT < RX_FIFO_LOWER_LIMIT) && (FLOW_CONTROL_ENABLED == 0x01)) If using flow control void VNC1L_Small_e() 094
_ PIC 마이크로컨트롤러에 USB 플래시드라이버인터페이싱하기 delay_ms(100); / / serial_sendbyte('e'); Send 'e' serial_sendbyte(0x0d); Send carriage Wait for 2 byte response return if (RX_FIFO_COUNT > 0x00) If data is available Synchronise to the VNC1L using the e and E echo commands while (RX_FIFO_COUNT > 0x02) Read all data available except last 2 bytes serial_readfromrxfifo(&fifobyte1); If more than 2 bytes char VNC1L_Sync() available, read surplus ones char LoopCount = 0x00; char FIFOByte1 = 0x00; char FIFOByte2 = 0x00; char Got_Big_E = 0x00; serial_readfromrxfifo(&fifobyte1); Check that remaining 2 bytes are 'E' and 0x0D char Got_Small_e = 0x00; serial_readfromrxfifo(&fifobyte2); serial_resetrxfifo(); Reset FIFO before if ((FIFOByte1 == 'E') && synchronising (FIFOByte2 == 0x0D)) while ((Got_Big_E == 0x00) && (LoopCount < 0xFF)) Got_Big_E = 0x01; VNC1L_Big_E(); Send Big else E echo LoopCount++; Increment delay_ms(10); / / loop count Wait a bit and retry synchronisation while (RX_FIFO_COUNT < 0x02) 095
if (Got_Big_E == 0x01) char VNC1L_FindDisk() else return 0x00 Return 0x01 if disk is found, char FIFOByte1 = 0x00; VNC1L_Small_e(); while (RX_FIFO_COUNT < 0x02) delay_ms(10); Wait for 2 char FIFOByte2 = 0x00; char FIFOByte3 = 0x00; char FIFOByte4 = 0x00; char FIFOByte5 = 0x00; byte response serial_readfromrxfifo(&fifobyte1); / / Check that remaining 2 bytes are 'e' and 0x0D serial_readfromrxfifo(&fifobyte2); if ((FIFOByte1 == 'e') && (FIFOByte2 == 0x0D)) Got_Small_e = 0x01; / / If small e found, then synchronised serial_sendbyte(0x0d); Send carriage return while (RX_FIFO_COUNT < 0x05); / / Wait until at least 5 bytes in the Rx FIFO serial_readfromrxfifo(&fifobyte1); Read bytes out of Rx FIFO serial_readfromrxfifo(&fifobyte2); serial_readfromrxfifo(&fifobyte3); serial_readfromrxfifo(&fifobyte4); serial_readfromrxfifo(&fifobyte5); if ((FIFOByte1 == 'D') && (FIFOByte2 == ':') && (FIFOByte3 == 0x5C) && (FIFOByte4 == '>') && (FIFOByte5 == return Got_Small_e; 0x0D)) Check for prompt Look for disk - assumes long command set being used return 0x01; then return disk available else If prompt found, while (RX_FIFO_COUNT > 0x00) 096
_ PIC 마이크로컨트롤러에 USB 플래시드라이버인터페이싱하기 serial_readfromrxfifo(&fifobyte1); bytes out of the FIFO return 0x00; available Read any additional Return no disk serial_sendbyte(0x0d); Send carriage return while (RX_FIFO_COUNT < 0x05) Wait until at least 5 bytes in the Rx FIFO delay_ms(10); Wait for 5 byte response("d:\>" + 0x0D) while (RX_FIFO_COUNT > 0x00) Open file for write command (OPW) using long command set serial_readfromrxfifo(&fifobyte); / / Read response bytes form FIFO void VNC1L_OpenFile() char FIFOByte = 0x00; Write to file command (OPW) using long command set serial_sendbyte('o'); serial_sendbyte('p'); serial_sendbyte('w'); serial_sendbyte(' '); serial_sendbyte('h'); serial_sendbyte('e'); Send 'O' Send 'P' Send 'W' Send ' ' Send 'h' Send 'e' void VNC1L_WriteToFile() char FIFOByte = 0x00; serial_sendbyte('l'); Send 'l' serial_sendbyte('w'); Send 'W' serial_sendbyte('l'); Send 'l' serial_sendbyte('r'); Send 'R' serial_sendbyte('o'); Send 'o' serial_sendbyte('f'); Send 'F' serial_sendbyte('.'); Send '.' serial_sendbyte(' '); Send ' ' serial_sendbyte('t'); serial_sendbyte('x'); Send 't' Send 'x' serial_sendbyte(0x00); Send 0x00 - Number of bytes to write MSB serial_sendbyte('t'); Send 't' serial_sendbyte(0x00); Send 0x00 097
serial_sendbyte(0x00); Send 0x00 serial_readfromrxfifo(&fifobyte); / / serial_sendbyte(0x0e); Send 0x0E - Number of bytes to write LSB Read response bytes form FIFO serial_sendbyte(0x0d); Send carriage return serial_sendbyte('h'); serial_sendbyte('e'); serial_sendbyte('l'); serial_sendbyte('l'); serial_sendbyte('o'); serial_sendbyte(' '); serial_sendbyte('w'); serial_sendbyte('o'); serial_sendbyte('r'); serial_sendbyte('l'); serial_sendbyte('d'); Send 'H' Send 'e' Send 'l' Send 'l' Send 'o' Send ' ' Send 'W' Send 'o' Send 'r' Send 'l' Send 'd' Close file command (CLF) using long command set void VNC1L_CloseFile() char FIFOByte = 0x00; serial_sendbyte('!'); Send '1' serial_sendbyte('c'); Send 'C' serial_sendbyte(0x0d); Send carriage serial_sendbyte('l'); Send 'L' return serial_sendbyte('f'); Send 'F' serial_sendbyte(0x0a); Send line feed serial_sendbyte(' '); Send ' ' serial_sendbyte(0x0d); Send carriage serial_sendbyte('h'); Send 'h' return serial_sendbyte('e'); serial_sendbyte('l'); Send 'e' Send 'l' while (RX_FIFO_COUNT < 0x05) Wait until at serial_sendbyte('l'); Send 'l' least 5 bytes in the Rx FIFO serial_sendbyte('o'); Send 'o' serial_sendbyte('.'); Send '.' delay_ms(10); Wait for 5 byte serial_sendbyte('t'); Send 't' response("d:\>" + 0x0D) serial_sendbyte('x'); Send 'x' serial_sendbyte('t'); Send 't' serial_sendbyte(0x0d); Send carriage while (RX_FIFO_COUNT > 0x00) return 098
_ PIC 마이크로컨트롤러에 USB 플래시드라이버인터페이싱하기 while (RX_FIFO_COUNT < 0x05) least 5 bytes in the Rx FIFO Wait until at to Rx FIFO serial_addtorxfifo(); Add received byte pir1.rcif = 0x00; Clear RCIF flag delay_ms(10); Wait for 5 byte response("d:\>" + 0x0D) while (RX_FIFO_COUNT > 0x00) serial_readfromrxfifo(&fifobyte); / / Read response bytes form FIFO Main line code void main() char Sync = 0x00; Interrupt routines go here VNC1L_State = VNC1L_Idle; Initialise state to Use receive character interrupt to add received idle characters to the RX FIFO void interrupt() serial_init(9600, FLOW_RTS_CTS); Baud rate and flow control delay_s(1); time for power up if (VNC1L_Sync() == Synchronised) to Vinculum Initialise Allow some Synchronise while (1) Main state machine - do not return from here if (pir1.rcif) switch (VNC1L_State) 099
case VNC1L_Idle: Sync = VNC1L_CloseFile(); (CLF) Send close file command VNC1L_Sync(); VNC1L_State i f = VNC1L_WaitForRemove; Update state to indicate (VNC1L_FindDisk() == GotDisk) Check for disk witing for disk to be removed VNC1L_State = VNC1L_DiskAvailable; Update state to case VNC1L_ indicate disk found WaitForRemove: Sync = VNC1L_Sync(); if (VNC1L_ case VNC1L_DiskAvailable: FindDisk()!= GotDisk) Check for disk VNC1L_OpenFile(); Send open file for write command (OPW) - file name "hello.txt" VNC1L_State = VNC1L_Idle; Update state to indicate VNC1L_State disk has been removed and return to idle = VNC1L_WriteFile; Update state to indicate file has been created and can be written default: case VNC1L_WriteFile: VNC1L_State VNC1L_WriteToFile(); (WRF) - write "Hello World!" Send write file command VNC1L_State = VNC1L_Idle; / Default to idle state = VNC1L_EndFile; Update state to indicate file has been written and can now be closed case VNC1L_EndFile: 100