Files
picogus/sw/bootloader.c
T
smymm 0e33a7b315 Implementation of multi-firmware for PicoGus.
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
2024-04-27 22:19:41 +02:00

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;
}