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.
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:
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:
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?
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:
/* 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.
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.