Add SD card menu

This commit is contained in:
Vincent Mistler
2023-03-05 16:21:22 +01:00
parent 3e8366e043
commit ea8721d465
6 changed files with 1048 additions and 2959 deletions
-1
View File
@@ -12,7 +12,6 @@ add_subdirectory(ext/FatFs_SPI build)
add_executable(RP2040_GB
src/main.c
src/rom.c
src/mk_ili9225.c
ext/minigb_apu/minigb_apu.c
ext/i2s/i2s.c
+11
View File
@@ -665,6 +665,17 @@ void auto_assign_palette(uint16_t palette[3][4], uint8_t game_checksum, const ch
}
case 0x16:
{
if(disambiguation_character=='M') {
/* CUSTOM */
/* Batman - The Animated Series (USA, Europe) */
get_colour_palette(palette,0x0D,0x05);
break;
} else {
/* Donkey Kong Land (Japan) */
get_colour_palette(palette,0x0C,0x05);
break;
}
/* Yakuman (Japan);; Yakuman (Japan) (Rev A) */
get_colour_palette(palette,0x12,0x00);
break;
+32
View File
@@ -23,6 +23,7 @@
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#define SCREEN_SIZE_X 176u
#define SCREEN_SIZE_Y 220u
@@ -141,3 +142,34 @@ void mk_ili9225_set_x(uint8_t x);
* Exit and stop using LCD. Currently does nothing.
*/
void mk_ili9225_exit(void);
/**
* Fill a rectangle at the given location, size and color.
*/
void mk_ili9225_fill_rect(uint8_t x,uint8_t y,uint8_t w,uint8_t h,uint16_t color);
/**
* Fill the entire screen with the specified RGB565 color
*/
void mk_ili9225_fill(uint16_t color);
/**
* Set a specified pixel to the given color
*/
void mk_ili9225_pixel(uint8_t x,uint8_t y,uint16_t color);
/**
* Copy the specified framebuffer at the given coordinates
*/
void mk_ili9225_blit(uint16_t *fbuf,uint8_t x,uint8_t y,uint8_t w,uint8_t h);
/**
* Return an 8x8 framebuffer for the given letter and color / background color
*/
void mk_ili9225_get_letter(uint16_t *fbuf,char letter,uint16_t color,uint16_t bgcolor);
/**
* Write text to the screen using the the coordinates as the upper-left corner of the text.
* All characters have dimensions of 8x8 pixels.
*/
void mk_ili9225_text(char *s,uint8_t x,uint8_t y,uint16_t color,uint16_t bgcolor);
+265 -222
View File
@@ -46,6 +46,7 @@
#include <hardware/dma.h>
#include <hardware/spi.h>
#include <hardware/sync.h>
#include <hardware/flash.h>
#include <hardware/timer.h>
#include <hardware/vreg.h>
#include <pico/bootrom.h>
@@ -81,27 +82,29 @@
#define GPIO_LED 22
#if ENABLE_SOUND
// Global variables for audio task
// stream contains N=AUDIO_SAMPLES samples
// each sample is 32 bits
// (16 bits for the left channel + 16 bits for the right channel in stereo interleaved format)
// This is intended to be played at AUDIO_SAMPLE_RATE Hz
uint16_t *stream;
/**
* Global variables for audio task
* stream contains N=AUDIO_SAMPLES samples
* each sample is 32 bits
* 16 bits for the left channel + 16 bits for the right channel in stereo interleaved format)
* This is intended to be played at AUDIO_SAMPLE_RATE Hz
*/
uint16_t *stream;
#endif
/* DMA channel for LCD communication. */
static uint dma_lcd;
/* Definition of ROM data variable. Must be declared like:
* #include <pico/platform.h>
* const unsigned char __in_flash("rom") rom[] = {
* ...
* };
/** Definition of ROM data
* We're going to erase and reprogram a region 1Mb from the start of the flash
* Once done, we can access this at XIP_BASE + 1Mb.
* Game Boy DMG ROM size ranges from 32768 bytes (e.g. Tetris) to 1,048,576 bytes (e.g. Pokemod Red)
*/
extern const unsigned char rom[];
unsigned char rom_bank0[16384];
#define FLASH_TARGET_OFFSET (1024 * 1024)
const uint8_t *rom = (const uint8_t *) (XIP_BASE + FLASH_TARGET_OFFSET);
static unsigned char rom_bank0[65536];
static uint8_t ram[32768];
static int lcd_line_busy = 0;
static palette_t palette; // Colour palette
static uint8_t manual_palette_selected=0;
static struct
{
@@ -134,12 +137,6 @@ union core_cmd {
uint32_t full;
};
struct gb_priv {
uint32_t lcd_line_hashes[LCD_HEIGHT];
uint dma_pixel_buffer_chan;
};
static struct gb_priv gb_priv = { 0 };
/* Pixel data is stored in here. */
static uint8_t pixels_buffer[LCD_WIDTH];
@@ -223,95 +220,35 @@ void gb_error(struct gb_s *gb, const enum gb_error_e gb_err, const uint16_t addr
#endif
}
void core1_irq_dma_lcd_end_transfer(void)
{
mk_ili9225_write_pixels_end();
__atomic_store_n(&lcd_line_busy, 0, __ATOMIC_SEQ_CST);
dma_channel_acknowledge_irq0(dma_lcd);
}
#if ENABLE_LCD
void core1_lcd_draw_line(const uint_fast8_t line)
{
static uint16_t fb[LCD_WIDTH];
//dma_channel_wait_for_finish_blocking(dma_lcd);
for(unsigned int x = 0; x < LCD_WIDTH; x++)
{
fb[x] = palette[(pixels_buffer[x] & LCD_PALETTE_ALL) >> 4]
[pixels_buffer[x] & 3];
}
//mk_ili9225_set_address(line + 16, LCD_WIDTH + 30);
mk_ili9225_set_x(line + 16);
#if USE_DMA
mk_ili9225_write_pixels_start();
dma_channel_transfer_from_buffer_now(dma_lcd, &fb[0], LCD_WIDTH);
do {
__wfi();
} while (dma_channel_is_busy(dma_lcd));
__compiler_memory_barrier();
#else
mk_ili9225_write_pixels(fb, LCD_WIDTH);
__atomic_store_n(&lcd_line_busy, 0, __ATOMIC_SEQ_CST);
#endif
}
_Noreturn
void main_core1(void)
{
static dma_channel_config c2;
uint16_t clear_screen_colour = palette[2][3];
union core_cmd cmd;
/* Initialise and control LCD on core 1. */
mk_ili9225_init();
/* Initilise DMA transfer for clearing the LCD screen. */
dma_lcd = dma_claim_unused_channel(true);
c2 = dma_channel_get_default_config(dma_lcd);
channel_config_set_transfer_data_size(&c2, DMA_SIZE_16);
channel_config_set_dreq(&c2,DREQ_SPI0_TX);
channel_config_set_read_increment(&c2, false);
channel_config_set_write_increment(&c2, false);
channel_config_set_ring(&c2, false, 0);
/* Enable IRQ for wake on interrupt functionality. */
/* Use DMA_IRQ_1, DMA_IRQ_0 is already used by the SD Card reader */
irq_set_exclusive_handler(DMA_IRQ_1, core1_irq_dma_lcd_end_transfer);
dma_channel_set_irq1_enabled(dma_lcd, true);
irq_set_enabled(DMA_IRQ_1, true);
/* Clear LCD screen. */
mk_ili9225_write_pixels_start();
dma_channel_configure(dma_lcd, &c2, &spi_get_hw(spi0)->dr, &clear_screen_colour,
SCREEN_SIZE_X*SCREEN_SIZE_Y+16, true);
do {
__wfi();
} while (dma_channel_is_busy(dma_lcd));
__compiler_memory_barrier();
/* Set DMA transfer to be the length of a DMG line. */
dma_channel_set_trans_count(dma_lcd, LCD_WIDTH, false);
channel_config_set_read_increment(&c2, true);
//dma_sniffer_enable(dma_lcd, 0, true);
mk_ili9225_fill(0x0000);
/* Set LCD window to DMG size. */
mk_ili9225_set_window(16, LCD_HEIGHT + 15,
31, LCD_WIDTH + 30);
mk_ili9225_set_address(16, LCD_WIDTH + 30);
//mk_ili9225_set_x(15);
#if 0
/* Clear GB Screen window. */
mk_ili9225_write_pixels_start();
dma_channel_set_trans_count(dma_lcd, LCD_HEIGHT*LCD_WIDTH+16, false);
dma_channel_set_read_addr(dma_lcd, &green, true);
/* TODO: Add sleeping wait. */
dma_channel_wait_for_finish_blocking(dma_lcd);
mk_ili9225_write_pixels_end();
#endif
mk_ili9225_fill_rect(31,16,LCD_WIDTH,LCD_HEIGHT,0x0000);
// Sleep used for debugging LCD window.
//sleep_ms(1000);
@@ -350,17 +287,7 @@ void lcd_draw_line(struct gb_s *gb, const uint8_t pixels[LCD_WIDTH],
while(__atomic_load_n(&lcd_line_busy, __ATOMIC_SEQ_CST))
tight_loop_contents();
//memcpy(pixels_buffer, pixels, LCD_WIDTH);
dma_hw->sniff_data = 0;
//line_to_copy = line;
dma_channel_set_read_addr(gb_priv.dma_pixel_buffer_chan, pixels, false);
dma_channel_set_write_addr(gb_priv.dma_pixel_buffer_chan, pixels_buffer, true);
dma_channel_wait_for_finish_blocking(gb_priv.dma_pixel_buffer_chan);
if(gb_priv.lcd_line_hashes[line] == dma_hw->sniff_data)
return;
gb_priv.lcd_line_hashes[line] = dma_hw->sniff_data;
memcpy(pixels_buffer, pixels, LCD_WIDTH);
/* Populate command. */
cmd.cmd = CORE_CMD_LCD_LINE;
@@ -372,11 +299,13 @@ void lcd_draw_line(struct gb_s *gb, const uint8_t pixels[LCD_WIDTH],
#endif
#if ENABLE_SDCARD
/**
* Load a save file from the SD card
*/
void read_cart_ram_file(struct gb_s *gb) {
/* Load Save File. */
char filename[16];
uint_fast32_t save_size;
UINT bw;
UINT br;
gb_get_rom_name(gb,filename);
save_size=gb_get_save_size(gb);
@@ -391,7 +320,7 @@ void read_cart_ram_file(struct gb_s *gb) {
FIL fil;
fr=f_open(&fil,filename,FA_READ);
if (fr==FR_OK) {
f_read(&fil,ram,save_size,&bw);
f_read(&fil,ram,f_size(&fil),&br);
} else {
printf("f_open(%s) error: %s (%d)\n",filename,FRESULT_str(fr),fr);
}
@@ -402,25 +331,12 @@ void read_cart_ram_file(struct gb_s *gb) {
}
f_unmount(pSD->pcName);
}
/** Set the RTC of the game cartridge. Only used by games that support it.
* You could potentially force the game to allow the player to
* reset the time by setting the RTC to invalid values.
*
* Using memset(&gb->cart_rtc, 0xFF, sizeof(gb->cart_rtc)) for
* example causes Pokemon Gold/Silver to say "TIME NOT SET",
* allowing the player to set the time without having some dumb
* password.
*
* The memset has to be done directly to gb->cart_rtc because
* gb_set_rtc() processes the input values, which may cause
* games to not detect invalid values.
*/
memset(gb->cart_rtc, 0xFF, sizeof(gb->cart_rtc));
printf("read_cart_ram_file(%s) COMPLETE (%lu bytes)\n",filename,save_size);
}
/**
* Write a save file to the SD card
*/
void write_cart_ram_file(struct gb_s *gb) {
char filename[16];
uint_fast32_t save_size;
@@ -452,6 +368,179 @@ void write_cart_ram_file(struct gb_s *gb) {
}
printf("write_cart_ram_file(%s) COMPLETE (%lu bytes)\n",filename,save_size);
}
/**
* Load a .gb rom file in flash from the SD card
*/
void load_cart_rom_file(char *filename) {
UINT br;
uint8_t buffer[FLASH_SECTOR_SIZE];
sd_card_t *pSD=sd_get_by_num(0);
FRESULT fr=f_mount(&pSD->fatfs,pSD->pcName,1);
if (FR_OK!=fr) {
printf("f_mount error: %s (%d)\n",FRESULT_str(fr),fr);
return;
}
FIL fil;
fr=f_open(&fil,filename,FA_READ);
if (fr==FR_OK) {
uint32_t flash_target_offset=FLASH_TARGET_OFFSET;
for(;;) {
f_read(&fil,buffer,sizeof buffer,&br);
if(br==0) break; /* end of file */
printf("\nErasing target region...\n");
flash_range_erase(flash_target_offset,FLASH_SECTOR_SIZE);
printf("\nProgramming target region...\n");
flash_range_program(flash_target_offset,buffer,FLASH_SECTOR_SIZE);
flash_target_offset+=FLASH_SECTOR_SIZE;
}
} else {
printf("f_open(%s) error: %s (%d)\n",filename,FRESULT_str(fr),fr);
}
fr=f_close(&fil);
if(fr!=FR_OK) {
printf("f_close error: %s (%d)\n", FRESULT_str(fr), fr);
}
f_unmount(pSD->pcName);
printf("load_cart_rom_file(%s) COMPLETE (%lu bytes)\n",filename,br);
}
/**
* Function used by the rom file selector to display one page of .gb rom files
*/
uint16_t rom_file_selector_display_page(char filename[22][256],uint16_t num_page) {
sd_card_t *pSD=sd_get_by_num(0);
DIR dj;
FILINFO fno;
FRESULT fr;
fr=f_mount(&pSD->fatfs,pSD->pcName,1);
if (FR_OK!=fr) {
printf("f_mount error: %s (%d)\n",FRESULT_str(fr),fr);
return 0;
}
/* clear the filenames array */
for(uint8_t ifile=0;ifile<22;ifile++) {
strcpy(filename[ifile],"");
}
/* search *.gb files */
uint16_t num_file=0;
fr=f_findfirst(&dj, &fno, "", "*.gb");
/* skip the first N pages */
if(num_page>0) {
while(num_file<num_page*22 && fr == FR_OK && fno.fname[0]) {
num_file++;
fr=f_findnext(&dj, &fno);
}
}
/* store the filenames of this page */
num_file=0;
while(num_file<22 && fr == FR_OK && fno.fname[0]) {
strcpy(filename[num_file],fno.fname);
num_file++;
fr=f_findnext(&dj, &fno);
}
f_closedir(&dj);
f_unmount(pSD->pcName);
/* display *.gb rom files on screen */
mk_ili9225_fill(0x0000);
for(uint8_t ifile=0;ifile<num_file;ifile++) {
mk_ili9225_text(filename[ifile],0,ifile*8,0xFFFF,0x0000);
}
return num_file;
}
/**
* The ROM selector displays pages of up to 22 rom files
* allowing the user to select which rom file to start
* Copy your *.gb rom files to the root directory of the SD card
*/
void rom_file_selector() {
uint16_t num_page;
char filename[22][256];
uint16_t num_file;
/* display the first page with up to 22 rom files */
num_file=rom_file_selector_display_page(filename,num_page);
/* select the first rom */
uint8_t selected=0;
mk_ili9225_text(filename[selected],0,selected*8,0xFFFF,0xF800);
/* get user's input */
bool up,down,left,right,a,b,select,start;
while(true) {
up=gpio_get(GPIO_UP);
down=gpio_get(GPIO_DOWN);
left=gpio_get(GPIO_LEFT);
right=gpio_get(GPIO_RIGHT);
a=gpio_get(GPIO_A);
b=gpio_get(GPIO_B);
select=gpio_get(GPIO_SELECT);
start=gpio_get(GPIO_START);
if(!start) {
/* re-start the last game (no need to reprogram flash) */
break;
}
if(!a | !b) {
/* copy the rom from the SD card to flash and start the game */
load_cart_rom_file(filename[selected]);
break;
}
if(!down) {
/* select the next rom */
mk_ili9225_text(filename[selected],0,selected*8,0xFFFF,0x0000);
selected++;
if(selected>=num_file) selected=0;
mk_ili9225_text(filename[selected],0,selected*8,0xFFFF,0xF800);
sleep_ms(150);
}
if(!up) {
/* select the previous rom */
mk_ili9225_text(filename[selected],0,selected*8,0xFFFF,0x0000);
if(selected==0) {
selected=num_file-1;
} else {
selected--;
}
mk_ili9225_text(filename[selected],0,selected*8,0xFFFF,0xF800);
sleep_ms(150);
}
if(!right) {
/* select the next page */
num_page++;
num_file=rom_file_selector_display_page(filename,num_page);
if(num_file==0) {
/* no files in this page, go to the previous page */
num_page--;
num_file=rom_file_selector_display_page(filename,num_page);
}
/* select the first file */
selected=0;
mk_ili9225_text(filename[selected],0,selected*8,0xFFFF,0xF800);
sleep_ms(150);
}
if((!left) && num_page>0) {
/* select the previous page */
num_page--;
num_file=rom_file_selector_display_page(filename,num_page);
/* select the first file */
selected=0;
mk_ili9225_text(filename[selected],0,selected*8,0xFFFF,0xF800);
sleep_ms(150);
}
tight_loop_contents();
}
}
#endif
int main(void)
@@ -523,103 +612,6 @@ int main(void)
spi_init(spi0, 30*1000*1000);
spi_set_format(spi0, 16, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
/* Initialise GB context. */
memcpy(rom_bank0, rom, sizeof(rom_bank0));
ret = gb_init(&gb, &gb_rom_read, &gb_cart_ram_read,
&gb_cart_ram_write, &gb_error, &gb_priv);
putstdio("GB ");
if(ret != GB_INIT_NO_ERROR)
{
printf("Error: %d\n", ret);
goto sleep;
}
#if ENABLE_SDCARD
/* Load Save File. */
read_cart_ram_file(&gb);
#endif
/* Update buttons state */
gb.direct.joypad_bits.up=gpio_get(GPIO_UP);
gb.direct.joypad_bits.down=gpio_get(GPIO_DOWN);
gb.direct.joypad_bits.left=gpio_get(GPIO_LEFT);
gb.direct.joypad_bits.right=gpio_get(GPIO_RIGHT);
gb.direct.joypad_bits.a=gpio_get(GPIO_A);
gb.direct.joypad_bits.b=gpio_get(GPIO_B);
gb.direct.joypad_bits.select=gpio_get(GPIO_SELECT);
gb.direct.joypad_bits.start=gpio_get(GPIO_START);
/* manually assign a palette with button combo */
if(!gb.direct.joypad_bits.a && !gb.direct.joypad_bits.up) {
get_colour_palette(palette,0x10,0x05); /* A + Up */
} else if(!gb.direct.joypad_bits.a && !gb.direct.joypad_bits.down) {
get_colour_palette(palette,0x07,0x00); /* A + Down */
} else if(!gb.direct.joypad_bits.a && !gb.direct.joypad_bits.right) {
get_colour_palette(palette,0x1C,0x03); /* A + Right */
} else if(!gb.direct.joypad_bits.a && !gb.direct.joypad_bits.left) {
get_colour_palette(palette,0x0D,0x05); /* A + Left */
} else if(!gb.direct.joypad_bits.b && !gb.direct.joypad_bits.up) {
get_colour_palette(palette,0x19,0x03); /* B + Up */
} else if(!gb.direct.joypad_bits.b && !gb.direct.joypad_bits.down) {
get_colour_palette(palette,0x1A,0x05); /* B + Down */
} else if(!gb.direct.joypad_bits.b && !gb.direct.joypad_bits.right) {
get_colour_palette(palette,0x13,0x00); /* B + Right */
} else if(!gb.direct.joypad_bits.b && !gb.direct.joypad_bits.left) {
get_colour_palette(palette,0x16,0x00); /* B + Left (Game Boy Pocket Palette, shades of gray) */
} else if(!gb.direct.joypad_bits.up) {
get_colour_palette(palette,0x12,0x00); /* Up */
} else if(!gb.direct.joypad_bits.down) {
get_colour_palette(palette,0x17,0x00); /* Down */
} else if(!gb.direct.joypad_bits.right) {
get_colour_palette(palette,0x05,0x00); /* Right */
} else if(!gb.direct.joypad_bits.left) {
get_colour_palette(palette,0x18,0x05); /* Left */
} else if(!gb.direct.joypad_bits.a && !gb.direct.joypad_bits.b) {
get_colour_palette(palette,0xFF,0xFF); /* A + B */
} else {
/* Automatically assign a colour palette to the game */
char rom_title[16];
auto_assign_palette(palette, gb_colour_hash(&gb),gb_get_rom_name(&gb,rom_title));
}
#if ENABLE_LCD
gb_init_lcd(&gb, &lcd_draw_line);
{
/* Start Core1, which processes requests to the LCD. */
putstdio("CORE1 ");
multicore_launch_core1(main_core1);
/* initialise pixel buffer copy DMA. */
static dma_channel_config dma_config;
gb_priv.dma_pixel_buffer_chan = dma_claim_unused_channel(true);
dma_config = dma_channel_get_default_config(gb_priv.dma_pixel_buffer_chan);
channel_config_set_transfer_data_size(&dma_config, DMA_SIZE_32);
channel_config_set_read_increment(&dma_config, true);
channel_config_set_write_increment(&dma_config, true);
dma_sniffer_enable(gb_priv.dma_pixel_buffer_chan, 0x0, true);
channel_config_set_sniff_enable(&dma_config, true);
#if 0
irq_set_exclusive_handler(DMA_IRQ_1, core0_irq_dma_lcd_line_copy);
dma_channel_set_irq1_enabled(gb_priv.dma_pixel_buffer_chan, true);
irq_set_enabled(DMA_IRQ_1, true);
#endif
dma_channel_configure(
gb_priv.dma_pixel_buffer_chan,
&dma_config,
pixels_buffer,
0, /* We don't have a pointer to the pixel buffer here. */
LCD_WIDTH/sizeof(uint32_t),
false
);
}
putstdio("LCD ");
//gb.direct.interlace = 1;
#endif
#if ENABLE_SOUND
// Allocate memory for the stream buffer
stream=malloc(AUDIO_BUFFER_SIZE_BYTES);
@@ -632,7 +624,51 @@ int main(void)
i2s_config.dma_trans_count =AUDIO_SAMPLES;
i2s_volume(&i2s_config,2);
i2s_init(&i2s_config);
#endif
while(true)
{
#if ENABLE_LCD
#if ENABLE_SDCARD
/* ROM File selector */
mk_ili9225_init();
mk_ili9225_fill(0x0000);
rom_file_selector();
#endif
#endif
/* Initialise GB context. */
memcpy(rom_bank0, rom, sizeof(rom_bank0));
ret = gb_init(&gb, &gb_rom_read, &gb_cart_ram_read,
&gb_cart_ram_write, &gb_error, NULL);
putstdio("GB ");
if(ret != GB_INIT_NO_ERROR)
{
printf("Error: %d\n", ret);
goto out;
}
#if ENABLE_SDCARD
/* Load Save File. */
read_cart_ram_file(&gb);
#endif
/* Automatically assign a colour palette to the game */
char rom_title[16];
auto_assign_palette(palette, gb_colour_hash(&gb),gb_get_rom_name(&gb,rom_title));
#if ENABLE_LCD
gb_init_lcd(&gb, &lcd_draw_line);
/* Start Core1, which processes requests to the LCD. */
putstdio("CORE1 ");
multicore_launch_core1(main_core1);
putstdio("LCD ");
#endif
#if ENABLE_SOUND
// Initialize audio emulation
audio_init();
@@ -689,11 +725,25 @@ int main(void)
i2s_decrease_volume(&i2s_config);
}
#endif
if(!gb.direct.joypad_bits.right && prev_joypad_bits.right) {
/* select + right */
if(manual_palette_selected<12) {
manual_palette_selected++;
manual_assign_palette(palette,manual_palette_selected);
}
}
if(!gb.direct.joypad_bits.left && prev_joypad_bits.left) {
/* select + left */
if(manual_palette_selected>0) {
manual_palette_selected--;
manual_assign_palette(palette,manual_palette_selected);
}
}
if(!gb.direct.joypad_bits.start && prev_joypad_bits.start) {
#if ENABLE_SDCARD
write_cart_ram_file(&gb);
#endif
gb_reset(&gb);
goto out;
}
}
@@ -819,17 +869,10 @@ int main(void)
}
}
out:
puts("\nEmulation Ended");
/* stop lcd task running on core 1 */
multicore_reset_core1();
}
mk_ili9225_set_rst(true);
reset_usb_boot(0, 0);
/* Sleep forever. */
sleep:
stdio_flush();
while(1)
__wfi();
HEDLEY_UNREACHABLE();
}
+738 -1
View File
@@ -392,7 +392,7 @@ unsigned mk_ili9225_init(void)
{ MK_ILI9225_REG_LCD_AC_DRIVING_CTRL, 0x0100 },
/* Increment vertical and horizontal address.
* Use vertical image. */
{ MK_ILI9225_REG_ENTRY_MODE, 0x1008 },
{ MK_ILI9225_REG_ENTRY_MODE, 0x1018 },
/* Turn off all display outputs. */
{ MK_ILI9225_REG_DISPLAY_CTRL, 0x0000 },
/* Set porches to 8 lines. */
@@ -558,3 +558,740 @@ void mk_ili9225_set_drive_freq(uint16_t f)
void mk_ili9225_exit(void)
{
}
void mk_ili9225_fill_rect(uint8_t x,uint8_t y,uint8_t w,uint8_t h,uint16_t color)
{
set_register(MK_ILI9225_REG_ENTRY_MODE,0x1018);
set_register(MK_ILI9225_REG_HORI_WIN_ADDR1, y+h-1); // y_max
set_register(MK_ILI9225_REG_HORI_WIN_ADDR2, y); // y_min
set_register(MK_ILI9225_REG_VERT_WIN_ADDR1, 219-x); // x_max
set_register(MK_ILI9225_REG_VERT_WIN_ADDR2, 219-(x+w-1)); // x_min
set_register(MK_ILI9225_REG_RAM_ADDR_SET1,y);
set_register(MK_ILI9225_REG_RAM_ADDR_SET2,219-x);
write_register(MK_ILI9225_REG_GRAM_RW);
mk_ili9225_set_rs(1);
mk_ili9225_set_cs(0);
for(uint16_t i=0;i<w*h;i++) {
mk_ili9225_spi_write16(&color,1);
}
mk_ili9225_set_cs(1);
}
void mk_ili9225_fill(uint16_t color)
{
mk_ili9225_fill_rect(0,0,220,176,color);
}
void mk_ili9225_pixel(uint8_t x,uint8_t y,uint16_t color)
{
set_register(MK_ILI9225_REG_RAM_ADDR_SET1,y);
set_register(MK_ILI9225_REG_RAM_ADDR_SET2,219-x);
set_register(MK_ILI9225_REG_GRAM_RW,color);
}
void mk_ili9225_blit(uint16_t *fbuf,uint8_t x,uint8_t y,uint8_t w,uint8_t h) {
set_register(MK_ILI9225_REG_ENTRY_MODE,0x1018);
set_register(MK_ILI9225_REG_HORI_WIN_ADDR1, y+h-1); // y_max
set_register(MK_ILI9225_REG_HORI_WIN_ADDR2, y); // y_min
set_register(MK_ILI9225_REG_VERT_WIN_ADDR1, 219-x); // x_max
set_register(MK_ILI9225_REG_VERT_WIN_ADDR2, 219-(x+w-1)); // x_min
set_register(MK_ILI9225_REG_RAM_ADDR_SET1,y);
set_register(MK_ILI9225_REG_RAM_ADDR_SET2,219-x);
write_register(MK_ILI9225_REG_GRAM_RW);
mk_ili9225_set_rs(1);
mk_ili9225_set_cs(0);
mk_ili9225_spi_write16(fbuf,w*h);
mk_ili9225_set_cs(1);
}
void mk_ili9225_get_letter(uint16_t *fbuf,char l,uint16_t color,uint16_t bgcolor) {
uint8_t letter[8];
uint8_t row;
switch(l)
{
case 'a':
case 'A':
{
const uint8_t letter_[8]={0b00111100,
0b01100110,
0b01100110,
0b01111110,
0b01100110,
0b01100110,
0b01100110,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 'b':
case 'B':
{
const uint8_t letter_[8]={0b01111100,
0b01100110,
0b01100110,
0b01111100,
0b01100110,
0b01100110,
0b01111100,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 'c':
case 'C':
{
const uint8_t letter_[8]={0b00011110,
0b00110000,
0b01100000,
0b01100000,
0b01100000,
0b00110000,
0b00011110,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 'd':
case 'D':
{
const uint8_t letter_[8]={0b01111000,
0b01101100,
0b01100110,
0b01100110,
0b01100110,
0b01101100,
0b01111000,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 'e':
case 'E':
{
const uint8_t letter_[8]={0b01111110,
0b01100000,
0b01100000,
0b01111000,
0b01100000,
0b01100000,
0b01111110,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 'f':
case 'F':
{
const uint8_t letter_[8]={0b01111110,
0b01100000,
0b01100000,
0b01111000,
0b01100000,
0b01100000,
0b01100000,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 'g':
case 'G':
{
const uint8_t letter_[8]={0b00111100,
0b01100110,
0b01100000,
0b01101110,
0b01100110,
0b01100110,
0b00111110,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 'h':
case 'H':
{
const uint8_t letter_[8]={0b01100110,
0b01100110,
0b01100110,
0b01111110,
0b01100110,
0b01100110,
0b01100110,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 'i':
case 'I':
{
const uint8_t letter_[8]={0b00111100,
0b00011000,
0b00011000,
0b00011000,
0b00011000,
0b00011000,
0b00111100,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 'j':
case 'J':
{
const uint8_t letter_[8]={0b00000110,
0b00000110,
0b00000110,
0b00000110,
0b00000110,
0b01100110,
0b00111100,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 'k':
case 'K':
{
const uint8_t letter_[8]={0b11000110,
0b11001100,
0b11011000,
0b11110000,
0b11011000,
0b11001100,
0b11000110,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 'l':
case 'L':
{
const uint8_t letter_[8]={0b01100000,
0b01100000,
0b01100000,
0b01100000,
0b01100000,
0b01100000,
0b01111110,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 'm':
case 'M':
{
const uint8_t letter_[8]={0b11000110,
0b11101110,
0b11111110,
0b11010110,
0b11000110,
0b11000110,
0b11000110,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 'n':
case 'N':
{
const uint8_t letter_[8]={0b11000110,
0b11100110,
0b11110110,
0b11011110,
0b11001110,
0b11000110,
0b11000110,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 'o':
case 'O':
{
const uint8_t letter_[8]={0b00111100,
0b01100110,
0b01100110,
0b01100110,
0b01100110,
0b01100110,
0b00111100,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 'p':
case 'P':
{
const uint8_t letter_[8]={0b01111100,
0b01100110,
0b01100110,
0b01111100,
0b01100000,
0b01100000,
0b01100000,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 'q':
case 'Q':
{
const uint8_t letter_[8]={0b01111000,
0b11001100,
0b11001100,
0b11001100,
0b11001100,
0b11011100,
0b01111110,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 'r':
case 'R':
{
const uint8_t letter_[8]={0b01111100,
0b01100110,
0b01100110,
0b01111100,
0b01101100,
0b01100110,
0b01100110,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 's':
case 'S':
{
const uint8_t letter_[8]={0b00111100,
0b01100110,
0b01110000,
0b00111100,
0b00001110,
0b01100110,
0b00111100,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 't':
case 'T':
{
const uint8_t letter_[8]={0b01111110,
0b00011000,
0b00011000,
0b00011000,
0b00011000,
0b00011000,
0b00011000,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 'u':
case 'U':
{
const uint8_t letter_[8]={0b01100110,
0b01100110,
0b01100110,
0b01100110,
0b01100110,
0b01100110,
0b00111100,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 'v':
case 'V':
{
const uint8_t letter_[8]={0b01100110,
0b01100110,
0b01100110,
0b01100110,
0b00111100,
0b00111100,
0b00011000,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 'w':
case 'W':
{
const uint8_t letter_[8]={0b11000110,
0b11000110,
0b11000110,
0b11010110,
0b11111110,
0b11101110,
0b11000110,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 'x':
case 'X':
{
const uint8_t letter_[8]={0b11000011,
0b01100110,
0b00111100,
0b00011000,
0b00111100,
0b01100110,
0b11000011,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 'y':
case 'Y':
{
const uint8_t letter_[8]={0b11000011,
0b01100110,
0b00111100,
0b00011000,
0b00011000,
0b00011000,
0b00011000,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case 'z':
case 'Z':
{
const uint8_t letter_[8]={0b11111110,
0b00001100,
0b00011000,
0b00110000,
0b01100000,
0b11000000,
0b11111110,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case '-':
{
const uint8_t letter_[8]={0b00000000,
0b00000000,
0b00000000,
0b01111110,
0b00000000,
0b00000000,
0b00000000,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case '(':
case '[':
case '{':
{
const uint8_t letter_[8]={0b00001100,
0b00011000,
0b00110000,
0b00110000,
0b00110000,
0b00011000,
0b00001100,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case ')':
case ']':
case '}':
{
const uint8_t letter_[8]={0b00110000,
0b00011000,
0b00001100,
0b00001100,
0b00001100,
0b00011000,
0b00110000,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case ',':
{
const uint8_t letter_[8]={0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00011000,
0b00011000,
0b00110000};
memcpy(letter,letter_,8);
break;
}
case '.':
{
const uint8_t letter_[8]={0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00011000,
0b00011000,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case '!':
{
const uint8_t letter_[8]={0b00011000,
0b00011000,
0b00011000,
0b00011000,
0b00011000,
0b00000000,
0b00011000,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case '&':
{
const uint8_t letter_[8]={0b00111000,
0b01101100,
0b01101000,
0b01110110,
0b11011100,
0b11001110,
0b01111011,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case '\'':
{
const uint8_t letter_[8]={0b00011000,
0b00011000,
0b00110000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case '0':
{
const uint8_t letter_[8]={0b00111100,
0b01100110,
0b01101110,
0b01111110,
0b01110110,
0b01100110,
0b00111100,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case '1':
{
const uint8_t letter_[8]={0b00011000,
0b00111000,
0b01111000,
0b00011000,
0b00011000,
0b00011000,
0b00011000,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case '2':
{
const uint8_t letter_[8]={0b00111100,
0b01100110,
0b00000110,
0b00001100,
0b00011000,
0b00110000,
0b01111110,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case '3':
{
const uint8_t letter_[8]={0b00111100,
0b01100110,
0b00000110,
0b00011100,
0b00000110,
0b01100110,
0b00111100,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case '4':
{
const uint8_t letter_[8]={0b00011100,
0b00111100,
0b01101100,
0b11001100,
0b11111110,
0b00001100,
0b00001100,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case '5':
{
const uint8_t letter_[8]={0b01111110,
0b01100000,
0b01111100,
0b00000110,
0b00000110,
0b01100110,
0b00111100,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case '6':
{
const uint8_t letter_[8]={0b00011100,
0b00110000,
0b01100000,
0b01111100,
0b01100110,
0b01100110,
0b00111100,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case '7':
{
const uint8_t letter_[8]={0b01111110,
0b00000110,
0b00000110,
0b00001100,
0b00011000,
0b00011000,
0b00011000,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case '8':
{
const uint8_t letter_[8]={0b00111100,
0b01100110,
0b01100110,
0b00111100,
0b01100110,
0b01100110,
0b00111100,
0b00000000};
memcpy(letter,letter_,8);
break;
}
case '9':
{
const uint8_t letter_[8]={0b00111100,
0b01100110,
0b01100110,
0b00111110,
0b00000110,
0b00001100,
0b00111000,
0b00000000};
memcpy(letter,letter_,8);
break;
}
default:
{
const uint8_t letter_[8]={0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000};
memcpy(letter,letter_,8);
break;
}
}
for(uint8_t y=0;y<8;y++) {
row=letter[y];
for(uint8_t x=0;x<8;x++) {
if(row & 128) {
fbuf[y*8+x]=color;
} else {
fbuf[y*8+x]=bgcolor;
}
row=row<<1;
}
}
}
void mk_ili9225_text(char *s,uint8_t x,uint8_t y,uint16_t color,uint16_t bgcolor) {
uint16_t fbuf[8*8];
for(uint8_t i=0;i<strlen(s);i++) {
mk_ili9225_get_letter(fbuf,s[i],color,bgcolor);
mk_ili9225_blit(fbuf,x,y,8,8);
x+=8;
if(x>27*8) {
break;
}
}
}
-2733
View File
File diff suppressed because it is too large Load Diff