BRT Community

Please login or register.

Login with username, password and session length
Advanced search  

News:

Welcome to the Bridgetek Community!

Please read our Welcome Note

Technical Support enquires
please contact the team
@ Bridgetek Support

Please refer to our website for detailed information on all our products - Bridgetek - Bridging Technology

Author Topic: BRT_AN_025 Beta - Portable MCU library for EVE  (Read 118 times)

BRT Community

  • Administrator
  • Full Member
  • *****
  • Posts: 137
    • View Profile
BRT_AN_025 Beta - Portable MCU library for EVE
« on: January 09, 2020, 01:39:10 PM »

Hi,

We have a new beta version of a framework for EVE which is designed to be portable across a range of different MCUs. The download includes projects for the following MCUs but you can also use it as the basis of your code on other platforms too.

- BridgeTek FT900
- ST STM32
- Microchip PIC18F
- Espressif ESP32
- TI MSP430
- BeagleBone
- Raspberry Pi

The code currently supports the FT80x and FT81x families of EVE.

Here are the draft document and the beta code project download links:

BRT_AN_025_FT8xx_Portable_MCU_Library_DRAFT.pdf
BRT_AN_025_Source_BETA.zip
(Note: The link in the pdf file for the source code download is not yet active but you can download the code via the link above)

The beta document and code are supplied on an as-is basis and are not guaranteed by BridgeTek.

Coming soon...
- We have almost finished adding the BT81x support to the code and this will be released as an update soon
- We also have a separate application note showing how to port this code to other MCUs, using an NXP K64 as an example.
- We will also be creating further code examples in future using the framework provided in BRT_AN_025

We hope this code helps to get you up and running with EVE on your own MCU. If you have any feedback or questions then please get in touch via support.emea@brtchip.com quoting "BRT_AN_025 feedback" in the email subject.

Best Regards,
BRT Community
Logged

Rudolph

  • Jr. Member
  • **
  • Posts: 86
    • View Profile
Re: BRT_AN_025 Beta - Portable MCU library for EVE
« Reply #1 on: February 21, 2020, 04:03:22 PM »

Since this looks nothing like the EVE HAL 2.0 but is very close to my own library, is it planned to add an exporter for this to the EVE Screen Editor?


Edit: I started to port an example to a platform that I can actually use to test this.
And my first feedback really is - what the heck?

Edit: I ported it now, sort of,  and I seriously doubt that the STM32 example even compiles.
Your library has quite some issues and I would not really call it portable code.
What goes where, which include is used for what, this is a mess so far.

Please provide a sample project that builds with PlatformIO.


Anyways, I modified the eve_display() function in eve_example.c:

Code: [Select]
#define BRT_LOGO_W 147
#define BRT_LOGO_H 60

void eve_display(void)
{
uint32_t counter = 0;

EVE_LIB_BeginCoProList();
EVE_CMD_DLSTART();
EVE_CLEAR_COLOR_RGB(0, 0, 0);
EVE_CLEAR(1,1,1);
EVE_COLOR_RGB(255, 255, 255);

EVE_CMD_NUMBER(120, 460, 28, EVE_OPT_RIGHTX|5, num_profile_a); /* duration in µs for this function */

EVE_CMD_NUMBER(70, 100, 28, EVE_OPT_RIGHTX|5, BRT_LOGO_W);
EVE_CMD_NUMBER(70, 130, 28, EVE_OPT_RIGHTX|5, BRT_LOGO_H);

EVE_BEGIN(EVE_BEGIN_BITMAPS);
EVE_CMD_SETBITMAP(0, EVE_FORMAT_RGB565, BRT_LOGO_W, BRT_LOGO_H);

// Set origin on canvas using EVE_VERTEX_TRANSLATE.
EVE_VERTEX_TRANSLATE_X(((EVE_DISP_WIDTH/2)-(BRT_LOGO_W/2)) * 16);
EVE_VERTEX2II(0, 0, 0, 0);
EVE_VERTEX_TRANSLATE_X(0);

EVE_CMD_TEXT(EVE_DISP_WIDTH/2, BRT_LOGO_H+10, 29, EVE_OPT_CENTERX, "Touch the counter");

EVE_TAG(100);
EVE_COLOR_RGB(255, 0, 0);

EVE_CMD_NUMBER(400, 240, 30, EVE_OPT_CENTER|5, counter);

EVE_DISPLAY();
EVE_CMD_SWAP();
EVE_LIB_EndCoProList();
EVE_LIB_AwaitCoProEmpty();
}

Not to make it display a fancier list but to allow to call it from main() every 20ms.
I also removed the touch as I am using an EVE2-35G for the test and it uses a GT911 which I
did not want to patch into your library.

I also removed the custom font and the use of bitmap-handle 7 for the logo in order to not have
to add this to my own code as well.

I completely replaced main.c with my own and used the same code to init the core, the timer and the SPI in both projects.
Same toolchain, same optimisation level (-O2).
And of course I am using one hardware, for this test a board I designed with an ATSAMC21E18A, this is a Cortex-M0+ running at 48MHz.
Oh yes, I also disabled DMA for my own library.

Now when I run your version with the function above the number printed for the var num_profile_a is 942.
It takes 942µs to run the function once.

There is one optimisation, remove the last line: "EVE_LIB_AwaitCoProEmpty();".
This is completely safe, for one it is part of "EVE_LIB_BeginCoProList();" anyways and then the function
is now called only once every 20ms and not anymore as fast as the controller could make the loop.

Without the line the time spend in the function drops to 372µs.

In my own library this looks like this:
Code: [Select]
#define BRT_LOGO_W 147
#define BRT_LOGO_H 60

void TFT_display(void)
{
uint32_t counter = 0;

if(tft_active != 0)
{
EVE_start_cmd_burst(); /* start writing to the cmd-fifo as one stream of bytes, only sending the address once */

EVE_cmd_dl(CMD_DLSTART); /* start the display list */
EVE_cmd_dl(DL_CLEAR_RGB | BLACK); /* set the default clear color to black */
EVE_cmd_dl(DL_CLEAR | CLR_COL | CLR_STN | CLR_TAG); /* clear the screen - this and the previous prevent artifacts between lists, Attributes are the color, stencil and tag buffers */

EVE_cmd_dl(DL_COLOR_RGB | WHITE);

EVE_cmd_number(120, 460, 28, EVE_OPT_RIGHTX|5, num_profile_a); /* duration in µs for this function */

EVE_cmd_number(70, 100, 28, EVE_OPT_RIGHTX|5, BRT_LOGO_W);
EVE_cmd_number(70, 130, 28, EVE_OPT_RIGHTX|5, BRT_LOGO_H);

EVE_cmd_dl(DL_BEGIN | EVE_BITMAPS);
EVE_cmd_setbitmap(MEM_LOGO, EVE_RGB565, BRT_LOGO_W, BRT_LOGO_H);

// Set origin on canvas using EVE_VERTEX_TRANSLATE.
EVE_cmd_dl(VERTEX_TRANSLATE_X(((EVE_HSIZE/2)-(BRT_LOGO_W/2)) * 16));
EVE_cmd_dl(VERTEX2II(0, 0, 0, 0));
EVE_cmd_dl(VERTEX_TRANSLATE_X(0));

EVE_cmd_text(EVE_HSIZE/2, BRT_LOGO_H+10, 29, EVE_OPT_CENTERX, "Touch the counter");

EVE_cmd_dl(TAG(100));
EVE_cmd_dl(DL_COLOR_RGB | RED);
EVE_cmd_number(400, 240, 30, EVE_OPT_CENTER|5, counter);

EVE_cmd_dl(DL_DISPLAY); /* instruct the graphics processor to show the list */
EVE_cmd_dl(CMD_SWAP); /* make this list active */

EVE_end_cmd_burst(); /* stop writing to the cmd-fifo */
EVE_cmd_start(); /* order the command co-processor to start processing its FIFO queue but do not wait for completion */
}
}

This also shows why I asked about the EVE Screen Editor output, I could almost directly use that. :-)
And I already plan to add more functions to replace the EVE_cmd_dl() calls.

This takes 259µs to execute.
When I remove the EVE_start_cmd_burst()/EVE_end_cmd_burst() lines this goes up to 351µs.

What this does is described in the comment: /* start writing to the cmd-fifo as one stream of bytes, only sending the address once */
This removes three bytes of overhead from every command by not sending the adress in the FIFO over and over again.

When I also make the function wait for the FIFO to be empty the time goes up to 917µs.

So  my library is 25µs faster under the same conditions, 21µs without waiting and 113µs with the litte burst-trick.
Sure, this is not much but this also is a very short display llist.

And just for the kicks since I can not do this with your library.  8)
When I enable DMA by setting "EVE_DMA" in my EVE_target.h and not changing anything else, the time drops to 82µs.

To be totally unfair that is 942µs for your example and 82µs for my version.  :o
« Last Edit: February 23, 2020, 09:01:23 PM by Rudolph »
Logged

BRT Community

  • Administrator
  • Full Member
  • *****
  • Posts: 137
    • View Profile
Re: BRT_AN_025 Beta - Portable MCU library for EVE
« Reply #2 on: February 25, 2020, 11:12:44 AM »

Hi Rudolph,

Thanks,
It is good to get your thoughts on the code and we'll certainly go through and review your concerns and recommendations.

Just to provide a few initial replies,

This library does use SPI burst writes and so the address is only sent once and the commands are then streamed over SPI and so it works in a similar way to your library.

The STM32 one was built using the Keil uVision IDE.

We thought our functions here...
EVE_LIB_BeginCoProList(); // CS low and send address
commands
EVE_LIB_EndCoProList(); // CS high and update REG_CMD_WRITE
EVE_LIB_AwaitCoProEmpty();     // Wait pointers becoming equal

... were quite similar to your functions here...
EVE_start_cmd_burst(); EVE_end_cmd_burst(); EVE_cmd_start(); 

We may have some duplication however. There could be cases where this is needed (e.g. if you execute a command and then want to perform other register or memory actions when complete rather than send a new co-pro list) and so we do check for the completion of the commands at the end of the list as well as at the start. We may be able to optimise this however to make it run faster.

We are keen to make the code as good and as easy to use as possible and so we appreciate your honest feedback,

Best Regards, BRT Community



Logged

Rudolph

  • Jr. Member
  • **
  • Posts: 86
    • View Profile
Re: BRT_AN_025 Beta - Portable MCU library for EVE
« Reply #3 on: February 25, 2020, 10:01:26 PM »

Hello,

Thanks,
It is good to get your thoughts on the code and we'll certainly go through and review your concerns and recommendations.

Just keep in mind that I am not trying to be rude here or attacking you.
But with Englisch not beeing my native language I sometimes struggle to write as polite as I intend to.
So if I overstep somewhere, please point it out to me.

Quote
The STM32 one was built using the Keil uVision IDE.

Okay, I was wrong, it does indeed compile just fine without any change when using Keil uVision IDE.
I just can not test it.

Edit: and Keil really is a tad bit to intrusive for me.

What made me believe that it probably would not build is for example the chip-select functions
in EVE_MCU_STM32.c.
These look like this:
Code: [Select]
inline void MCU_CSlow(void)
{
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET); //lo
  //Nop();
}

Having a function declared as "inline" from within a .c file usually does not work.

The function in my EVE_MCU_ATSAMC21.c is this:
Code: [Select]
void MCU_CSlow(void)
{
PORT->Group[EVE_CS_PORT].OUTCLR.reg = EVE_CS;
}

And it will not compile when I put "inline" in front of it.
Well, I am using GCC and the Keil µVision IDE uses the ARM compiler, maybe that is it.

There are other issues though.
Why is eve_example.h defining the platform_calib_xxx() functions that are in main.c?
Why is MCU.h defining MCU_Setup() that is in main.c?
Why are so many modules over-including files they do not even need?
Why is EVE_MCU_STM32.c setting up the system clock?
What is the purpose of all these byte-swapping functions and why are they in EVE_MCU_xx.c?

Quote
This library does use SPI burst writes and so the address is only sent once and the commands are then streamed over SPI And so it works in a similar way to your library.

We thought our functions here...
EVE_LIB_BeginCoProList(); // CS low and send address
commands
EVE_LIB_EndCoProList(); // CS high and update REG_CMD_WRITE
EVE_LIB_AwaitCoProEmpty();     // Wait pointers becoming equal

... were quite similar to your functions here...
EVE_start_cmd_burst(); EVE_end_cmd_burst(); EVE_cmd_start(); 

You are right, I hooked up a logic-analyzer and attached two logfiles.
I created these with a Logic 16 from Saleae.
This clearly shows now that you actually are using a command-burst.
I assumed wrongly your version does not burst since it put the execution times so much closer together
when I switched it off for my version.

Unfortunately this makes the different in speed quite a lot bigger.
With my version commands are transfered in 248µs plus 7,16µs for the command to execute.
With your version I get a command, sometimes two or more of 14µs before the burst, 337µs for the commands and
13.34µs for the command to execute.

Oh yes, I do not check if the command-fifo is ready.
This is because apart from loading images it is always ready to accept more data as soon as you execute the fifo.
EVE just is this fast to execute the fifo, there is not much of a chance to be faster.
The only thing that I found so far that really takes time is decoding .png images.
And then there is that I am only writing every 20ms to the FIFO and always check for the execution time
during development of a HMI.

The command to execute is of course only the write to REG_CMD_WRITE.
For your version I right now have the sequence 0xb0 0x20 0xfc 0xec 0x08 0x00 0x00 on the screen.
It takes 1.58µs from chip-select-low to the first rising clock.
The gaps between the bytes are: 0.66µs, 0.76µs, 2.48µs, 0.68µs and 0.76µs.
And the time from the last falling clock to the rising chip select is 1.34µs.

For my version I ended up with the sequence 0xb0 0x20 0xfc 0x84 0x07.
Okay, first difference, I only write REG_CMD_WRITE as 16 bits - as the valid range is 12 bits anyways.
It takes 0.44µs from chip-select-low to the first rising clock.
The gaps between the bytes are: 0.66µs, 0.68µs, 0.9µs and 0.82µs.
And the time from the last falling clock to the rising chip select is 0.56µs.

I would like to know what you measure with your system, preferably of course with the STM32 and
runnning the SPI at 12MHz. :-)

This is my start-command:
Code: [Select]
/* order the command co-processor to start processing its FIFO queue and do not wait for completion */
void EVE_cmd_start(void)
{
uint32_t ftAddress;

#if defined (EVE_DMA)
if(EVE_dma_busy)
{
return; /* just do nothing if a dma transfer is in progress */
}
#endif

ftAddress = REG_CMD_WRITE; /* this changes between EVE 80x and 81x, so as a constant at compile-time the compiler should happily optimize away the following bit-shifting */

EVE_cs_set();
spi_transmit((uint8_t)(ftAddress >> 16) | MEM_WRITE); /* send Memory Write plus high address byte */
spi_transmit((uint8_t)(ftAddress >> 8)); /* send middle address byte */
spi_transmit((uint8_t)(ftAddress));      /* send low address byte */
spi_transmit((uint8_t)(cmdOffset));      /* send data low byte */
spi_transmit((uint8_t)(cmdOffset >> 8)); /* send data high byte */
EVE_cs_clear();
}

All of the code at the bottom is replaced with inline code though.
There is no function beeing called.
It sure does cost a couple kB of code extra but I worry about that if I actually run out of memory. :-)
And with the BT81x this is even less of an issue.

Quote
We may have some duplication however. There could be cases where this is needed (e.g. if you execute a command and then want to perform other register or memory actions when complete rather than send a new co-pro list) and so we do check for the completion of the commands at the end of the list as well as at the start. We may be able to optimise this however to make it run faster.

Sure, my code does read the touch registers every 5 ms and as you can see in my test-code I usually read the size of the display list right before building a new one in order to be able to keep an eye on its size.
The TFT_touch() function in my current project does check if EVE is busy, mostly due to my use of DMA,
but also because the little overhead does no harm there since the function has a very short runtime overall.
And it uses a CMD_TRACK for a slider with my EVE_cmd_execute() function for this which waits for completion of the command.
But when I check this with the logic-analyzer I usually see the command, the write to REG_CMD_WRITE and only a single read of REG_CMD_READ since EVE executes this faster than I can check if she is busy.
So for this I could even change to EVE_cmd_start() since building the next display list is at least a return-from-function and a call-function away.
But then again, the usually <50µs for the touch function are neglectable in comparison with building the display list.
My current project has a display list that takes >1ms to build, even without any SPI transfers due to DMA.
« Last Edit: February 25, 2020, 10:34:15 PM by Rudolph »
Logged