C Version of system_rtc_mem_read

Here are C versions of system_rtc_mem_write & system_rtc_mem_write. You don’t need these when your app is compiled against the SDK but if you are running bare-metal code you might find them handy. You could add this code to rBoot so you can communicate with it between boots, e.g. setting a flag from your app to alter the behaviour of rBoot on next boot.

Note: in the SDK version if you specify a length that is not a multiple of 4 the actual length read will be rounded up and so it may overflow the supplied buffer (although alignment/packing of memory may mean this isn’t a problem), my version requires a read in multiples of 4 bytes, but you can easily remove that check if you wish.

uint32 system_rtc_mem_read(int32 addr, void *buff, int32 length) {

	int32 blocks;
	
	// validate reading a user block
	//if (addr < 64) return 0;
	if (buff == 0) return 0;
	// validate 4 byte aligned
	if (((uint32)buff & 0x3) != 0) return 0;
	// validate length is multiple of 4
	if ((length & 0x3) != 0) return 0;
	
	// check valid length from specified starting point
	if (length > (0x300 - (addr * 4))) return 0;

	// copy the data
	for (blocks = (length >> 2) - 1; blocks >= 0; blocks--) {
		volatile uint32 *ram = ((uint32*)buff) + blocks;
		volatile uint32 *rtc = ((uint32*)0x60001100) + addr + blocks;
		*ram = *rtc;
	}

	return 1;
}

You’ll notice how similar these two functions are, if you need both you could easily combine them into a single function with a parameter to indicate read/write mode (which would save rom space).

uint32 system_rtc_mem_write(int32 addr, void *buff, int32 length) {

	int32 blocks;
	
	// validate reading a user block
	if (addr < 64) return 0;
	if (buff == 0) return 0;
	// validate 4 byte aligned
	if (((uint32)buff & 0x3) != 0) return 0;
	// validate length is multiple of 4
	if ((length & 0x3) != 0) return 0;
	
	// check valid length from specified starting point
	if (length > (0x300 - (addr * 4))) return 0;

	// copy the data
	for (blocks = (length >> 2) - 1; blocks >= 0; blocks--) {
		volatile uint32 *ram = ((uint32*)buff) + blocks;
		volatile uint32 *rtc = ((uint32*)0x60001100) + addr + blocks;
		*rtc = *ram;
	}

	return 1;
}

C Version of system_get_rst_info

People keep asking me how to use SDK functions (e.g. system_get_rst_info) in rBoot so they can add interesting new features. The simplest answer is you can’t – if you want to use the full set of SDK features you would need to link rBoot against the SDK, it’s size would go from <4k to >200k and it wouldn’t actually be possible to chain load a user rom. The less simple answer is if the SDK functions are simple enough and can be reverse engineered then you can replicate them in rBoot, or any other bare-metal app. So some simple things will be possible, with work, but you’ll never be able to use more complex features like wifi from rBoot.

Here is C code to replicate the system_get_rst_info. Note that it passes back a structure rather than a pointer to one (the SDK creates and stores this structure at boot and later just passes a pointer to it when requested, but the code below creates it when needed). Also note that you cannot use this code after the SDK has started because the SDK resets this information when it boots, but it will work just fine in rBoot.

struct rst_info {
	uint32 reason;
	uint32 exccause;
	uint32 epc1;
	uint32 epc2;
	uint32 epc3;
	uint32 excvaddr;
	uint32 depc;
};

struct rst_info system_get_rst_info() {
	struct rst_info rst;
	system_rtc_mem_read(0, &rst, sizeof(struct rst_info);
	if (rst.reason >= 7) {
		ets_memset(&rst, 0, sizeof(struct rst_info));
	}
	if (rtc_get_reset_reason() == 2) {
		ets_memset(&rst, 0, sizeof(struct rst_info));
		rst.reason = 6;
	}
	return rst;
}