-
Notifications
You must be signed in to change notification settings - Fork 904
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cannot access XIP from sram build #412
Comments
Is the |
there is |
@lurch i thought so, and i tried it like this (with int main() {
stdio_init_all();
// copied verbatim from https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/hardware_flash/flash.c#L51
void (*flash_enter_cmd_xip)(void) = (void(*)(void))rom_func_lookup(rom_table_code('C', 'X'));
assert(flash_enter_cmd_xip);
flash_enter_cmd_xip();
// rom_funcs below is *not* the bootrom stuff but a const struct defined in the XIP .rodata, the address is automatically set via a linker script:
while (true) {
printf("rom_funcs* %x\n",&rom_funcs);
printf("rom_funcs: %x\n",rom_funcs);
printf(" init: %x\n",rom_funcs.init);
printf(" on: %x\n",rom_funcs.on);
printf(" off: %x\n",rom_funcs.off);
printf("\n");
sleep_ms(1000);
}
} but either the assertion fails or the function errors out (i don't have a SWD probe that can debug sadly), because the CPU locks up and doesn't even respond to USB keepalive packets anymore. before adding the xip/bootrom stuff the loop would actually run and print something (but every actual access, so everything except @kilograham i know and that would be the exact opposite of what i need, given i don't want to overwrite the flash before accessing it. |
You're probably already aware of this, but just in case you're not: You can use either a Raspberry Pi or a second Pico for this. Instructions in the Getting Started guide. |
@lurch yeah i am but the only pi i have currently is hardwired into my 3d printer and i don't have a 2nd pico yet (currently stuck in shipping), so i was hoping anyone could tell me if i'm just calling that function wrong until it arrives |
in case anyone wants to see the full code: https://gitlab.com/nonchip/pi-pico-xipram/-/blob/master/ram/ram.c is where i do the xip access, what actually happens is as soon as i load the ram uf2 it initializes cdc and hangs. |
It seems like it should work, so I tried your code, and it works fine for me. I'm not sure what you're trying to do; the code in the bootrom will get you generic (slower speed) access to XIP. The simplest thing to do might be to have a valid program in flash which just calls into RAM, then you can run boot stage2 by doing a watchdog reboot - note also it is possible to call the second stage boot as a function (you have to copy it into RAM at the right place first); i could swear there was an example that does this, but I cannot find it atm. |
oh, i didn't read this - i have UART hooked up, and saw the right stuff there. might be worth trying it without a USB terminal hooked up to see if it makes a difference. |
i just cleared my whole
essentially what i was trying to do is have a bunch of low level common functionality i'll need for a "modular" kinda project in XIP, then load application specific code into RAM which accesses that to save on code duplication and flash destruction.
yeah that's what i thought first but then i'd have to implement the bootloader for the RAM code loading myself so i figured i'd rather have the program in flash reboot into the bootloader :/ |
inspired by this i tried putting the stdio init below the XIP init stuff, now i get this:
note it's trying to load a driver, so apparently there's some USB traffic going on, but then just fails to do anything. without the XIP init code it simply prints fine |
yeah using USB as a starting point is likely making life hard.... note for a start you are likely to be shooting yourself in the foot if your flash based "program" uses any static mutable data, as without extra work it is going to stomp on the data of the ram based program.
Not sure what RAM bootloader you are talking about? |
oh yeah that's something to keep in mind, i'd have to allocate any buffers in the ram program i guess
well if i have code sitting in XIP which you suggested should jump to ram instead of just resetting to the bootloader like i'm currently doing, then i'd have to make that XIP code actually load the code to ram, because the builtin bootloader isn't gonna do that for me then. i'd also probably have to write my own linker script and/or crt to produce a payload for that to load correctly |
to elaborate on what i'm trying to do: build a "smart" adapter for a variety of different serial interfaces (Gameboy/GBA Link to be precise), where i'll put the low level "phy" layer stuff that never changes (and common game-agnostic features like the GBA wireless adapter emulation or MultiBoot) in XIP, and then have an application on the host (the USB host, aka PC, not the gameboy) that can load game-specific logic onto RAM which then interfaces that to the application over USB, because there's various games that require handshakes / ping timeouts (all implemented differently without any standard) faster than even USB can guarantee. |
so i'll need to:
only thing i can imagine being the culprit there with USB and XIP is the "super slow XIP" access i'm using via the boot1 function literally timing out some USB interrupts/timing, maybe it might be worthwile investigating option 3:
but that sounds very much like a load of pain and boils down to "please gimme a target mode that runs in ram that isn't |
well someone's pain, and given how much other stuff we have going on, probably gonna be yours :-)
I was suggesting you make a flash binary, which when run just jumps into a known address in the RAM binary (in fact just the beginning of binary is fine with a RAM binary). Your RAM binary when run checks one of the watchdog scratch registers to see what to do; (either do a watchdog reboot (into flash) having set a value in the scratch register for the next re-entry into the RAM binary), or continue executing and clear the special value. |
ooh that might actually work, especially given i think i can "flash" the ram binary using good idea and sounds rather easy to achieve, will try :) |
that works too; though i was just suggesting you run the RAM binary, and it reboots into flash, which then calls back into RAM |
@kilograham ok that worked, ...somewhat. // XIP:
int main() {
if(watchdog_caused_reboot()){
int (*ram_entry)() = (int(*)())SRAM_BASE;
return ram_entry(); // jump to ram
}
reset_usb_boot(0, 0); // reboot into bootloader
}
// RAM:
int main() {
if(!watchdog_caused_reboot()){
int (*xip_entry)() = (int(*)())XIP_BASE; // yes the double cast is unnecessary but it works and is consistent with above
watchdog_reboot((uintptr_t)xip_entry,SRAM_END,10);
while (true); // let the watchdog kill us
}
stdio_init_all();
/// my printf loop
} problem is my output is now:
according to the map file those 3 should be function pointers to the addresses:
could it be the ram entry point actually actively resets whatever boot2 did before?
actually i've pushed the current code again if you wanna give it a try |
I'm sure you can debug on your own, but I will note that the ram pointer should be Also if you want to reboot into flash, you should pass 0 for the address |
weird that it actually called into ram then, i suspect that's the compiler saving me (thumb calls are always odd). but good point for the rebooting to 0 there, trying... |
ok yeah you were right @kilograham, something during ram initialization killed the "are we rebooting from watchdog" detection, i never actually reached the XIP code even, so my non-thumb-call didn't matter, and the struct was still borked because XIP never got initialized. fixed that now by using different scratch registers, tried with both watchdog-rebooting to |
what i still don't quite get is how update on that front: it seems to actually crash the CPU and not just USBCDC when talking to XIP after "enabling" it using that bootrom call. void __no_inline_not_in_flash_func(enable_xip)(){
void (*connect_internal_flash)(void) = (void(*)(void))rom_func_lookup(rom_table_code('I', 'F'));
void (*flash_enter_cmd_xip)(void) = (void(*)(void))rom_func_lookup(rom_table_code('C', 'X'));
void (*flash_exit_xip)(void) = (void(*)(void))rom_func_lookup(rom_table_code('E', 'X'));
printf("connect_internal_flash: %x\n", connect_internal_flash);
printf("flash_enter_cmd_xip: %x\n", flash_enter_cmd_xip);
printf("flash_exit_xip: %x\n", flash_exit_xip);
assert(connect_internal_flash && flash_enter_cmd_xip && flash_exit_xip);
// enable super-slow XIP
__compiler_memory_barrier();
printf("connect_internal_flash: ");
connect_internal_flash();
printf("done\n");
__compiler_memory_barrier();
// enable super-slow XIP
__compiler_memory_barrier();
printf("flash_enter_cmd_xip: ");
flash_enter_cmd_xip();
printf("done\n");
__compiler_memory_barrier();
// we're in super-slow XIP now, copy boot2 to RAM
__compiler_memory_barrier();
static uint32_t boot2_copyout[64];
printf("copying boot2 from %x to %x: ",XIP_BASE,boot2_copyout);
for (int i = 0; i < 64; ++i){
boot2_copyout[i] = ((uint32_t *)XIP_BASE)[i];
printf(".");
}
printf("done\n");
__compiler_memory_barrier();
// we have the boot2 in RAM now, disable super-slow XIP
__compiler_memory_barrier();
printf("flash_exit_xip: ");
flash_exit_xip();
printf("done\n");
__compiler_memory_barrier();
// call boot2 to set up fast XIP
__compiler_memory_barrier();
printf("calling boot2: ");
((void (*)(void))boot2_copyout+1)();
printf("done\n");
__compiler_memory_barrier();
} note this is literally the same as what the output i get from that (via UART):
and then it just hangs there like that, not doing anything else. |
The call to Likewise To get the flash from zero to slow-XIP access the sequence of calls is
which matches what you see in the SDK, minus some programming operation taking place in between the second and third call. |
It's an entirely separate repo, but this reminds me of raspberrypi/openocd#29 EDIT: I meant in terms of the enter/exit XIP stuff |
Seems unrelated, this issue doesn't involve flash erase, flash write, or openocd |
@Wren6991 omg thank you so much, i would never have guessed i need to actively exit and flush before entering, it works perfectly now! will clean up the code a bit and put it here for future reference :) |
Great! The |
So here we go, this is the code for enabling "fast" XIP via a boot2 inside XIP: #include "pico/stdlib.h"
#include "pico/bootrom.h"
// call this if you want "slow XIP":
void __no_inline_not_in_flash_func(enable_xip_via_bootrom)(){
void (*connect_internal_flash)(void) = (void(*)(void))rom_func_lookup(rom_table_code('I', 'F'));
void (*flash_exit_xip)(void) = (void(*)(void))rom_func_lookup(rom_table_code('E', 'X'));
void (*flash_flush_cache)(void) = (void(*)(void))rom_func_lookup(rom_table_code('F', 'C'));
void (*flash_enter_cmd_xip)(void) = (void(*)(void))rom_func_lookup(rom_table_code('C', 'X'));
assert(connect_internal_flash && flash_enter_cmd_xip && flash_exit_xip && flash_flush_cache);
__compiler_memory_barrier();
connect_internal_flash();
__compiler_memory_barrier();
flash_exit_xip();
__compiler_memory_barrier();
flash_flush_cache();
__compiler_memory_barrier();
flash_enter_cmd_xip();
__compiler_memory_barrier();
}
// call this if you want "fast XIP" and have boot2 residing in XIP:
void __no_inline_not_in_flash_func(enable_xip_via_boot2_in_xip)(){
void (*flash_exit_xip)(void) = (void(*)(void))rom_func_lookup(rom_table_code('E', 'X'));
assert(flash_exit_xip);
enable_xip_via_bootrom();
static uint32_t boot2_copyout[64];
for (int i = 0; i < 64; ++i){
boot2_copyout[i] = ((uint32_t *)XIP_BASE)[i];
}
__compiler_memory_barrier();
flash_exit_xip();
__compiler_memory_barrier();
((void (*)(void))boot2_copyout+1)();
__compiler_memory_barrier();
} |
Hmmm :) |
yeeaaaah i feel dumb, did a copypaste derp, noticed when i saw the watchdog never killing me :'D |
while
hardware_flash
provides functions to write/erase the flash when running from sram (typeno_flash
), i'd need to both read from and execute into XIP, but sram builds don't (seem to) provide a way of enablingboot_stage2
and the sdk doesn't (seem to) provide any other function to initialize the flash for XIP.manually adding
boot_stage2
as atarget_link_library
fails too because then the linker complains about there not being alibboot_stage2.so
could you please provide a "load into and run from sram" mode that doesn't disable flash access (= includes
boot_stage2
)?EDIT: apparently there seems to be some weirdness with
flash_enter_cmd_xip
while using usb CDC, but also please just add a "run from sram but with boot2" step, because "run from sram" does not always have to mean "no_flash"Update
figured out the correct sequence for enabling XIP via
boot2
(located inside XIP) thanks to @Wren6991: #412 (comment)also I provide a full working "blink" example containing a neat header+source file you can use over there: https://gitlab.com/nonchip/pi-pico-xipram
The text was updated successfully, but these errors were encountered: