대메뉴 바로가기 본문 바로가기

데이터 기술 자료

데이터 기술 자료 상세보기
제목 PSoC로 간단히 만드는 나만의 미니 앨범
등록일 조회수 4490
첨부파일  

PSoC로 간단히 만드는

나만의 미니 앨범 ②



첫 번째 연재에서는 프로젝트를 간단히 소개하고 PSoC 사용법 등을 설명했다. 이번 호에서는 미니 앨범 프로젝트의 구조와 각각의 구성요소를 살펴보겠다.



미니 앨범 프로젝트 구조

전체 프로젝트는 두 개의 단계로 구성된다. 첫 번째 단계는 PC 로부터 사진을 받아 미니 앨범의 플래시 메모리에 SPI 통신으로 저장하는 단계고 두 번째 단계는 플래시 메모리에 저장된 사진를 LCD 에 디스플레이하는 단계다. 두 번째 단계에서는 플래시 메모리로부터 SPI로 사진을 전달받아 LCD에 SPI로 전송한다. 실제 미니 액자의 동작을 하는 부분이다.

미니 앨범에는 세 개의 프로젝트가 필요하다. 첫째는 PC에서 RS232로 사진를 송신하는 PC 프로젝트다. 둘째는 RS232로 받은 사진를 플래시 메모리에 기록하는 마이컴 프로젝트, 셋째가 미니 앨범이다. 미니 앨범 만들기는 플래시 메모리에 저장된 사진을 LCD에 디스플레이하는 프로젝트다.



이 세 가지 프로젝트를 완성하기 위해 플래시 메모리, LCD, 그리고 RS232 프로토콜에 대해 알아보자.



플래시 메모리

이 프로젝트에서 사용할 플래시 메모리는 시리얼 플래시로써 SPI 통신으로 Read/Write/Erase가 가능하다. 시리얼 플래시를 다룰 때 몇 가지 주의할 점을 리스트들을 통해 확인하자. 플래시 메모리에 Write하기 위해서는 두 가지 작업이 선행돼야 한다. 첫 번째가 프로텍션을 풀어야 하는 것이다. 실수로 플래시 메모리의 데이터를 지우는 것을 방지하기 위해서 프로텍션을 걸어 놓는데 최초 동작 시 프로텍션을 풀어주어야 한다. <리스트 1>은 각 블록에 걸려있는 프로텍션을 푸는 소스다.



<리스트 1> 각 블록에 걸린 프로텍션을 푸는 소스 // remove protection for (i=0i< 18i++) { block_protection_18[i]=0x00 } SPI_WriteBlockProtection(); SPI_Wait_Busy();



Line 780에서 호출하는 SPI_WriteBlockProtection() 함수 내부는 <리스트 2>와 같이 돼있는데 필자가 모두 작성한 코드는 아니다. 인터넷에 올라와 있는 소스를 기본으로 사용해 포트제어 함수를 PSoC용으로 바꿨다. 시리얼 플래시 제어 소스의 경우 인터넷에서 FlashName.c로 검색하면 대부분의 플래시 소스를 구할 수 있다.



<리스트 2> 플래시 프로텍션 제어 함수 void SPI_WriteBlockProtection (void) { unsigned char i = 0 SPI1_CS_Write(0); Flash_SPI_1_SpiUartWriteTxData(0x42); for (i=18i>0i--) { Flash_SPI_1_SpiUartWriteTxData(block_protection_18[i-1]); } SPI1_CS_Write(1); }



시리얼 플래시 제어 커맨드 하나를 스팩문서와 비교하여 살펴보겠다.

0x42 ? block #0 ? block #1 …

프로텍션을 풀기 위해 18개의 블록 번호를 차례로 송신하는 것을 알 수 있다. 스펙에서 블록 프로텍션을 찾아보면 <그림 4>처럼 나와있다. 이 스팩을 보면서 소스를 작성하면 되지만 이미 잘 작성된 코드가 인터넷에 많이 올라와 있으므로 가져다가 사용하면 빠르게 작업할 수 있다.



<리스트 1>의 Line 781에서 호출한 SPI_Wait_Busy() 함수를 포함해 앞으로 나오는 플래시 제어 관련 함수는 모두 마찬가지로 인터넷에서 받은 소스에서 포트를 제어하는 부분을 PSoC로 교체한 함수들이다. Erase는 4096 byte 단위로 한다. 4096이라는 단위는 플래시마다 달라질 수 있으므로 스펙을 참고하여야 한다.

<리스트 3>은 플래시 메모리를 Erase하는데 사진의 시작 위치로부터 57개의 블록을 지운다.



<리스트 3> 플래시 Erase // 사진을 넣을 위치를 4096 단위로 지움 for (i=0 i< eEraseCnt i++) { SPI_WREN(); SPI_Sector_Erase(imgPos * eImageRoomSize + i * eEraseSize); SPI_Wait_Busy(); }



마지막으로 256 byte로 이루어진 페이지 단위로 Write를 실행한다.



<리스트 4> 플래시 Write // 사진을 플래시에 기록하기 SPI_WREN(); SPI_Page_Program(imgPos * eImageRoomSize + i * 256); SPI_Wait_Busy();



이렇게 하면 사진를 받아 플래시 메모리에 Write 할 수 있다. 다음은 LCD 디스플레이에 대해 알아보자.



LCD 디스플레이
사진 한 장의 사이즈는 가로×세로×pixel depth 이므로 320×240×24 = 1843200 bit이고 byte로 계산하면 230400 byte다. 이미지를 플래시 메모리에 넣을때 주의할 사항이 하나 있는데 플래시의 특성상 1 byte 단위로 write 할 수 없다. 게다가 write하기 전에 반드시 erase를 해야 한다. erase는 block이라는 단위로, write는 page라는 단위로 수행되므로 스팩에서 block과 page의 사이즈를 확인해야 한다. 우리가 사용할 플래시 메모리의 page는 256 byte, Block은 4096 byte 이다.

즉, 사진 한 장당 할당해야 할 크기는 230400이 아니라 4096×57 = 233472 byte다. 이렇게 할당해야 사진 한장을 지울 때 다른 사진까지 지우는 문제가 생기지 않는다. <그림 3>을 보면 Block #4가 Image #1, #2에 걸쳐있기 때문에 Block #4를 지울 때 Image #1과 #2가 같이 지워지는 문제가 발생하므로, <그림 4>처럼 Image에 대한 배치를 하여 Image #1과 Image #2를 Block 단위로 분리시켜야 한다.







LCD

필자가 사용한 LCD에 장착된 컨트롤러는 ILI9341이라는 컨트롤러이다. 이 프로젝트에서 알아야 할 ILI9341의 커맨드는 X좌표 설정, Y좌표 설정, Memory Write다. X좌표 설정하고 Y좌표 설정하고 플래시 메모리에서 사이 디스플레이 된다.

<리스트 4>의 1234, 1238 line이 LCD로 보내는 데이터이고 1237 Line은 플래시 메모리에서 사진을 읽어오는 코드이다. 즉, 사양서 대로 0x2C를 보낸 뒤 데이터를 연이어 보내고 있다.



<리스트 5> LCD 에 디스플레이하는 소스 while(1) { Set_Col(0, 239); Set_Page(0, 319); Send_Cmd(0x2C); for (i=0 i< (240 * 320 * 3); i++) { ch = Flash_SPI_1_SpiUartReadRxData(); SPI_Transfer(ch); } CyDelay(5*60*1000); // ms imgPos++ if(imgPos > eEndImgNo) { imgPos = eStartImgNo } }



그럼 LCD에 디스플레이할 데이터를 보낼 때 어떻게 보내야 하는지를 살펴보아야 하는데, 스펙에 보면 <그림 8>처럼 되어있다. 18bit/pixel는 한 픽셀에 18bit를 사용한다는 의미이고, RGB666은 Red, Green, Blue에 각 6bit씩 할당한다는 의미이다. 데이터를 보낼 때는 하위 두 비트 (D0, D1)은 아무 의미가 없다. 예를 들어 빨간색 한 pixel을 전송 하려면 0xFC ? 0x00 ? 0x00 이렇게 3 byte를 보내면 된다(<그림 5> 참조).



LCD 컨트롤러 소스도 인터넷에 다양하게 있는데, 컨트롤러 이름으로 찾거나, 아두이노에 사용되는 LCD 쉴드의 소스를 찾아서 활용하면 빠른 시간에 개발할 수 있을 것이다.



RS232 프로토콜

PC로부터 사진을 전송 받아야 하므로 PC와 마이컴이 통신할 수 있는 프로토콜을 만들어야 하는데 간단하게 아래와 같이 만들었다. 사진을 전송하겠다는 커맨드를 보낸뒤 256byte씩 사진을 나누어서 보내는 것이다. 256byte씩 보내는 이유는 필자가 사용한 플래시 메모리의 page가 256byte이기 때문이다(<그림 6> 참조).



마이컴 프로그램에서는 <리스트 6>처럼 UART_ReadRxData() 로 PC에서 송신하는 데이터가 0x02, ‘I’, image number 순서대로 오는지 확인한다.



<리스트 6> 사진 전송 커맨드 확인 소스 while(1) { if ( UART_ReadRxStatus() == UART_RX_STS_FIFO_NOTEMPTY) { ch = UART_ReadRxData(); // 사진은 상위 6 bit 만 사용하므로 0x02 은 사진 데이터에서 나올 수 없음. if ((ch == 0x02) && (cnt == 0)) { cnt++; } else if ((ch == 'I') && (cnt == 1)) { cmd = eCmdImage; break; } else { cnt = 0; } } }



<리스트 7>은 256 byte씩 사진을 받아서 플래시 메모리에 write하고 다음 256 byte를 요청하기 위해 1 byte를 송신하는 부분이다.



<리스트 7> 플래시 메모리 Write for (i=0 i< eWriteCnt ; i++) { // data 256 개 받기 j = 0 while(1) { if ( UART_ReadRxStatus() == UART_RX_STS_FIFO_NOTEMPTY) { data_256[j++] = UART_ReadRxData(); } if (j >= 256) { // data flash 에 기록하기 SPI_WREN(); SPI_Page_Program(imgPos * eImageRoomSize + i * 256); SPI_Wait_Busy(); sprintf(buf, "%d", i); UART_PutString(buf); break; } } }



PC 쪽 프로그램은 “Picture Box”로 사진을 차례로 불러와서, 한 픽셀씩 데이터를 읽어 RS232로 송신한다.



<리스트 8>을 보면 사진을 “Picture Box”로 읽어들이고, 사진 전송을 시작하겠다는 0x02 와 ‘I’를 나타내는 0x49, 그리고 34장중 몇 번째 image를 보낼 것인지를 나타내는 ImgPos를 송신한다.



<리스트 8> 사진 읽기 및 전송 시작 PictureBox1.Image = Image.FromFile(imgPath) Dim TempBitmap As New Bitmap(PictureBox1.Image) ' 0x02 - 'I' - imgPos SerialPort1.Write({&H2, &H49, imgPos}, 0, 3)



<리스트 9>를 보면 “Picture box”에 불러온 사진으로부터 GetPixel() 함수를 호출하여 한 pixel을 읽어 col3 변수에 저장하고, col3.R로 Red 값을 읽어서 전송한다. 같은 방법으로 col2.G, col2.B를 읽어 전송하면 사진의 모든 pixel이 전송된다.



<리스트 9> 사진 전송 소스 For j = 0 To 320 - 1 RichTextBox2.Text = "l-cnt:" & 320 - 1 - j & vbCrLf & RichTextBox2.Text For i = 0 To 240 - 1 col3 = TempBitmap.GetPixel(i, j) SerialPort1.Write({col3.R * (63 / 255) * 4}, 0, 1) Application.DoEvents() If cnt >= 255 Then cnt = 0 timeOut = 0 Application.DoEvents() While (True) byte2read = SerialPort1.BytesToRead If byte2read > 0 Then SerialPort1.Read(strBuff, 0, byte2read) For k = 0 To byte2read - 1 RichTextBox1.Text = RichTextBox1.Text & Chr(strBuff(k)) '& "," Next k



글을 마치며

실제 개발은 짬짬히 1~2주 정도 소요된 간단한 프로젝트였지만 글로 옮기다 보니 집고 넘어가야할 사항이 많아 템포가 빠르게 진행된다.



출처 : 마이크로소프트웨어 8월호

제공 : 데이터 전문가 지식포털 DBguide.net