August 4, 2023

Pi Pico - RP2040, IO in four flavors

This is something new to the RP2040, at least I have not seen anything quite like it elsewhere.

The registers for a given IO peripheral are placed in 4K blocks. The 4K block is replicated 4 times (so we have 16K overall). This gives us 4 ways to access a given register as follows:

You could ignore the fancy access addresses and just use the regular R/W access address as you do with most other microcontrollers. You always use the regular address to read the register.

The registers are 32 bits (4 bytes) in size.
If you want to just set a bit, you do a 32 bit write with a mask for the bit(s) you want to set to the SET address.
If you want to just clear a bit, you do a 32 bit write with a mask for the bit(s) you want to clear to the CLR address..
If you want to toggle a bit, you do a 32 bit write with a mask for the bit(s) you want to toggle to the XOR address..

Example

Suppose we want to clear the reset bit for IO_BANK0. The mask is 1<<5 (i.e. 0x20).

The basic reset "device" has 3 32 bit registers like so:

#define RESET_BASE	0x4000c000	
#define RESET_R_BASE	RESET_BASE + 0
#define RESET_WD_BASE	RESET_BASE + 4
#define RESET_DONE_BASE	RESET_BASE + 8
So, let's define the flavor offsets:
#define FL_RW		0x0000
#define FL_XOR		0x1000
#define FL_SET		0x2000
#define FL_CLR		0x3000
Here is how I would write C code to clear the reset bit for IO_BANK0.
#define RESET_BASE	0x4000c000	
#define RESET_BASE_RW	RESET_BASE + FL_RW
#define RESET_BASE_XOR	RESET_BASE + FL_XOR
#define RESET_BASE_SET	RESET_BASE + FL_SET
#define RESET_BASE_CLR	RESET_BASE + FL_CLR

struct resets {
    u32		reset;
    u32		wdsel;
    u32		done;
};

#define	R_IO_BANK0	(1<<5)

void
reset_io_bank0 ( void )
{
	struct resets *rp;

	rp = (struct resets *) RESET_BASE_CLR;
	rp->reset = R_IO_BANK0;

	rp = (struct resets *) RESET_BASE_RW;
	while ( rp->done & R_IO_BANK) )
	    ;
}
Some people get crazy about writing code like this to do IO, but it works fine and I find it clearer that invoking unnecessary functions (or inline assembly) to do register access. Some might argue about portability, but we are writing code for just the rp2040 here -- so the heck with them.
Feedback? Questions? Drop me a line!

Tom's Computer Info / [email protected]