0

I wrote, following guides and documentations, since I am not very navigated yet in this bare metal interaction, the following arm program to make the LED on pin 25 light up, on the raspberry pi pico.

On the building side no problem, I used arm-none-eabi-as (to assemble) and arm-none-eabi-ld (to link) on linux; even the conversion from binary (elf 32bit) to uf2 (I used the program at https://github.com/willth7/binuf2 for conversion). But when I connect the pico, pressing the BOOTSEL button, and coping the uf2 file on the pico folder, it automatically disconnects. I tried also to mount the folder somewhere else, thinking this could be the problem, but I got the same result.

Can anyone help me solving this please? Thanks in advance for any useful answer.

This is the code, if needed:

.section .data
.EQU    reset_rw, 0x4000c000
.EQU    reset_clr, 0x4000f000
.EQU    gpio_clr, 0x40014000
.EQU    sio, 0xd0000000

.section .text
.global _start
_start:
    ldr r0, =reset_clr
    mov r1, #32
    str r1, [r0, #0]
    ldr r0, =reset_rw
_gpio_clr:
    ldr r2, [r0, #2]
    and r2, r1
    beq _gpio_clr

    ldr r0, =gpio_clr
    add r0, #128
    mov r1, #5
    str r1, [r0, #19]

    ldr r0, =sio
    mov r1, #1
    lsl r1, r1, #25
    str r1, [r0, #9]

    str r1, [r0, #5]
  • this is expected. when you load new firmware, then the bootloader firmware with usb support is replaced. if you want usb AND blink an led there is TON more code that you need. – old_timer Jun 26 '23 at 18:14
  • this is why you reset or power cycle with the boot select to boot into the bootloader or boot into your firmware. even if you had usb firmware that doesnt mean you have firmware that makes this look like a thumb drive and allows for drag and drop of uf2 files... – old_timer Jun 26 '23 at 18:17
  • I dont remember where that default bootloader lives, maybe an alternate eeprom/flash or a section of the flash that we dont normally touch. I dont think the part has non-volatile storage on chip. – old_timer Jun 26 '23 at 18:17
  • I understand the problem now, thanks. In a video I have seen thought, this guy, who wrote his own tool chain (I had to use the arm default tools), did this way and worked for him. Anyway, what do you suggest now: fix the problem adding SOMEHOW the missing code, or change completely direction? – KmerPadreDiPdor Jun 26 '23 at 18:28
  • it is not a bug it is not a problem. you want to blink an led you blink the led (are you seeing the led blink)? once you have done that then you press the button and reset and/or unplug and replug and try another program. this is the norm, the old days you removed the prom and put it in the eraser for an hour or removed the whole mcu and put it in a programmer, etc. in this case and a number of current solutions you press a button and power cycle putting it in a debug or load mode. – old_timer Jun 26 '23 at 18:39
  • you are weeks/months away from asking usb questions. – old_timer Jun 26 '23 at 18:39
  • with code this simple and I forget all the rules if any, but there are two different kind of uf2 files if you will or basically how you set the address (I wrote my own uf2 file creation tool). you can either program the uf2 file into the flash so that after you power cycle (with using a default setting on boot selection) you get your program. You can build for and load a uf2 file into sram so that it only runs while powered, a power cycle puts you back in the prior flash state – old_timer Jun 26 '23 at 18:41
  • there are some erase the flash files you can download and that uf2 file has a program that erases the flash so that a power cycle goes into this debug/bootloader mode – old_timer Jun 26 '23 at 18:42
  • if you are trying to mimic a specific video online, you need to specifically talk to that person not us. From what you are showing or at least implying (I didnt run your code nor examine it). How this works is you use a button on the pico when you plug in the usb to put it in a loader mode. you get a virtual thumb drive, you copy your uf2 file. If successful the thumb drive/usb goes away and your program runs. depending on the construction of your binary and uf2 file (basically sram or flash) subsequent power cycles without a button pressed will run your program again. ... – old_timer Jun 26 '23 at 18:44
  • with no usb/thumb drive until you power cycle with the button pressed. I dont remember if a stock pico has a reset button or if I soldered my own on, actually I think I soldered my own on (so I didnt have to unplug the usb cable, now there are usb hubs that have a power button, that in theory will work also). – old_timer Jun 26 '23 at 18:45
  • mcu work in general you ideally have an in circuit programming solution which sometimes is a bootloader running on the chip. you go through the hundreds of iterations of writing code and testing it, each of those builds requires a re-programming of the mcu in some way, sometimes the debugger can stop the chip and program it, sometimes, like this, you reset with a button pressed and it puts it in a programming mode. many dev boards have a second mcu that is the usb debugger and separate from the target mcu, I do not think that is how a pico board works. – old_timer Jun 26 '23 at 18:48
  • actually I know it is not because they provide a debugger uf2 file that you program into one pico and then jumper wires to a second pico to use as a debug interface to the second pico... – old_timer Jun 26 '23 at 18:49
  • if developing bare metal for a raspberry pi (not pico) for example, then it is what I call the sd card dance, you remove the sd card put it in the development machine copy the new binary over, unmount, remove from dev machine, plug in the raspi, power on the raspi, examine the results, repeat a few thousand times. – old_timer Jun 26 '23 at 18:50
  • Maybe I have not explained myself in the clearest way: I cannot see the LED blink because each time I try to copy the uf2 file into the raspberry pi pico folder it gets disconnected. This is what I would like to solve. I appreciate your explanation. Actually I have learned things form it. Thought the problem remain... Last option that remains is the uf2 file itself. Could it might be the problem? – KmerPadreDiPdor Jun 26 '23 at 20:19
  • it is not the disconnection, the code you posted does not blink – old_timer Jun 26 '23 at 20:26
  • maybe code you did not post does. – old_timer Jun 26 '23 at 20:27

1 Answers1

-1

The USB disconnection is not your problem, the USB will disconnect and this is normal and correct, after it loads your uf2 file. So the problem is in the uf2 file...your code, or the construction of the file.

The code you posted looks incomplete and it definitely does not blink, so maybe it turns the led on or turns it off and leaves it.

Seems like you need to just use someone else's example, pick one that uses the same tools you have or can work with your tools. Success or fail, especially with the initial blinking LED example should be based on one that just builds and works for you, then you can try to change it (and break it) after that.

This code works and actually blinks you can compare each step/bit to the steps in the code you are using as well as the documentation (bare metal programming).

void PUT32 ( unsigned int, unsigned int );
unsigned int GET32 ( unsigned int );
void DELAY ( unsigned int );

#define RESETS_BASE                 0x4000C000

#define RESETS_RESET_RW             (RESETS_BASE+0x0+0x0000)
#define RESETS_RESET_XOR            (RESETS_BASE+0x0+0x1000)
#define RESETS_RESET_SET            (RESETS_BASE+0x0+0x2000)
#define RESETS_RESET_CLR            (RESETS_BASE+0x0+0x3000)

#define RESETS_RESET_DONE_RW        (RESETS_BASE+0x8+0x0000)
#define RESETS_RESET_DONE_XOR       (RESETS_BASE+0x8+0x1000)
#define RESETS_RESET_DONE_SET       (RESETS_BASE+0x8+0x2000)
#define RESETS_RESET_DONE_CLR       (RESETS_BASE+0x8+0x3000)

#define SIO_BASE                    0xD0000000

#define SIO_GPIO_OUT_RW             (SIO_BASE+0x10)
#define SIO_GPIO_OUT_SET            (SIO_BASE+0x14)
#define SIO_GPIO_OUT_CLR            (SIO_BASE+0x18)
#define SIO_GPIO_OUT_XOR            (SIO_BASE+0x1C)

#define SIO_GPIO_OE_RW              (SIO_BASE+0x20)
#define SIO_GPIO_OE_SET             (SIO_BASE+0x24)
#define SIO_GPIO_OE_CLR             (SIO_BASE+0x28)
#define SIO_GPIO_OE_XOR             (SIO_BASE+0x2C)

#define IO_BANK0_BASE               0x40014000

#define IO_BANK0_GPIO25_STATUS_RW   (IO_BANK0_BASE+0x0C8+0x0000)
#define IO_BANK0_GPIO25_STATUS_XOR  (IO_BANK0_BASE+0x0C8+0x1000)
#define IO_BANK0_GPIO25_STATUS_SET  (IO_BANK0_BASE+0x0C8+0x2000)
#define IO_BANK0_GPIO25_STATUS_CLR  (IO_BANK0_BASE+0x0C8+0x3000)

#define IO_BANK0_GPIO25_CTRL_RW     (IO_BANK0_BASE+0x0CC+0x0000)
#define IO_BANK0_GPIO25_CTRL_XOR    (IO_BANK0_BASE+0x0CC+0x1000)
#define IO_BANK0_GPIO25_CTRL_SET    (IO_BANK0_BASE+0x0CC+0x2000)
#define IO_BANK0_GPIO25_CTRL_CLR    (IO_BANK0_BASE+0x0CC+0x3000)

int notmain ( void )
{
    unsigned int ra;

    PUT32(RESETS_RESET_CLR,1<<5); //IO_BANK0
    while(1)
    {
        if((GET32(RESETS_RESET_DONE_RW)&(1<<5))!=0) break;
    }
    PUT32(SIO_GPIO_OE_CLR,1<<25);
    PUT32(SIO_GPIO_OUT_CLR,1<<25);
    PUT32(IO_BANK0_GPIO25_CTRL_RW,5); //SIO
    PUT32(SIO_GPIO_OE_SET,1<<25);
    for(ra=0;ra<100;ra++)
    {
        PUT32(SIO_GPIO_OUT_XOR,1<<25);
        DELAY(0x10000);
    }
    return(0);
}

.cpu cortex-m0
.thumb

    ldr r0,=0x20001000
    mov sp,r0
    bl notmain
    b .

.thumb_func
.globl PUT32
PUT32:
    str r1,[r0]
    bx lr

.thumb_func
.globl GET32
GET32:
    ldr r0,[r0]
    bx lr

.globl DELAY
.thumb_func
DELAY:
    sub r0,#1
    bne DELAY
    bx lr

I can link it for different places, linking it for sram

MEMORY
{
    stuff : ORIGIN = 0x20000000, LENGTH = 0xFC
}
SECTIONS
{
    .text   : { *(.text*)   } > stuff
}

I won't touch the flash so whatever you had on flash will remain after you power cycle.

I can link it for flash

MEMORY
{
    flash : ORIGIN = 0x10000000, LENGTH = 0xFC
}
SECTIONS
{
    .text   : { *(.text*)   } > flash
}

As mentioned I rolled my own uf2 file generation tool but your experience may differ.

It builds to 136 bytes with the tools I use (some version of gnu, do not expect the exact same number of bytes with your version of gnu tools). Which is less than the 252? Max for a single uf2 block, some number like that.

You can read the boot process documentation. But it is or can be a multi-staged process. Possibly calling all of them bootloaders or bootstrap. If your program is small enough then you have simpler options than if it is more than this 252 or some number of bytes.

This bootsel bootloader sources are all there with the Raspberry Pi folks sandbox stuff and you can examine it to understand what it is doing with the uf2 file and what address space it is using and what is left for you to use (if you want to try running in sram).

Another thing that you have to understand and this is true for any mcu not just this one, is that, for example, if you want to run code in sram loaded by this complicated bootloader, that means a lot of the chip has been initialized by the bootloader, clocks, uart, clock enables, etc. This means for example you could write a few lines of asm program that spews characters out the uart, because the bootloader already set it up. write that to flash though and it may work the first time loaded using the bootloader, but with a power cycle it does not because you didn't init anything.

Likewise you take a blinker program and I expect the blink rate will vary (if programmed to flash) the first time run from the bootloader and after that run from a power cycle. It can happen, just do not be surprised (the bootloader may boost the system clocks up to something faster, and a power cycle or reset will default them and if your code is not managing the clock speeds, just managing gpio, using a timer or a countdown loop, will blink at a different rate).

You need to figure out your situation. Starting with finding an example that just works. It needs to be as simple as you are seeing, if the initial blinker example has anything to do with PLLs and timers and interrupts, move on to another. I think the above is the bare minimum number of register writes, maybe I have an extra one or two in there, but do not think so.

I do not think all the steps have to be done exactly in that order, but I assume there is some order dependence as part of it. I wrote it when the boards came out and re-visited it not long ago for someone else, can go through it if we have to, but you can just read through the docs.

In order to blink though you have to switch the LED state either using the xor or by having one path set and one path reset the gpio pin, and then you have to have a loop that is slow enough for human time. If you just loop without a delay or make the classic high level language mistake of generating dead (and optimized out) code, then you need a scope on the gpio line/led to see it blink, it will just "glow" to human eyes.

halfer
  • 19,824
  • 17
  • 99
  • 186
old_timer
  • 69,149
  • 8
  • 89
  • 168