diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a76e43e..249a2f6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,6 +6,9 @@ add_executable(${PROGRAM}) target_sources(${PROGRAM} PRIVATE main.c palette.c clocks.pio.h) +# generate image array source files from png images +visrealm_generate_image_source_ram(${PROGRAM} splash res/splash.png ) + # generate header file from pio pico_generate_pio_header(${PROGRAM} ${CMAKE_CURRENT_LIST_DIR}/clocks.pio) diff --git a/src/main.c b/src/main.c index f0d7f5f..d842ae2 100644 --- a/src/main.c +++ b/src/main.c @@ -16,6 +16,8 @@ #include "palette.h" +#include "splash.h" + #include "vrEmuTms9918Util.h" #include "pico/stdlib.h" @@ -67,15 +69,22 @@ #define GPIO_INT 22 #define GPIO_GROMCL 29 #define GPIO_CPUCL 23 +#define GPIO_LED 25 #define GPIO_CD_MASK (0xff << GPIO_CD0) #define GPIO_CSR_MASK (0x01 << GPIO_CSR) #define GPIO_CSW_MASK (0x01 << GPIO_CSW) #define GPIO_MODE_MASK (0x01 << GPIO_MODE) #define GPIO_INT_MASK (0x01 << GPIO_INT) +#define GPIO_LED_MASK (0x01 << GPIO_LED) #define TMS_CRYSTAL_FREQ_HZ 10738635.0f +#define GPIO_CD_REVERSED 1 +#define LED_BLINK_ON_WRITE 1 + + +#if GPIO_CD_REVERSED /* In revision 0.2 of my prototype PCB, CD0 through CD7 are inconveniently reversed into the Pi Pico GPIO pins. Quickest way to deal with that is this lookup table. @@ -101,9 +110,12 @@ static uint8_t __aligned(4) reversed[] = 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF }; +#define REVERSE(x) reversed[x] +#else +#define REVERSE(x) x +#endif - -/* file globals */ + /* file globals */ static VrEmuTms9918* tms = NULL; /* our vrEmuTms9918 instance handle */ static uint32_t nextValue = 0; /* TMS9918A read-ahead value */ @@ -128,7 +140,7 @@ void __time_critical_func(gpioExclusiveCallbackProc1)() if (gpios & GPIO_MODE_MASK) /* read status register */ { - sio_hw->gpio_out = ((uint32_t)reversed[vrEmuTms9918ReadStatus(tms)] << GPIO_CD0) | GPIO_INT_MASK; + sio_hw->gpio_out = ((uint32_t)REVERSE(vrEmuTms9918ReadStatus(tms)) << GPIO_CD0) | GPIO_INT_MASK; currentInt = GPIO_INT_MASK; } else /* read data */ @@ -139,7 +151,7 @@ void __time_critical_func(gpioExclusiveCallbackProc1)() } else if ((gpios & GPIO_CSW_MASK) == 0) /* write? */ { - uint8_t value = reversed[(sio_hw->gpio_in >> GPIO_CD0) & 0xff]; + uint8_t value = REVERSE((sio_hw->gpio_in >> GPIO_CD0) & 0xff); if (gpios & GPIO_MODE_MASK) /* write register/address */ { @@ -151,15 +163,20 @@ void __time_critical_func(gpioExclusiveCallbackProc1)() else /* write data */ { vrEmuTms9918WriteData(tms, value); + +#if LED_BLINK_ON_WRITE + sio_hw->gpio_out = GPIO_LED_MASK | currentInt; +#endif } } else /* both CSR and CSW are high (inactive). Go High-Z */ { sio_hw->gpio_oe_clr = GPIO_CD_MASK; + sio_hw->gpio_out = currentInt; } /* update read-ahead */ - nextValue = reversed[vrEmuTms9918ReadDataNoInc(tms)] << GPIO_CD0; + nextValue = REVERSE(vrEmuTms9918ReadDataNoInc(tms)) << GPIO_CD0; /* interrupt handled */ iobank0_hw->intr[GPIO_CSR >> 3u] = iobank0_hw->proc1_irq_ctrl.ints[GPIO_CSR >> 3u]; @@ -171,9 +188,9 @@ void __time_critical_func(gpioExclusiveCallbackProc1)() void proc1Entry() { // set up gpio pins - gpio_init_mask(GPIO_CD_MASK | GPIO_CSR_MASK | GPIO_CSW_MASK | GPIO_MODE_MASK | GPIO_INT_MASK); + gpio_init_mask(GPIO_CD_MASK | GPIO_CSR_MASK | GPIO_CSW_MASK | GPIO_MODE_MASK | GPIO_INT_MASK | GPIO_LED_MASK); gpio_put_all(GPIO_INT_MASK); - gpio_set_dir_all_bits(GPIO_INT_MASK); // int is an output + gpio_set_dir_all_bits(GPIO_INT_MASK | GPIO_LED_MASK); // int is an output // ensure CSR and CSW are high (inactive) while (!gpio_get(GPIO_CSW) || !gpio_get(GPIO_CSR)) @@ -196,7 +213,7 @@ void proc1Entry() static void __time_critical_func(tmsScanline)(uint16_t y, VgaParams* params, uint16_t* pixels) { const uint32_t vBorder = (params->vVirtualPixels - TMS9918_PIXELS_Y) / 2; - const uint32_t hBorder = (params->hVirtualPixels - TMS9918_PIXELS_X) / 2; + const uint32_t hBorder = (params->hVirtualPixels - TMS9918_PIXELS_X * 2) / 2; uint16_t bg = tms9918PaletteBGR12[vrEmuTms9918RegValue(tms, TMS_REG_FG_BG_COLOR) & 0x0f]; @@ -207,6 +224,30 @@ static void __time_critical_func(tmsScanline)(uint16_t y, VgaParams* params, uin { pixels[x] = bg; } + + + /* source: C:/Users/troy/OneDrive/Documents/projects/pico9918/src/res/splash.png + * size : 172px x 10px + * : 3440 bytes + * format: 16bpp abgr image + */ + if (y >= vBorder + TMS9918_PIXELS_Y + 12) + { + y -= vBorder + TMS9918_PIXELS_Y + 12; + if (y < 10) + { + uint16_t* splashPtr = splash + (y * 172); + for (int x = 4; x < 4 + 172; ++x) + { + uint16_t c = *(splashPtr++); + if (c & 0xf000) + { + pixels[x] = c; + } + } + } + } + return; } @@ -225,13 +266,24 @@ static void __time_critical_func(tmsScanline)(uint16_t y, VgaParams* params, uin /* convert from tms palette to bgr12 */ int tmsX = 0; - for (int x = hBorder; x < hBorder + TMS9918_PIXELS_X; ++x, ++tmsX) + if (tmsScanlineBuffer[0] & 0xf0) { - pixels[x] = tms9918PaletteBGR12[tmsScanlineBuffer[tmsX]]; + for (int x = hBorder; x < hBorder + TMS9918_PIXELS_X * 2; x += 2, ++tmsX) + { + pixels[x] = tms9918PaletteBGR12[(tmsScanlineBuffer[tmsX] & 0xf0) >> 4]; + pixels[x + 1] = tms9918PaletteBGR12[tmsScanlineBuffer[tmsX] & 0x0f]; + } + } + else + { + for (int x = hBorder; x < hBorder + TMS9918_PIXELS_X * 2; x += 2, ++tmsX) + { + pixels[x] = pixels[x + 1] = tms9918PaletteBGR12[tmsScanlineBuffer[tmsX] & 0x0f]; + } } /*** right border ***/ - for (int x = hBorder + TMS9918_PIXELS_X; x < params->hVirtualPixels; ++x) + for (int x = hBorder + TMS9918_PIXELS_X * 2; x < params->hVirtualPixels; ++x) { pixels[x] = bg; } @@ -246,9 +298,6 @@ static void __time_critical_func(tmsScanline)(uint16_t y, VgaParams* params, uin /* * initialise a clock output using PIO - * - * GROMCLK is crystal frequency / 24 (~447KHz) - * CPUCLK is crystal frequency / 3 (~3.58MHz) */ uint initClock(uint gpio, float freqHz) { @@ -295,8 +344,14 @@ int main(void) /* then set up VGA output */ VgaInitParams params = { 0 }; - params.params = vgaGetParams(VGA_640_480_60HZ, 2); + params.params = vgaGetParams(VGA_640_480_60HZ); + + /* virtual size will be 640 x 320 to accomodate 80-column mode */ + setVgaParamsScaleY(¶ms.params, 2); + + /* set vga scanline callback to generate tms9918 scanlines */ params.scanlineFn = tmsScanline; + vgaInit(params); /* signal proc1 that we're ready to start the display */ diff --git a/src/vga/vga-modes.c b/src/vga/vga-modes.c index bd05790..4764516 100644 --- a/src/vga/vga-modes.c +++ b/src/vga/vga-modes.c @@ -16,10 +16,8 @@ void vgaUpdateTotalPixels(VgaSyncParams* params); /* * populate VgaParams for known vga modes */ -VgaParams vgaGetParams(VgaMode mode, int pixelScale) +VgaParams vgaGetParams(VgaMode mode) { - if (pixelScale < 1) pixelScale = 1; - VgaParams params; switch (mode) @@ -112,14 +110,44 @@ VgaParams vgaGetParams(VgaMode mode, int pixelScale) params.vSyncParams.freqHz = 1.0f / frameTimeSeconds; } - params.hPixelScale = pixelScale; - params.vPixelScale = pixelScale; - params.hVirtualPixels = (params.hSyncParams.displayPixels / params.hPixelScale); - params.vVirtualPixels = (params.vSyncParams.displayPixels / params.vPixelScale); + setVgaParamsScale(¶ms, 1); return params; } +/* + * set the scale/multiplier of virtual pixel size + */ +bool setVgaParamsScale(VgaParams* params, int pixelScale) +{ + return setVgaParamsScaleX(params, pixelScale) && + setVgaParamsScaleY(params, pixelScale); +} + +bool setVgaParamsScaleXY(VgaParams* params, int pixelScaleX, int pixelScaleY) +{ + return setVgaParamsScaleX(params, pixelScaleX) && + setVgaParamsScaleY(params, pixelScaleY); +} + +bool setVgaParamsScaleX(VgaParams* params, int pixelScale) +{ + if (!params || pixelScale < 1) return false; + + params->hPixelScale = pixelScale; + params->hVirtualPixels = (params->hSyncParams.displayPixels / params->hPixelScale); + return true; +} + +bool setVgaParamsScaleY(VgaParams* params, int pixelScale) +{ + if (!params || pixelScale < 1) return false; + + params->vPixelScale = pixelScale; + params->vVirtualPixels = (params->vSyncParams.displayPixels / params->vPixelScale); + return true; +} + /* * update total number of pixels */ diff --git a/src/vga/vga-modes.h b/src/vga/vga-modes.h index 3fb1114..f83b440 100644 --- a/src/vga/vga-modes.h +++ b/src/vga/vga-modes.h @@ -22,4 +22,16 @@ typedef enum VGA_1280_1024_60HZ, } VgaMode; -extern VgaParams vgaGetParams(VgaMode mode, int pixelScale); + +/* + * get the vga parameters for known modes + */ +VgaParams vgaGetParams(VgaMode mode); + +/* + * set the scale/multiplier of virtual pixel size + */ +bool setVgaParamsScale(VgaParams* params, int pixelScale); +bool setVgaParamsScaleXY(VgaParams* params, int pixelScaleX, int pixelScaleY); +bool setVgaParamsScaleX(VgaParams* params, int pixelScale); +bool setVgaParamsScaleY(VgaParams* params, int pixelScale); \ No newline at end of file diff --git a/src/vga/vga.c b/src/vga/vga.c index b052975..6b5d484 100644 --- a/src/vga/vga.c +++ b/src/vga/vga.c @@ -35,10 +35,13 @@ #define SYNC_SM 0 // vga sync state machine index #define RGB_SM 1 // vga rgb state machine index - #define END_OF_SCANLINE_MSG 0x40000000 #define END_OF_FRAME_MSG 0x80000000 +#define CRT_EFFECT 0 +#define SCANLINE_TIME_DEBUG 1 + + /* * sync pio dma data buffers */ @@ -46,16 +49,22 @@ uint32_t __aligned(4) syncDataActive[4]; // active display area uint32_t __aligned(4) syncDataPorch[4]; // vertical porch uint32_t __aligned(4) syncDataSync[4]; // vertical sync -uint16_t* rgbDataBufferEven = NULL; -uint16_t* rgbDataBufferOdd = NULL; +uint16_t* __aligned(4) rgbDataBuffer[2 + SCANLINE_TIME_DEBUG] = { 0 }; // two scanline buffers (odd and even) /* * file scope */ static int syncDmaChan = 0; static int rgbDmaChan = 0; +static uint syncDmaChanMask = 0; +static uint rgbDmaChanMask = 0; static VgaInitParams vgaParams = { 0 }; +#if SCANLINE_TIME_DEBUG +bool hasRenderedNext = false; +#endif + + uint32_t vgaMinimumPioClockKHz(VgaParams* params) { if (params) @@ -84,8 +93,15 @@ static bool buildSyncData() return false; } - if (!rgbDataBufferEven) rgbDataBufferEven = malloc(vgaParams.params.hVirtualPixels * sizeof(uint16_t)); - if (!rgbDataBufferOdd) rgbDataBufferOdd = malloc(vgaParams.params.hVirtualPixels * sizeof(uint16_t)); + rgbDataBuffer[0] = malloc(vgaParams.params.hVirtualPixels * sizeof(uint16_t)); + rgbDataBuffer[1] = malloc(vgaParams.params.hVirtualPixels * sizeof(uint16_t)); + +#if SCANLINE_TIME_DEBUG + rgbDataBuffer[2] = malloc(vgaParams.params.hVirtualPixels * sizeof(uint16_t)); + + for (int i = 0; i < vgaParams.params.hVirtualPixels; ++i) + rgbDataBuffer[2][i] = 0x0f00; +#endif vgaParams.params.pioDivider = round(sysClockKHz / (float)minClockKHz); vgaParams.params.pioFreqKHz = sysClockKHz / vgaParams.params.pioDivider; @@ -102,10 +118,10 @@ static bool buildSyncData() // compute sync bits - const uint32_t hSyncOff = (vgaParams.params.hSyncParams.syncHigh ? 0 : 1) << vga_sync_WORD_HSYNC_OFFSET; - const uint32_t hSyncOn = (vgaParams.params.hSyncParams.syncHigh ? 1 : 0) << vga_sync_WORD_HSYNC_OFFSET; - const uint32_t vSyncOff = (vgaParams.params.vSyncParams.syncHigh ? 0 : 1) << vga_sync_WORD_VSYNC_OFFSET; - const uint32_t vSyncOn = (vgaParams.params.vSyncParams.syncHigh ? 1 : 0) << vga_sync_WORD_VSYNC_OFFSET; + const uint32_t hSyncOff = !vgaParams.params.hSyncParams.syncHigh << vga_sync_WORD_HSYNC_OFFSET; + const uint32_t hSyncOn = vgaParams.params.hSyncParams.syncHigh << vga_sync_WORD_HSYNC_OFFSET; + const uint32_t vSyncOff = !vgaParams.params.vSyncParams.syncHigh << vga_sync_WORD_VSYNC_OFFSET; + const uint32_t vSyncOn = vgaParams.params.vSyncParams.syncHigh << vga_sync_WORD_VSYNC_OFFSET; // compute exec instructions const uint32_t instIrq = pio_encode_irq_set(false, vga_rgb_RGB_IRQ) << vga_sync_WORD_EXEC_OFFSET; @@ -165,6 +181,7 @@ static void vgaInitSync() // initialise sync dma syncDmaChan = dma_claim_unused_channel(true); + syncDmaChanMask = 0x01 << syncDmaChan; dma_channel_config syncDmaChanConfig = dma_channel_get_default_config(syncDmaChan); channel_config_set_transfer_data_size(&syncDmaChanConfig, DMA_SIZE_32); // transfer 32 bits at a time channel_config_set_read_increment(&syncDmaChanConfig, true); // increment read @@ -218,6 +235,7 @@ static void vgaInitRgb() // initialise rgb dma rgbDmaChan = dma_claim_unused_channel(true); + rgbDmaChanMask = 0x01 << rgbDmaChan; dma_channel_config rgbDmaChanConfig = dma_channel_get_default_config(rgbDmaChan); channel_config_set_transfer_data_size(&rgbDmaChanConfig, DMA_SIZE_16); // transfer 16 bits at a time channel_config_set_read_increment(&rgbDmaChanConfig, true); // increment read @@ -225,7 +243,7 @@ static void vgaInitRgb() channel_config_set_dreq(&rgbDmaChanConfig, pio_get_dreq(VGA_PIO, RGB_SM, true)); // setup the dma channel and set it going - dma_channel_configure(rgbDmaChan, &rgbDmaChanConfig, &VGA_PIO->txf[RGB_SM], rgbDataBufferEven, vgaParams.params.hVirtualPixels, false); + dma_channel_configure(rgbDmaChan, &rgbDmaChanConfig, &VGA_PIO->txf[RGB_SM], rgbDataBuffer[0], vgaParams.params.hVirtualPixels, false); dma_channel_set_irq0_enabled(rgbDmaChan, true); } @@ -237,9 +255,9 @@ static void __time_critical_func(dmaIrqHandler)(void) static int currentTimingLine = -1; static int currentDisplayLine = -1; - if (dma_hw->ints0 & (1u << syncDmaChan)) + if (dma_hw->ints0 & syncDmaChanMask) { - dma_hw->ints0 = 1u << syncDmaChan; + dma_hw->ints0 = syncDmaChanMask; if (++currentTimingLine >= vgaParams.params.vSyncParams.totalPixels) { @@ -266,16 +284,34 @@ static void __time_critical_func(dmaIrqHandler)(void) multicore_fifo_push_timeout_us(END_OF_SCANLINE_MSG | currentTimingLine, 0); } - - if (dma_hw->ints0 & (1u << rgbDmaChan)) + if (dma_hw->ints0 & rgbDmaChanMask) { - dma_hw->ints0 = 1u << rgbDmaChan; + dma_hw->ints0 = rgbDmaChanMask; divmod_result_t pxLineVal = divmod_u32u32(currentDisplayLine++, vgaParams.params.vPixelScale); uint32_t pxLine = to_quotient_u32(pxLineVal); uint32_t pxLineRpt = to_remainder_u32(pxLineVal); + uint16_t* currentBuffer = rgbDataBuffer[pxLine & 0x01]; + +#if CRT_EFFECT + if (pxLineRpt != 0) + { + for (int i = 0; i < 10; ++i) + { + currentBuffer[i] = (currentBuffer[i] >> 1) & 0x0777; + } + } +#endif - dma_channel_set_read_addr(rgbDmaChan, (pxLine & 1) ? rgbDataBufferOdd : rgbDataBufferEven, true); +#if SCANLINE_TIME_DEBUG + if (pxLineRpt != 0 && hasRenderedNext) + { + currentBuffer = rgbDataBuffer[2]; + } +#endif + + + dma_channel_set_read_addr(rgbDmaChan, currentBuffer, true); // need a new line every X display lines if ((pxLineRpt == 0)) @@ -284,14 +320,24 @@ static void __time_critical_func(dmaIrqHandler)(void) if (requestLine >= vgaParams.params.vVirtualPixels) requestLine -= vgaParams.params.vVirtualPixels; multicore_fifo_push_timeout_us(requestLine, 0); + hasRenderedNext = false; if (requestLine == vgaParams.params.vVirtualPixels - 1) { multicore_fifo_push_timeout_us(END_OF_FRAME_MSG, 0); } } +#if CRT_EFFECT + else + { + for (int i = 10; i < vgaParams.params.hVirtualPixels; ++i) + { + currentBuffer[i] = (currentBuffer[i] >> 1) & 0x0777; + } + } +#endif + } } -} /* * initialise the pio dma @@ -335,13 +381,14 @@ void vgaLoop() vgaParams.endOfScanlineFn(); } } - else if (message & 0x01) - { - vgaParams.scanlineFn(message & 0xfff, &vgaParams.params, rgbDataBufferOdd); - } else { - vgaParams.scanlineFn(message & 0xfff, &vgaParams.params, rgbDataBufferEven); + // get the next scanline pixels + vgaParams.scanlineFn(message & 0xfff, &vgaParams.params, rgbDataBuffer[message & 0x01]); +#if SCANLINE_TIME_DEBUG + dma_channel_set_read_addr(rgbDmaChan, rgbDataBuffer[2], true); + hasRenderedNext = true; +#endif } } } diff --git a/submodules/vrEmuTms9918 b/submodules/vrEmuTms9918 index ec77565..0e698da 160000 --- a/submodules/vrEmuTms9918 +++ b/submodules/vrEmuTms9918 @@ -1 +1 @@ -Subproject commit ec77565e104a2f8b5319de52d8b561cdac3b6cac +Subproject commit 0e698da4c5b9fd284fdfe111dfc16d51274d204b diff --git a/tools/bin2carray.py b/tools/bin2carray.py index 49092b6..78ef626 100644 --- a/tools/bin2carray.py +++ b/tools/bin2carray.py @@ -25,10 +25,14 @@ def main() -> int: parser = argparse.ArgumentParser( description='Convert binary files into C-style arrays for use with the PICO-56.', epilog="GitHub: https://github.com/visrealm/pico-56") - parser.add_argument('-v', '--verbose', help='verbose output', action='store_true') - parser.add_argument('-p', '--prefix', help='array variable prefix', default='') - parser.add_argument('-o', '--out', help='output file - defaults to base input file name with .c extension') - parser.add_argument('-i', '--in', nargs='+', help='input file(s) to store in Pi Pico ROM - can use wildcards') + parser.add_argument('-v', '--verbose', + help='verbose output', action='store_true') + parser.add_argument( + '-p', '--prefix', help='array variable prefix', default='') + parser.add_argument( + '-o', '--out', help='output file - defaults to base input file name with .c extension') + parser.add_argument('-i', '--in', nargs='+', + help='input file(s) to store in Pi Pico ROM - can use wildcards') args = vars(parser.parse_args()) outSourceFileName = args['out'] @@ -47,15 +51,16 @@ def main() -> int: outHeaderFileName = os.path.splitext(outSourceFileName)[0] + ".h" outHeaderFile = open(outHeaderFileName, "w") - outSourceFile.write(getFileHeader(outSourceFileName, inFileNames, args, isHeaderFile=False)) - outHeaderFile.write(getFileHeader(outHeaderFileName, inFileNames, args, isHeaderFile=True)) + outSourceFile.write(getFileHeader( + outSourceFileName, inFileNames, args, isHeaderFile=False)) + outHeaderFile.write(getFileHeader( + outHeaderFileName, inFileNames, args, isHeaderFile=True)) for infile in inFileNames: processFile(infile, outSourceFile, outHeaderFile, args) outSourceFile.close() - outHeaderFile.write("\n#endif") outHeaderFile.close() fileList = "" @@ -95,8 +100,7 @@ def getFileHeader(fileName, fileList, args, isHeaderFile) -> str: if isHeaderFile: baseName = args['prefix'] + "_" + os.path.basename(fileName) sanitizedFile = re.sub('[^0-9a-zA-Z]+', '_', baseName.upper()) - hdrText += f"#ifndef _{sanitizedFile}\n" - hdrText += f"#define _{sanitizedFile}\n\n" + hdrText += f"#pragma once\n\n" else: hdrText += "#include \"pico/platform.h\"\n" hdrText += "#include " @@ -153,9 +157,11 @@ def processFile(infile, srcOutput, hdrOutput, args) -> None: closeFile = False if srcOutput == None: srcOutput = open(outPathWithoutExt + ".c", "w") - srcOutput.write(getFileHeader(srcOutput.name, [infile], args, isHeaderFile=False)) + srcOutput.write(getFileHeader(srcOutput.name, [ + infile], args, isHeaderFile=False)) hdrOutput = open(outPathWithoutExt + ".h", "w") - hdrOutput.write(getFileHeader(hdrOutput.name, [infile], args, isHeaderFile=True)) + hdrOutput.write(getFileHeader(hdrOutput.name, [ + infile], args, isHeaderFile=True)) closeFile = True varName = os.path.split(infile)[1] @@ -182,7 +188,6 @@ def processFile(infile, srcOutput, hdrOutput, args) -> None: if closeFile: srcOutput.close() - hdrOutput.write("\n#endif") hdrOutput.close() return diff --git a/tools/img2carray.py b/tools/img2carray.py index 1a8e361..9e08c5b 100644 --- a/tools/img2carray.py +++ b/tools/img2carray.py @@ -34,7 +34,7 @@ def main() -> int: '-o', '--out', help='output file - defaults to base input file name with .c extension') parser.add_argument('-r', '--ram', nargs='+', default='', help='input file(s) to store in Pi Pico RAM - can use wildcards') - parser.add_argument('-i', '--in', nargs='+', + parser.add_argument('-i', '--in', nargs='+', default='', help='input file(s) to store in Pi Pico ROM - can use wildcards') args = vars(parser.parse_args()) @@ -73,7 +73,6 @@ def main() -> int: outHeaderFile, args, inRam=False) outSourceFile.close() - outHeaderFile.write("\n#endif") outHeaderFile.close() fileList = "" @@ -118,8 +117,7 @@ def getFileHeader(fileName, romFileList, ramFileList, args, isHeaderFile) -> str if isHeaderFile: baseName = args['prefix'] + "_" + os.path.basename(fileName) sanitizedFile = re.sub('[^0-9a-zA-Z]+', '_', baseName.upper()) - hdrText += f"#ifndef _{sanitizedFile}\n" - hdrText += f"#define _{sanitizedFile}\n\n" + hdrText += f"#pragma once\n\n" else: hdrText += "#include \"pico/platform.h\"\n" hdrText += "#include " @@ -271,7 +269,6 @@ def processImageFile(infile, srcOutput, hdrOutput, args, inRam) -> None: if closeFile: srcOutput.close() - hdrOutput.write("\n#endif") hdrOutput.close() return diff --git a/visrealm_tools.cmake b/visrealm_tools.cmake index a8ca72b..f337928 100644 --- a/visrealm_tools.cmake +++ b/visrealm_tools.cmake @@ -26,6 +26,21 @@ function(visrealm_generate_image_source TARGET DST ROMSRC) target_sources(${TARGET} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/${DST}.c) endfunction() +# custom function to generate source code from images using tools/img2carray.py +function(visrealm_generate_image_source_ram TARGET DST RAMSRC) + set(fullSrc ${CMAKE_CURRENT_SOURCE_DIR}/${RAMSRC}) + cmake_path(GET fullSrc PARENT_PATH srcPath) + + add_custom_command( + OUTPUT ${DST}.c ${DST}.h + COMMAND ${PYTHON} ${IMG_CONV} -r ${CMAKE_CURRENT_SOURCE_DIR}/${RAMSRC} -o ${DST}.c + DEPENDS ${IMG_CONV} ${srcPath} + ) + target_include_directories(${TARGET} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + target_sources(${TARGET} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/${DST}.c) +endfunction() + + # custom function to generate source code from images using tools/img2carray.py