mirror of
https://github.com/polpo/picogus.git
synced 2026-10-25 21:40:16 +00:00
Flash only one file: pg-multi.uf2 only one time. It contains all firmwares (6 at this moment). You can change between them in DOS:
New usage for this version:
pgusinit /m x [d] - change card mode to x (1=gus,2=sb,3=mpu,4=tandy,5=cms,6=joy)
the optional parameter 'd' makes the mode permanent at boot
(Only if pg-multi.uf2 is flashed)
Examples of use:
You have default mode as GUS mode on boot, want to change mode to SB, but only temporarily:
pgusinit /m 2
You want to change the default (permanent) mode of the card to SB mode, and the next system cold boots / hard resets / power off you want to stay in SB mode without using pgusinit:
pgusinit /m 2 d
75 lines
2.3 KiB
C
75 lines
2.3 KiB
C
// By Jeroen Taverne
|
|
// New features and mods by smymm
|
|
|
|
#include "pico/stdlib.h"
|
|
#include "hardware/structs/watchdog.h"
|
|
#include <hardware/flash.h>
|
|
#include "pico/multicore.h"
|
|
#include "flash_firmware.h"
|
|
|
|
static uint32_t sStart = 0;
|
|
static const uint32_t permOffset = (2048 * 1024) - FLASH_PAGE_SIZE; // last page of a 2M flash (adjust for other flash sizes if needed)
|
|
static const uint32_t offset[NR_OF_FIRMWARES] = {FLASH_FIRMWARE1, FLASH_FIRMWARE2, FLASH_FIRMWARE3, FLASH_FIRMWARE4, FLASH_FIRMWARE5, FLASH_FIRMWARE6};
|
|
|
|
uint8_t read_permMode(void)
|
|
{
|
|
const uint8_t *pMode = (const uint8_t *) (XIP_BASE + permOffset);
|
|
uint8_t pModeByte = *pMode;
|
|
|
|
if (pModeByte >= 1 && pModeByte <= NR_OF_FIRMWARES)
|
|
return (pModeByte - 1);
|
|
else
|
|
return 0; // No valid value, boot 1st fw.
|
|
}
|
|
|
|
void write_permMode(uint8_t pModeFw) // warning!! erasing last 4kb sector of the flash, and writing last page
|
|
{
|
|
uint8_t data[FLASH_PAGE_SIZE] = {0};
|
|
|
|
data[0] = pModeFw;
|
|
|
|
uint32_t ints = save_and_disable_interrupts();
|
|
flash_range_erase((permOffset + FLASH_PAGE_SIZE - FLASH_SECTOR_SIZE), FLASH_SECTOR_SIZE); // last sector
|
|
restore_interrupts(ints);
|
|
sleep_ms(100);
|
|
ints = save_and_disable_interrupts();
|
|
flash_range_program(permOffset, data, FLASH_PAGE_SIZE); // last page
|
|
restore_interrupts(ints);
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
uint8_t firmware_nr = (uint8_t) (0x000000FF & watchdog_hw->scratch[3]);
|
|
uint8_t firmware_mode = (uint8_t) (0x000000FF & (watchdog_hw->scratch[3] >> 8));
|
|
|
|
if (firmware_nr > NR_OF_FIRMWARES) {
|
|
firmware_nr = 0;
|
|
}
|
|
|
|
if (firmware_mode == 1 && firmware_nr > 0) // Perm mode requested. Write fw num to flash.
|
|
write_permMode(firmware_nr);
|
|
|
|
if (firmware_nr == 0) // Try to boot from permanent storage if no change requested / cold boot / bad value
|
|
{
|
|
sStart = offset[read_permMode()] + XIP_BASE;
|
|
} else { // Mode change requested by pgusinit
|
|
sStart = offset[firmware_nr-1] + XIP_BASE;
|
|
}
|
|
|
|
// Jump to application
|
|
asm volatile
|
|
(
|
|
"mov r0, %[start]\n"
|
|
"ldr r1, =%[vtable]\n"
|
|
"str r0, [r1]\n"
|
|
"ldmia r0, {r0, r1}\n"
|
|
"msr msp, r0\n"
|
|
"bx r1\n"
|
|
:
|
|
: [start] "r" (sStart + 0x100), [vtable] "X" (PPB_BASE + M0PLUS_VTOR_OFFSET)
|
|
:
|
|
);
|
|
|
|
return 0;
|
|
}
|