예전에 설명하였던 LCD1602나 LCD12864의 경우 글자를 출력하기 위한 기능이 디스플레이 내부에 들어 있었지만, SSD1306은 그런 기능이 없기 때문에 글자를 표현하기 위해서 직접 점들을 조합하여야 한다.이번 프로젝트에서는 5x7 픽셀의 점들을 이용하여 ASCII code를 출력하는 방법에 대해서 설명하겠다.예를 들어 대문자 'A'를 출력하기 위한 표시는 위의 그림과 같다. 가로로 5칸, 세로로 7칸의 조합으로 표시하며, 좌,우,상,하 글자와 구분하기 위하여 아래로 한칸, 오른쪽에 한줄의 공백을 두어야 한다. SSD1306 datasheet 문서를 보면 Page내에서 위쪽에 있는 점이 D0에 해당되고 가장 아래쪽에 있는 점이 D7에 해당된다. 그러므로, 'A'의 첫번째 행을 이진수로 표현하면 '..
앞의 글들을 통해서 기본적인 SSD1306의 동작 원리를 설명하였으므로 이를 응용하여 화면에 원하는 위치에 점 하나를 표시하는 방법을 구현해 보도록 하겠다.점 하나만을 표시하고자 할때 주의할 점은 위의 그림을 보면 알겠지만, column의 위치는 특정 SEG위치를 지정해 줌으로써 원하는 위치를 직접 지정해 줄수 있지만, row의 위치는 Page단위, 즉, 1바이트 크기만큼씩 지정해 줄수밖에 없는 구조에 대해 고려해 주어야 한다는 것이다.만약, 18번째 줄의 어딘가에 점하나를 출력하고자 원한다면, PAGE2의 D1비트의 값을 1로 설정해 주면 된다. 하지만 이때 나머지 비트값들은 그대로 유지해 주어야한다. 그렇지 않으면, D1비트값만 켜지고 나머지 줄들의 데이터는 모두 0이 되므로 꺼지게 되는 것이다.따라..
앞의 글에서 SSD1306의 세가지 출력모드(addressing mode)가 있다는 것을 간단히 언급하였고, 그중에서 page addressing mode에 대해서 설명하였다.이번에는 나머지 horizontal mode와 vertical mode에 대해서 설명하도록 하겠다. 두가지 모드는 출력되는 방향만 다를뿐 나머지 동작되는 방식은 완전히 동일하다.위의 그림에 Horizontal addressing mode일때의 동작되는 방식이 설명되어 있다.GDDRAM에 데이터를 쓰면 자동적으로 column이 증가되고, COL127에 데이터를 쓰면 RAM 주소가 COL0가 되고 PAGE는 다음 영역으로 자동으로 넘어가게 된다. 만약 가장 마지막 픽셀에 해당되는 RAM에 데이터가 쓰여지면 PAGE0, COL0의 주소로..
이전 글에서 MCU와 OLED 모듈간의 SPI 통신이 제대로 수행되는지 확인하는 방법에 대해서 설명하였다. 확인하는 방법으로 Entire Display ON 레지스터의 값을 1로 설정하여 전 영역의 픽셀들이 모두 켜보는것이었다.기본적인 통신이 잘 되는지 확인하였으면 정상적인 화면 출력을 위하여 Entire Display ON 레지스터의 값을 0으로 만들어 어떻게 화면 출력이 이루어지는지 확인해 보도록 하겠다. void ssd1306_init(void) { _delay_ms(1); ssd1306_reset(); ssd1306_chargepump_enable(true); ssd1306_entire_on(false); ssd1306_display_on(true); } 8번 줄에 보이는것처럼 ssd1306_en..
이번 프로젝트는 SSD1306를 사용한 OLED 128 x 64 디스플레이를 구동해 보는 방법을 구현해 보는것이다.먼저 해야할 일은 SSD1306 datasheet를 구해서 충분히 이해될 정도로 반복해서 읽어 보는것이다.위의 표에 설명되어 있는것처럼 SSD1306은 MCU와 연결하는 방법이 5가지가 있음을 알수 있다. 이번 프로젝트에서는 그 중에서 4-wire SPI 연결 방법을 이용하여 MCU와 연결하도록 하겠다.이 프로젝트에서는 위의 그림에 보이는 OLED 디스플레이 모듈을 사용하도록 하겠다. 그림을 보면 모두 7핀이 제공되는데, SDIN(MOSI), SCLK(SCK), CS, D/C 이렇게 4개의 신호선을 SPI 통신으로 연결하는데 사용하고, Reset 신호를 받아들이기 위한 RES핀과 전원 연결을..
지금까지 분석하고 만들어 봤던 FAT32 파일 시스템 프로젝트를 VS1003 프로젝트에 적용 시켜 문제 없이 제대로 동작하는지 확인해 보도록 하겠다. void setup(void) { sysclock_init(BD_CLKSRC, BD_PLLMUL, BD_AHBPRE, BD_APB1PRE, BD_APB2PRE, BD_ADCPRE); uart_init(); spi_init(BAUD_PRE256); printf(CLEAR_SCRN"Coarse MP3 Player. %s - %s\n\n", __DATE__, __TIME__); init_command(); vs1003_init(); vs1003_write_reg(SCI_CLOCKF, 0xD000); vs1003_chg_volume(40); microsd_init..
이번에는 SD 메모리 카드에 기록되어 있는 파일들 중 하나를 선택하여 끝까지 읽어 오는 방법에 대해서 설명하도록 하겠다.파일을 읽어 오기 위해서는 먼저 어떤 파일을 읽어 올것인지 지정해 주어야 하는데, 이를 위하여 fat32_openfile() 함수를 이용한다. int fat32_openfile(const char *path) { struct fat32_info *fat = &cur_file; struct dir_entry cur_dir; char tmp_buf[BD_ARG_BUF_SZ]; char *delimit = "/"; char *token; fat->dir.clst_index = fat->disk.root_clst; fat->dir.sect_index = 0; fat->dir.entry_inde..
이번 글에서는 root directory에서 출발하여 특정 디렉토리에 어떤 하위디렉토리와 파일들이 있는지 알아보는 방법에 대해서 설명하도록 하겠다.이를 위하여 두개의 API를 만들어볼 예정이다.먼저 특정 디렉토리를 선택하기 위한 fat32_opendir()과 선택된 디렉토리에서 차례차례로 directory entry를 가져오기 위한 fat32_readdir() 함수이다.먼저, FAT32 파일 시스템의 기본 파라미터와 디렉토리 관리를 위한 구조체를 만들어 보도록 하겠다.struct disk_info { uint32_t sect_size; uint32_t clst_size; uint32_t root_clst; uint32_t bpb_start; uint32_t fat_start; uint32_t data_s..
이번 글에서는 FAT 영역에 어떤 정보가 들어가는지에 대하여 설명하도록 하겠다.FAT영역에 저장되는 FAT entry는 한마디로 파일이나 디렉토리가 Data 영역의 몇번째 클러스터에서 시작되는지 알려주기 위하여 cluster index를 저장하는 table이라고 할 수 있겠다.앞에서 설명했듯이 FAT32의 경우 root directory가 Data 영역 어디에도 위치할 수 있는데, 실제로는 어디에 있는지 클러스터 index를 boot sector에서 알려주었기 때문에 클러스터 index에 해당되는 위치에서 root directory 내용을 읽을수 있었다.위의 그림은 FAT#0 영역을 dump 해 본 것인데, 초록색박스로 표시된 부분이 FAT32에서 예약된 cluster#0, cluster#1이고, 빨간색..
이번 글에서는 디렉토리와 파일들에 대한 메타 정보를 담고 있는 directory entry에 대해서 알아보도록 하겠다.첫번째로 할 일은, 디렉토리 정보를 분석하기에 앞서 FAT32에 있는 주요한 세개의 영역이 어디에서 시작하는지 그 정보를 따로 저장해 두는것이 좋다.예를 들어 앞의 글에서 설명한 내용중에 다음 그림을 볼 수 있는데,BPB는 2048에서 시작되고, FAT영역은 3466에서, Data 영역은 18432에서 시작되는 것으로 확인 되었다. 이 값들은 SD 메모리 카드마다 다를수 있음을 주의하여야 한다.이 영역들의 시작 위치는 다음과 같은 코드로 알아낼 수 있다. bpb.bpb_start = bs; bpb.fat_start = bs + bpb.rsvd_sec_cnt; bpb.data_start =..