Jump to content

Porting to ESP8266 Sming


Recommended Posts

Guest Matthias
Posted

Hi everyone,

sorry, if this is a FAQ. I'm thinking about porting µGFX to Sming. However, _setjmp()_ and _longjmp()_ are not available on that platform. Is there a way to use µGFX without this functions?

With kind regards,
Matthias

Guest Matthias
Posted

Dear Joel,

thank you for the fast reply (and your great work!). Unfortunately the ESP8266 does not have a Cortex CPU but a Tesilica Xtensa LX106 32-bit CPU. There is no underlying OS but only a SDK based on callbacks. It does not provide _setjmp()_ or other means for task switching. Current cross-compiler for windows is gcc 5.2.0.

The only thing I could find is some assembly code for continuations that was done for porting the Arduino enviroment to the ESP8266. However, I have no idea how to use this for µGFX in the correct way.

Is there perhaps also a option to run µGFX single-threaded?

With kind regards,

Matthias

 

Posted

Hello Matthias,

The solution is simple: You can keep using our RAW32 scheduler but you only have to implement the two functions in assembly for the context switching: _gfxTaskSwitch() and _gfxStartThread(). This is how it's done for all the Cortex-M processors currently as well in order not to rely on the setjmp() and longjmp() implementations. You can have a look at the file /src/gos/gos_x_threads_cortexm347.h to have a look at how we implemented them. Simply create a new file like that for the LX106 processor and implement the two functions. You can see that we even implemented them twice using different types of assembly (embedded and in-line).

One thing that comes to mind: Is it possible that your used library provides setjmp() instead of _setjmp()? We have seen this before which is why we have this code (line 217 of /src/gos/gos_x_threads.c:

	#if (!defined(setjmp) && !defined(_setjmp)) || GFX_COMPILER == GFX_COMPILER_KEIL || GFX_COMPILER == GFX_COMPILER_MINGW32 || GFX_COMPILER == GFX_COMPILER_MINGW64
		#define CXT_SAVE 		setjmp
	#else
		#define CXT_SAVE 		_setjmp
	#endif
	#if (!defined(longjmp) && !defined(_longjmp)) || GFX_COMPILER == GFX_COMPILER_KEIL || GFX_COMPILER == GFX_COMPILER_MINGW32 || GFX_COMPILER == GFX_COMPILER_MINGW64
		#define CXT_RESTORE 	longjmp
	#else
		#define CXT_RESTORE 	_longjmp
	#endif

If you have those, then properly setting your compiler (and probably modifying the lines shown above) might solve your issue as well.

These two things are actually the reason why the GFX_CPU and GFX_COMPILER options exist in the configuration file. However, we always try to to provide implementations which work for most cases.

Guest Matthias
Posted

Thank you for the instructions Joel!

Unfortunately neither setjmp nor _setjmp seem to be available within the Sming enviroment. Well, I've not coded in assembly language for the Xtensa before but I will give it a try and let you know ;-)

With kind regards
Matthias
 

Posted

As an arm processor it is likely to be similar to one of the cortex m chips in terms of instruction set. The arm chips are generally instruction set consistent between similar levels and are often backwards compatible between levels. That is why arm publish an eabi specification. 

For example the m0 code can be used on a m7 chip provided your application doesn't use floating point - it just won't be quite as efficient doing the context switch.

For your lx chip try a simple project with no floating point using the m0 code and work from there.

  • 2 weeks later...
Posted

Finally found an implementation of longjmp() and setjmp() for the Xtensa LX106 cpu. I tested it with the sample code from Wikipedia and got the expected results :-)

I was able to compile µGFX after applying some small changes to the header files. However, I would like to have a better understanding of the BareMetal threading mechanism. The ESP8266 SDK is based on callbacks and no methods should run longer than a few ms at most, otherwise the connectivity may be affected and the watchdog timer will be triggered.

So running a loop like this to keep the µGFX event system running is not an option:

    while(TRUE) {
        gfxSleepMilliseconds(500);
    }  

Could be calling _gfxYield()_ every ms via a timer callback be a better approach?

    static Timer* _timer;
    _timer = new Timer();
    _timer->initializeMs(1, []() {
        gfxYield() );
    }).start();

Or is this not required at all to use µGFXl? Thank you very much for your help!

With kind regards,
Matthias

 

 

Posted

You will see that the sleep function  internally calls gfxYield so modifying gfxYield to call the esp code to prevent the watchdog triggering might be possible. 

Better perhaps would be to init ugfx and then create a thread to run your ugfx application. The main thread would then return and loop to keep the wifi code happy.

Note that because the raw32 scheduler is non-preemptive you will still need to ensure that you get to gfxSleepMillseconds or gfxYield periodically in your ugfx application as that will give the main thread a chance to operate thereby satisfying the wifi requirements. 

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...