Controlling GPIO within nrfjprog

Hello,

I have a product with QSPI flash that I would like to use nrfjprog to program the flash part. However, the QSPI flash's VCC is controlled (via a FET) from a GPIO line. I am looking for a way to have nrfjprog enable the GPIO line before attempting to access the QSPI flash (so that the flash is powered up). Is there a way from qspiinit.ini to do this?

Thanks,

Jon

  • Hello Jon,

    Unfortunately, nrfjprog currently does not have a setting to let you define the IO state for a particular GPIO during QSPI programming. I will make a feature request for it internally. In the meantime, maybe you can use pynrfjprog instead. Here is an example script proposed by one of the developers:

    from pynrfjprog import LowLevel
    from pathlib import Path
    import logging
    # Uncomment to enable verbose log output
    # logging.basicConfig(level=logging.DEBUG)
    target_cp = LowLevel.CoProcessor.CP_APPLICATION
    debugger_snr = 960158306 # Update with your snr here
    hex_to_flash = Path('qspi_hex.hex')
    if not hex_to_flash.exists():
        raise AssertionError(f"Selected hex {hex_to_flash} file does not exist")
    with LowLevel.API("NRF53", log=True) as api:
        # Connect and halt target core
        print("Connect to target")
        api.connect_to_emu_with_snr(debugger_snr)
        api.enable_coprocessor(target_cp)
        api.select_coprocessor(target_cp)
        api.connect_to_device()
        api.halt()
        # Disable MPU/SPU if enabled. Behaviour is device spesific.
        # For nRF53 it will issue a system reset w/halt
        print("Disable bprot")
        api.disable_bprot()
        
        # Example set GPIO P0.31 low (will light up LED4 on nRF53 DK)
        # Refer to device datasheet for addresses and values
        print("Set pin low")
        pin = 31
        gpio_base = 0x50842500
        gpio_dirset = gpio_base + 0x018
        gpio_outclr = gpio_base + 0x00C
        val = (1 << pin)
        api.write_u32(gpio_dirset, val, False)
        api.write_u32(gpio_outclr, val, False)
        # Enable qspi module
        api.qspi_init()
        
        # Do the programming yourself using QSPI functions
        addr = 0 # Address 0 is start of QSPI 
        data_len = 100
        data = list(range(0, data_len)) # data = [0,1,2,3 ... , 99]
        api.qspi_erase(addr, LowLevel.QSPIEraseLen.ERASE4KB) # Erase first page
        api.qspi_write(addr, data) # Write data
        # Read and verify
        device_data = api.qspi_read(addr, data_len) 
        assert data == list(device_data)
        # Optionally reset programmed device
        print("Applying pin reset")
        api.pin_reset()
        print("Done")

    Optionally you can try to use the program_file function. But we do not guarantee that there will not be a reset during programming (which will result in the GPIO being reset

    from pynrfjprog import LowLevel
    from pathlib import Path
    import logging
    # Uncomment to enable verbose log output
    # logging.basicConfig(level=logging.DEBUG)
    target_cp = LowLevel.CoProcessor.CP_APPLICATION
    debugger_snr = 960158306 # Update with your snr here
    hex_to_flash = Path('qspi_hex.hex')
    if not hex_to_flash.exists():
        raise AssertionError(f"Selected hex {hex_to_flash} file does not exist")
    with LowLevel.API("NRF53", log=True) as api:
        # Connect and halt target core
        print("Connect to target")
        api.connect_to_emu_with_snr(debugger_snr)
        api.enable_coprocessor(target_cp)
        api.select_coprocessor(target_cp)
        api.connect_to_device()
        api.halt()
        # Disable MPU/SPU if enabled. Behaviour is device spesific.
        # For nRF53 it will issue a system reset w/halt
        print("Disable bprot")
        api.disable_bprot()
        
        # Example set GPIO P0.31 low (will light up LED4 on nRF53 DK)
        # Refer to device datasheet for addresses and values
        print("Set pin low")
        pin = 31
        gpio_base = 0x50842500
        gpio_dirset = gpio_base + 0x018
        gpio_outclr = gpio_base + 0x00C
        val = (1 << pin)
        api.write_u32(gpio_dirset, val, False)
        api.write_u32(gpio_outclr, val, False)
        # Program your hex file
        print("Programming device")
        api.erase_file(hex_to_flash) # Optional: erase memory before writing
        api.program_file(hex_to_flash)
        api.verify_file(hex_to_flash) # Optional: verify after write
        # Optionally reset programmed device
        print("Applying pin reset")
        api.pin_reset()
        print("done")

    Best regards,

    Vidar

  • Thanks for the reply. A couple of questions:

    1. I assume this will be very similar for nRF52, correct?

    2. You mention that the program_file API might allow the part to reset during programming. Can you explain why? Would this potential reset happen on the nRf52 as well. Also, I currently found that I could program the gpio similarly with nrfjprog and the memwr command, followed by a second run of nrfjprog with the program command. However, now you have me concerned that with nrfjprog the part might reset losing the gpio seeing...

    Thanks,

    Jon

  • 1. Yes, it should be mostly the same except for the gpio addresses and device name (obviously).

    2 I did not think of doing it like that. This might be the simplest solution if it works. Are there any indications that it might be powering off? I.e. do you get any programming errors if you include the --verify argument?

    Jon said:
    You mention that the program_file API might allow the part to reset during programming. Can you explain why?

    I am not familiar with the internals of this library, so I will have to check with the developers again and get back to you.

  • It seems to work okay and verifies ok, but understanding of the part might reset for some reason mid programming is important just in case it might happen occasionally. The main issue with the workaround I do is that it's a bit slow since I have to call nrfjprog several times.

  • I have created a feature request for this internally so we will hopefully get official support for this in a future nrfjprog release.

    Regarding resets during programming, feedback from the team is that in general you cannot expected the device not to be reset during programming. A reset will for instance be required if there are is any runtime memory block protection enabled on the device (BPROT, ACL, SPU, MPU etc.), which may be the case if you are not programming a blank chip.

Related