Why do I need code execution from RAM? Well, if executing from RAM, some µCs can shutdown the Flash Memory and thus consume a lower avarage current. This is useful for Ultra-low-power µCs like my STM8L152, that can reduce the current consumption down to far less than 100µAmps. Also, in some cases execution from RAM can be faster than execution from Flash.
To execute a function from RAM with SDCC, the function must be copied to a start-address within the RAM area of the microcontroller.
#include <stdint.h>
#define RAMFUN_BUFLEN 25
// Define a type of function pointer (same as ramfun is)
typedef uint8_t (*cbfun)(uint8_t);
// This is where the function is copied
char RAMFUN_BUF[RAMFUN_BUFLEN];
// This function shall be copied to RAM
uint8_t ramfun(uint8_t value)
{
return value+1;
}
// Located directly after ramfun (so we can read out the length of
// the function we want to copy to RAM
int main(void)
{
// Preset RAMFUN Area with 0xEE (for debugging reasons)
for(uint8_t i=0; i<RAMFUN_BUFLEN; i++)RAMFUN_BUF[i]=0xEE;
// Copy RAMFUN Segment to RAM
char* src=(char*)&ramfun;
char* dst=(char*)RAMFUN_BUF;
for(uint16_t i=0; i<((uint16_t)&main - (uint16_t)&ramfun); i++)
{
*dst++ = *src++;
}
// Declare Function Pointer
cbfun f = (cbfun)(&RAMFUN_BUF[0]);
// main (counts until 5)
uint8_t i=0;
while(1)
{
if(i==5) continue;
i=f(i);
}
}
The code snippet above replaces the main.c file in the Minimal Example .tgz-File. It can be exchanged and compiled as described before.
It is easy to find the start position of the function in Flash, that has to be copied to RAM. For determination of the length of the function, there are several approaches found on the web, some of which use assembly to get the length of a code section. But one can simply find out the length by finding the beginning of the following function. In this case, it is important to have the right order: ramfun is located before main, hence, the length of ramfun is the difference of the addresses of the two functions as in the code snippet below. This method does not need any additional code segments and functionality is sufficient.
uint16_t length = ((uint16_t)&main - (uint16_t)&ramfun);
A disadvantage of this setup is that GDB cannot step into the RAM function. (At least, I did not get this managed). But it is not a huge problem because functions can be tested in flash and copied to RAM if they are known to work correctly.